From 891633322a87146735c6693b497eed2c8e2e8933 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 30 May 2021 17:42:39 +0200 Subject: [PATCH] lpc: Care for protected pages on LPC80x devices. --- src/target/lpc11xx.c | 33 +++++++++---------- src/target/lpc_common.c | 70 ++++++++++++++++++++++++++++++++--------- src/target/lpc_common.h | 3 +- 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/target/lpc11xx.c b/src/target/lpc11xx.c index 9dc4b58f..5b12e1c6 100644 --- a/src/target/lpc11xx.c +++ b/src/target/lpc11xx.c @@ -72,7 +72,7 @@ const struct command_s lpc11xx_cmd_list[] = { {NULL, NULL, NULL} }; -void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize, uint32_t iap_entry) +void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize, uint32_t iap_entry, uint8_t reserved_pages) { struct lpc_flash *lf = lpc_add_flash(t, addr, len); lf->f.blocksize = erasesize; @@ -81,6 +81,7 @@ void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize, u lf->iap_entry = iap_entry; lf->iap_ram = IAP_RAM_BASE; lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES; + lf->reserved_pages = reserved_pages; } bool @@ -125,7 +126,7 @@ lpc11xx_probe(target *t) case 0x2980002B: /* lpc11u24x/401 */ t->driver = "LPC11xx"; target_add_ram(t, 0x10000000, 0x2000); - lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST, 0); target_add_commands(t, lpc11xx_cmd_list, "LPC11xx"); return true; @@ -133,18 +134,18 @@ lpc11xx_probe(target *t) case 0x1A24902B: t->driver = "LPC1112"; target_add_ram(t, 0x10000000, 0x1000); - lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000, IAP_ENTRY_MOST, 0); return true; case 0x1000002b: // FX LPC11U6 32 kB SRAM/256 kB flash (max) t->driver = "LPC11U6"; target_add_ram(t, 0x10000000, 0x8000); - lpc11xx_add_flash(t, 0x00000000, 0x40000, 0x1000, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x40000, 0x1000, IAP_ENTRY_MOST, 0); return true; case 0x3000002B: case 0x3D00002B: t->driver = "LPC1343"; target_add_ram(t, 0x10000000, 0x2000); - lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000, IAP_ENTRY_MOST, 0); return true; case 0x00008A04: /* LPC8N04 (see UM11074 Rev.1.3 section 4.5.19) */ t->driver = "LPC8N04"; @@ -152,7 +153,7 @@ lpc11xx_probe(target *t) /* UM11074/ Flash controller/15.2: The two topmost sectors * contain the initialization code and IAP firmware. * Do not touch the! */ - lpc11xx_add_flash(t, 0x00000000, 0x7800, 0x400, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x7800, 0x400, IAP_ENTRY_MOST, 0); target_add_commands(t, lpc11xx_cmd_list, "LPC8N04"); return true; } @@ -167,7 +168,7 @@ lpc11xx_probe(target *t) case 0x00008024: /* 802M001JHI33 */ t->driver = "LPC802"; target_add_ram(t, 0x10000000, 0x800); - lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_84x); + lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_84x, 2); target_add_commands(t, lpc11xx_cmd_list, "LPC802"); return true; case 0x00008040: /* 804M101JBD64 */ @@ -177,7 +178,7 @@ lpc11xx_probe(target *t) case 0x00008044: /* 804M101JHI33 */ t->driver = "LPC804"; target_add_ram(t, 0x10000000, 0x1000); - lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_84x); + lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_84x, 2); target_add_commands(t, lpc11xx_cmd_list, "LPC804"); return true; case 0x00008100: /* LPC810M021FN8 */ @@ -187,7 +188,7 @@ lpc11xx_probe(target *t) case 0x00008122: /* LPC812M101JDH20 / LPC812M101JTB16 */ t->driver = "LPC81x"; target_add_ram(t, 0x10000000, 0x1000); - lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST, 0); target_add_commands(t, lpc11xx_cmd_list, "LPC81x"); return true; case 0x00008221: /* LPC822M101JHI33 */ @@ -196,19 +197,19 @@ lpc11xx_probe(target *t) case 0x00008242: /* LPC824M201JDH20 */ t->driver = "LPC82x"; target_add_ram(t, 0x10000000, 0x2000); - lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST, 0); target_add_commands(t, lpc11xx_cmd_list, "LPC82x"); return true; case 0x00008322: /* LPC832M101FDH20 */ t->driver = "LPC832"; target_add_ram(t, 0x10000000, 0x1000); - lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST, 0); target_add_commands(t, lpc11xx_cmd_list, "LPC832"); return true; case 0x00008341: /* LPC8341201FHI33 */ t->driver = "LPC834"; target_add_ram(t, 0x10000000, 0x1000); - lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST, 0); target_add_commands(t, lpc11xx_cmd_list, "LPC834"); return true; case 0x00008441: @@ -217,7 +218,7 @@ lpc11xx_probe(target *t) case 0x00008444: t->driver = "LPC844"; target_add_ram(t, 0x10000000, 0x2000); - lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x); + lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x, 0); return true; case 0x00008451: case 0x00008452: @@ -225,7 +226,7 @@ lpc11xx_probe(target *t) case 0x00008454: t->driver = "LPC845"; target_add_ram(t, 0x10000000, 0x4000); - lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x); + lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x, 0); return true; case 0x0003D440: /* LPC11U34/311 */ case 0x0001cc40: /* LPC11U34/421 */ @@ -237,13 +238,13 @@ lpc11xx_probe(target *t) case 0x00007C40: /* LPC11U37FBD64/501 */ t->driver = "LPC11U3x"; target_add_ram(t, 0x10000000, 0x2000); - lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST, 0); return true; case 0x00040070: /* LPC1114/333 */ case 0x00050080: /* lpc1115XL */ t->driver = "LPC1100XL"; target_add_ram(t, 0x10000000, 0x2000); - lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST); + lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST, 0); return true; } if (idcode) { diff --git a/src/target/lpc_common.c b/src/target/lpc_common.c index bfb5c8ee..7b6b2efc 100644 --- a/src/target/lpc_common.c +++ b/src/target/lpc_common.c @@ -70,6 +70,9 @@ char *iap_error[] = { "Page is invalid", }; +static int lpc_flash_write(struct target_flash *tf, + target_addr dest, const void *src, size_t len); + struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length) { struct lpc_flash *lf = calloc(1, sizeof(*lf)); @@ -164,43 +167,80 @@ static uint8_t lpc_sector_for_addr(struct lpc_flash *f, uint32_t addr) return f->base_sector + (addr - f->f.start) / f->f.blocksize; } +#define LPX80X_SECTOR_SIZE 0x400 +#define LPX80X_PAGE_SIZE 0x40 + int lpc_flash_erase(struct target_flash *tf, target_addr addr, size_t len) { struct lpc_flash *f = (struct lpc_flash *)tf; uint32_t start = lpc_sector_for_addr(f, addr); uint32_t end = lpc_sector_for_addr(f, addr + len - 1); + uint32_t last_full_sector = end; if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, start, end, f->bank)) return -1; - /* and now erase them */ - if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank)) - return -2; + /* Only LPC80x has reserved pages!*/ + if (f->reserved_pages && ((addr + len) >= tf->length - 0x400) ) { + last_full_sector -= 1; + } + if (start >= last_full_sector) { + /* Sector erase */ + if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, start, last_full_sector, CPU_CLK_KHZ, f->bank)) + return -2; - /* check erase ok */ - if (lpc_iap_call(f, NULL, IAP_CMD_BLANKCHECK, start, end, f->bank)) - return -3; + /* check erase ok */ + if (lpc_iap_call(f, NULL, IAP_CMD_BLANKCHECK, start, last_full_sector, f->bank)) + return -3; + } + if (last_full_sector != end) { + uint32_t page_start = (addr + len - LPX80X_SECTOR_SIZE) / LPX80X_PAGE_SIZE; + uint32_t page_end = page_start + LPX80X_SECTOR_SIZE/LPX80X_PAGE_SIZE - 1 - f->reserved_pages; + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, end, end, f->bank)) + return -1; + if (lpc_iap_call(f, NULL, IAP_CMD_ERASE_PAGE, page_start, page_end, CPU_CLK_KHZ, f->bank)) + return -2; + /* Blank check omitted!*/ + } return 0; } -int lpc_flash_write(struct target_flash *tf, +static int lpc_flash_write(struct target_flash *tf, target_addr dest, const void *src, size_t len) { struct lpc_flash *f = (struct lpc_flash *)tf; /* prepare... */ uint32_t sector = lpc_sector_for_addr(f, dest); - if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, sector, sector, f->bank)) + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, sector, sector, f->bank)) { + DEBUG_WARN("Prepare failed\n"); return -1; - - /* Write payload to target ram */ + } uint32_t bufaddr = ALIGN(f->iap_ram + sizeof(struct flash_param), 4); target_mem_write(f->f.t, bufaddr, src, len); - - /* set the destination address and program */ - if (lpc_iap_call(f, NULL, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ)) - return -2; - + /* Only LPC80x has reserved pages!*/ + if ((!f->reserved_pages) || ((dest + len) <= (tf->length - len))) { + /* Write payload to target ram */ + /* set the destination address and program */ + if (lpc_iap_call(f, NULL, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ)) + return -2; + } else { + /* On LPC80x, write top sector in pages. + * Silently ignore write to the 2 reserved pages at top!*/ + len -= 0x40 * f->reserved_pages; + while (len) { + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, sector, sector, f->bank)) { + DEBUG_WARN("Prepare failed\n"); + return -1; + } + /* set the destination address and program */ + if (lpc_iap_call(f, NULL, IAP_CMD_PROGRAM, dest, bufaddr, LPX80X_PAGE_SIZE, CPU_CLK_KHZ)) + return -2; + dest += LPX80X_PAGE_SIZE; + bufaddr += LPX80X_PAGE_SIZE; + len -= LPX80X_PAGE_SIZE; + } + } return 0; } diff --git a/src/target/lpc_common.h b/src/target/lpc_common.h index d5a4efc3..5d17eef9 100644 --- a/src/target/lpc_common.h +++ b/src/target/lpc_common.h @@ -72,6 +72,7 @@ struct lpc_flash { struct target_flash f; uint8_t base_sector; uint8_t bank; + uint8_t reserved_pages; /* Info filled in by specific driver */ void (*wdt_kick)(target *t); uint32_t iap_entry; @@ -82,8 +83,6 @@ struct lpc_flash { struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length); enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd, ...); int lpc_flash_erase(struct target_flash *f, target_addr addr, size_t len); -int lpc_flash_write(struct target_flash *f, - target_addr dest, const void *src, size_t len); int lpc_flash_write_magic_vect(struct target_flash *f, target_addr dest, const void *src, size_t len);