X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=lib%2Fccdbg-flash.c;fp=lib%2Fccdbg-flash.c;h=3e6729851502ff8895a6e2088836284035f7702c;hb=17d2432a8b9c15963cd3b821f025ad33972ef477;hp=0000000000000000000000000000000000000000;hpb=210dbaa23cdacf3a6f2d6e23493e96ee2ac9bca7;p=fw%2Faltos diff --git a/lib/ccdbg-flash.c b/lib/ccdbg-flash.c new file mode 100644 index 00000000..3e672985 --- /dev/null +++ b/lib/ccdbg-flash.c @@ -0,0 +1,356 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +/* From SWRA124 section 3.1.6 */ + +static uint8_t flash_page[] = { + + MOV_direct_data, P1DIR, 0x02, + MOV_direct_data, P1, 0xFF, + + MOV_direct_data, FADDRH, 0, +#define FLASH_ADDR_HIGH 8 + + MOV_direct_data, FADDRL, 0, +#define FLASH_ADDR_LOW 11 + + MOV_DPTR_data16, 0, 0, +#define RAM_ADDR_HIGH 13 +#define RAM_ADDR_LOW 14 + + MOV_Rn_data(7), 0, +#define FLASH_WORDS_HIGH 16 + + MOV_Rn_data(6), 0, +#define FLASH_WORDS_LOW 18 + + MOV_direct_data, FWT, 0x20, +#define FLASH_TIMING 21 + + MOV_direct_data, FCTL, FCTL_ERASE, +/* eraseWaitLoop: */ + MOV_A_direct, FCTL, + JB, ACC(FCTL_BUSY_BIT), 0xfb, + + MOV_direct_data, P1, 0xfd, + + MOV_direct_data, FCTL, FCTL_WRITE, +/* writeLoop: */ + MOV_Rn_data(5), 2, +/* writeWordLoop: */ + MOVX_A_atDPTR, + INC_DPTR, + MOV_direct_A, FWDATA, + DJNZ_Rn_rel(5), 0xfa, /* writeWordLoop */ +/* writeWaitLoop: */ + MOV_A_direct, FCTL, + JB, ACC(FCTL_SWBSY_BIT), 0xfb, /* writeWaitLoop */ + DJNZ_Rn_rel(6), 0xf1, /* writeLoop */ + DJNZ_Rn_rel(7), 0xef, /* writeLoop */ + + MOV_direct_data, P1DIR, 0x00, + MOV_direct_data, P1, 0xFF, + TRAP, +}; + +#define FLASH_RAM 0xf000 + +#if 0 +static uint8_t flash_erase_page[] = { + 3, MOV_direct_data, FADDRH, 0, +#define ERASE_PAGE_HIGH 3 + + 3, MOV_direct_data, FADDRL, 0, +#define ERASE_PAGE_LOW 7 + + 3, MOV_direct_data, FWT, 0x2A, + 3, MOV_direct_data, FCTL, FCTL_ERASE, + 0 +}; + +static uint8_t flash_read_control[] = { + 2, MOV_A_direct, FCTL, + 0 +}; +#endif + +#if 0 +static uint8_t flash_control_clear[] = { + 3, MOV_direct_data, FCTL, 0, + 2, MOV_A_direct, FCTL, + 0 +}; +#endif + +#if 0 +static uint8_t +ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr) +{ + uint16_t page_addr = addr >> 1; + uint8_t status; + uint8_t old[0x10], new[0x10]; + int i; + + ccdbg_read_memory(dbg, addr, old, 0x10); + flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8; + flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff; + status = ccdbg_execute(dbg, flash_erase_page); + ccdbg_debug(CC_DEBUG_FLASH, "erase status 0x%02x\n", status); + do { + status = ccdbg_execute(dbg, flash_read_control); + ccdbg_debug(CC_DEBUG_FLASH, "fctl 0x%02x\n", status); + } while (status & FCTL_BUSY); + ccdbg_read_memory(dbg, addr, new, 0x10); + for (i = 0; i < 0x10; i++) + ccdbg_debug(CC_DEBUG_FLASH, "0x%02x -> 0x%02x\n", old[i], new[i]); + status = ccdbg_execute(dbg, flash_control_clear); + ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status); + return 0; +} +#endif + +#if 0 +static uint8_t flash_write[] = { + MOV_direct_data, P1DIR, 0x02, + MOV_direct_data, P1, 0xFD, + + MOV_A_direct, FCTL, + JB, ACC(FCTL_BUSY_BIT), 0xf1, + + MOV_direct_data, FCTL, 0x20, + + MOV_direct_data, FADDRH, 0, +#define WRITE_PAGE_HIGH 16 + + MOV_direct_data, FADDRL, 0, +#define WRITE_PAGE_LOW 19 + + MOV_direct_data, FCTL, FCTL_WRITE, + MOV_direct_data, FWDATA, 0, +#define WRITE_BYTE_0 25 + MOV_direct_data, FWDATA, 0, +#define WRITE_BYTE_1 28 + MOV_A_direct, FCTL, + JB, ACC(FCTL_SWBSY_BIT), 0xf1, + + MOV_direct_data, P1, 0xFF, + TRAP, +}; +#endif + +static uint8_t +ccdbg_clock_init(struct ccdbg *dbg) +{ + static uint8_t set_clkcon_fast[] = { + 3, MOV_direct_data, CLKCON, 0x00, + 0 + }; + + static uint8_t get_sleep[] = { + 2, MOV_A_direct, SLEEP, + 0 + }; + + uint8_t status; + + ccdbg_execute(dbg, set_clkcon_fast); + do { + status = ccdbg_execute(dbg, get_sleep); + } while (!(status & 0x40)); + return 0; +} + +#if 0 +static uint8_t +ccdbg_flash_write_word(struct ccdbg *dbg, uint16_t addr, uint8_t data[2]) +{ + uint16_t page_addr = addr >> 1; + uint8_t check[2]; + uint8_t status; + int i; + + flash_write[WRITE_PAGE_HIGH] = page_addr >> 8; + flash_write[WRITE_PAGE_LOW] = page_addr & 0xff; + flash_write[WRITE_BYTE_0] = data[0]; + flash_write[WRITE_BYTE_1] = data[1]; + ccdbg_debug(CC_DEBUG_FLASH, "upload flash write\n"); + ccdbg_write_memory(dbg, 0xf000, flash_write, sizeof(flash_write)); + ccdbg_set_pc(dbg, 0xf000); + ccdbg_resume(dbg); + for (;;) { + status = ccdbg_read_status(dbg); + ccdbg_debug(CC_DEBUG_FLASH, "waiting for write 0x%02x\n", status); + if ((status & CC_STATUS_CPU_HALTED) != 0) + break; + sleep (1); + } + status = ccdbg_execute(dbg, flash_control_clear); + ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status); + ccdbg_read_memory(dbg, addr, check, 2); + for (i = 0; i < 2; i++) + ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", data[i], check[i]); + return 0; +} +#endif + +#define TIMERS_OFF 0x08 +#define DMA_PAUSE 0x04 +#define TIMER_SUSPEND 0x02 +#define SEL_FLASH_INFO_PAGE 0x01 + +#if 0 +static uint8_t +ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock) +{ + uint8_t config; + uint8_t bytes[2]; + uint8_t old[1], new[1]; + + config = ccdbg_rd_config(dbg); + ccdbg_wr_config(dbg, config|SEL_FLASH_INFO_PAGE); + bytes[0] = lock; + bytes[1] = 0; + ccdbg_flash_erase_page(dbg, 0); + ccdbg_read_memory(dbg, 0, old, 1); + ccdbg_flash_write_word(dbg, 0, bytes); + ccdbg_read_memory(dbg, 0, new, 1); + ccdbg_debug(CC_DEBUG_FLASH, "flash lock 0x%02x -> 0x%02x\n", old[0], new[0]); + ccdbg_wr_config(dbg, config & ~SEL_FLASH_INFO_PAGE); + return 0; +} +#endif + +uint8_t +ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) +{ + uint16_t offset; + uint16_t flash_prog; + uint16_t flash_len; + uint8_t fwt; + uint16_t flash_addr; + uint16_t flash_word_addr; + uint16_t flash_words; + uint8_t flash_words_high, flash_words_low; + uint16_t ram_addr; + uint16_t pc; + uint8_t status; + uint16_t remain, this_time, start; + uint8_t verify[0x400]; + int times; + + ccdbg_clock_init(dbg); + if (image->address + image->length > 0x8000) { + fprintf(stderr, "cannot flash image from 0x%04x to 0x%04x\n", + image->address, image->address + image->length); + return 1; + } + if (image->address & 0x3ff) { + fprintf(stderr, "flash image must start on page boundary\n"); + return 1; + } + ram_addr = 0xf000; + + + flash_prog = 0xf400; + + fwt = 0x20; + + flash_page[FLASH_TIMING] = fwt; + ccdbg_debug(CC_DEBUG_FLASH, "Upload %d flash program bytes to 0x%04x\n", + sizeof (flash_page), flash_prog); + ccdbg_write_memory(dbg, flash_prog, flash_page, sizeof(flash_page)); + + remain = image->length; + start = 0; + while (remain) { + this_time = remain; + if (this_time > 0x400) + this_time = 0x400; + + offset = ram_addr - (image->address + start); + + ccdbg_debug(CC_DEBUG_FLASH, "Upload %d bytes at 0x%04x\n", this_time, ram_addr); + ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time); +#if 0 + ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in ram\n", this_time); + ccdbg_read_memory(dbg, ram_addr, verify, this_time); + if (memcmp (image->data + start, verify, this_time) != 0) { + fprintf(stderr, "ram verify failed\n"); + return 1; + } +#endif + + flash_addr = image->address + start; + flash_word_addr = flash_addr >> 1; + flash_len = this_time + (this_time & 1); + flash_words = flash_len >> 1; + + flash_words_low = flash_words & 0xff; + flash_words_high = flash_words >> 8; + + /* The flash code above is lame */ + if (flash_words_low) + flash_words_high++; + + ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_HIGH, flash_word_addr >> 8); + ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_LOW, flash_word_addr & 0xff); + + ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_HIGH, ram_addr >> 8); + ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_LOW, ram_addr & 0xff); + + ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_HIGH, flash_words_high); + ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words_low); + + ccdbg_set_pc(dbg, flash_prog); + pc = ccdbg_get_pc(dbg); + ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n", + this_time, flash_addr); + status = ccdbg_resume(dbg); + for (times = 0; times < 10; times++) { + status = ccdbg_read_status(dbg); + ccdbg_debug(CC_DEBUG_FLASH, "."); + ccdbg_flush(CC_DEBUG_FLASH); + if ((status & CC_STATUS_CPU_HALTED) != 0) + break; + usleep(10000); + } + ccdbg_debug(CC_DEBUG_FLASH, "\n"); + if (times == 10) { + fprintf(stderr, "flash page timed out\n"); + return 1; + } + + ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in flash\n", this_time); + ccdbg_read_memory(dbg, flash_addr, verify, this_time); + if (memcmp (image->data + start, verify, this_time) != 0) { + int i; + fprintf(stderr, "flash verify failed\n"); + for (i = 0; i < this_time; i++) { + if (image->data[start + i] != verify[i]) + fprintf(stderr, "0x%04x: 0x%02x != 0x%02x\n", + start + i, image->data[start+i], verify[i]); + } + return 1; + } + remain -= this_time; + start += this_time; + } + return 0; +}