lpc: Care for protected pages on LPC80x devices.

This commit is contained in:
Uwe Bonnes 2021-05-30 17:42:39 +02:00 committed by UweBonnes
parent f7b4697280
commit 891633322a
3 changed files with 73 additions and 33 deletions

View File

@ -72,7 +72,7 @@ const struct command_s lpc11xx_cmd_list[] = {
{NULL, NULL, NULL} {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); struct lpc_flash *lf = lpc_add_flash(t, addr, len);
lf->f.blocksize = erasesize; 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_entry = iap_entry;
lf->iap_ram = IAP_RAM_BASE; lf->iap_ram = IAP_RAM_BASE;
lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES; lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES;
lf->reserved_pages = reserved_pages;
} }
bool bool
@ -125,7 +126,7 @@ lpc11xx_probe(target *t)
case 0x2980002B: /* lpc11u24x/401 */ case 0x2980002B: /* lpc11u24x/401 */
t->driver = "LPC11xx"; t->driver = "LPC11xx";
target_add_ram(t, 0x10000000, 0x2000); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC11xx");
return true; return true;
@ -133,18 +134,18 @@ lpc11xx_probe(target *t)
case 0x1A24902B: case 0x1A24902B:
t->driver = "LPC1112"; t->driver = "LPC1112";
target_add_ram(t, 0x10000000, 0x1000); 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; return true;
case 0x1000002b: // FX LPC11U6 32 kB SRAM/256 kB flash (max) case 0x1000002b: // FX LPC11U6 32 kB SRAM/256 kB flash (max)
t->driver = "LPC11U6"; t->driver = "LPC11U6";
target_add_ram(t, 0x10000000, 0x8000); 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; return true;
case 0x3000002B: case 0x3000002B:
case 0x3D00002B: case 0x3D00002B:
t->driver = "LPC1343"; t->driver = "LPC1343";
target_add_ram(t, 0x10000000, 0x2000); 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; return true;
case 0x00008A04: /* LPC8N04 (see UM11074 Rev.1.3 section 4.5.19) */ case 0x00008A04: /* LPC8N04 (see UM11074 Rev.1.3 section 4.5.19) */
t->driver = "LPC8N04"; t->driver = "LPC8N04";
@ -152,7 +153,7 @@ lpc11xx_probe(target *t)
/* UM11074/ Flash controller/15.2: The two topmost sectors /* UM11074/ Flash controller/15.2: The two topmost sectors
* contain the initialization code and IAP firmware. * contain the initialization code and IAP firmware.
* Do not touch the! */ * 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC8N04");
return true; return true;
} }
@ -167,7 +168,7 @@ lpc11xx_probe(target *t)
case 0x00008024: /* 802M001JHI33 */ case 0x00008024: /* 802M001JHI33 */
t->driver = "LPC802"; t->driver = "LPC802";
target_add_ram(t, 0x10000000, 0x800); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC802");
return true; return true;
case 0x00008040: /* 804M101JBD64 */ case 0x00008040: /* 804M101JBD64 */
@ -177,7 +178,7 @@ lpc11xx_probe(target *t)
case 0x00008044: /* 804M101JHI33 */ case 0x00008044: /* 804M101JHI33 */
t->driver = "LPC804"; t->driver = "LPC804";
target_add_ram(t, 0x10000000, 0x1000); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC804");
return true; return true;
case 0x00008100: /* LPC810M021FN8 */ case 0x00008100: /* LPC810M021FN8 */
@ -187,7 +188,7 @@ lpc11xx_probe(target *t)
case 0x00008122: /* LPC812M101JDH20 / LPC812M101JTB16 */ case 0x00008122: /* LPC812M101JDH20 / LPC812M101JTB16 */
t->driver = "LPC81x"; t->driver = "LPC81x";
target_add_ram(t, 0x10000000, 0x1000); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC81x");
return true; return true;
case 0x00008221: /* LPC822M101JHI33 */ case 0x00008221: /* LPC822M101JHI33 */
@ -196,19 +197,19 @@ lpc11xx_probe(target *t)
case 0x00008242: /* LPC824M201JDH20 */ case 0x00008242: /* LPC824M201JDH20 */
t->driver = "LPC82x"; t->driver = "LPC82x";
target_add_ram(t, 0x10000000, 0x2000); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC82x");
return true; return true;
case 0x00008322: /* LPC832M101FDH20 */ case 0x00008322: /* LPC832M101FDH20 */
t->driver = "LPC832"; t->driver = "LPC832";
target_add_ram(t, 0x10000000, 0x1000); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC832");
return true; return true;
case 0x00008341: /* LPC8341201FHI33 */ case 0x00008341: /* LPC8341201FHI33 */
t->driver = "LPC834"; t->driver = "LPC834";
target_add_ram(t, 0x10000000, 0x1000); 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"); target_add_commands(t, lpc11xx_cmd_list, "LPC834");
return true; return true;
case 0x00008441: case 0x00008441:
@ -217,7 +218,7 @@ lpc11xx_probe(target *t)
case 0x00008444: case 0x00008444:
t->driver = "LPC844"; t->driver = "LPC844";
target_add_ram(t, 0x10000000, 0x2000); 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; return true;
case 0x00008451: case 0x00008451:
case 0x00008452: case 0x00008452:
@ -225,7 +226,7 @@ lpc11xx_probe(target *t)
case 0x00008454: case 0x00008454:
t->driver = "LPC845"; t->driver = "LPC845";
target_add_ram(t, 0x10000000, 0x4000); 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; return true;
case 0x0003D440: /* LPC11U34/311 */ case 0x0003D440: /* LPC11U34/311 */
case 0x0001cc40: /* LPC11U34/421 */ case 0x0001cc40: /* LPC11U34/421 */
@ -237,13 +238,13 @@ lpc11xx_probe(target *t)
case 0x00007C40: /* LPC11U37FBD64/501 */ case 0x00007C40: /* LPC11U37FBD64/501 */
t->driver = "LPC11U3x"; t->driver = "LPC11U3x";
target_add_ram(t, 0x10000000, 0x2000); 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; return true;
case 0x00040070: /* LPC1114/333 */ case 0x00040070: /* LPC1114/333 */
case 0x00050080: /* lpc1115XL */ case 0x00050080: /* lpc1115XL */
t->driver = "LPC1100XL"; t->driver = "LPC1100XL";
target_add_ram(t, 0x10000000, 0x2000); 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; return true;
} }
if (idcode) { if (idcode) {

View File

@ -70,6 +70,9 @@ char *iap_error[] = {
"Page is invalid", "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 *lpc_add_flash(target *t, target_addr addr, size_t length)
{ {
struct lpc_flash *lf = calloc(1, sizeof(*lf)); 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; 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) int lpc_flash_erase(struct target_flash *tf, target_addr addr, size_t len)
{ {
struct lpc_flash *f = (struct lpc_flash *)tf; struct lpc_flash *f = (struct lpc_flash *)tf;
uint32_t start = lpc_sector_for_addr(f, addr); uint32_t start = lpc_sector_for_addr(f, addr);
uint32_t end = lpc_sector_for_addr(f, addr + len - 1); 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)) if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, start, end, f->bank))
return -1; return -1;
/* and now erase them */ /* Only LPC80x has reserved pages!*/
if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank)) if (f->reserved_pages && ((addr + len) >= tf->length - 0x400) ) {
return -2; 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 */ /* check erase ok */
if (lpc_iap_call(f, NULL, IAP_CMD_BLANKCHECK, start, end, f->bank)) if (lpc_iap_call(f, NULL, IAP_CMD_BLANKCHECK, start, last_full_sector, f->bank))
return -3; 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; 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) target_addr dest, const void *src, size_t len)
{ {
struct lpc_flash *f = (struct lpc_flash *)tf; struct lpc_flash *f = (struct lpc_flash *)tf;
/* prepare... */ /* prepare... */
uint32_t sector = lpc_sector_for_addr(f, dest); 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; return -1;
}
/* Write payload to target ram */
uint32_t bufaddr = ALIGN(f->iap_ram + sizeof(struct flash_param), 4); uint32_t bufaddr = ALIGN(f->iap_ram + sizeof(struct flash_param), 4);
target_mem_write(f->f.t, bufaddr, src, len); target_mem_write(f->f.t, bufaddr, src, len);
/* Only LPC80x has reserved pages!*/
/* set the destination address and program */ if ((!f->reserved_pages) || ((dest + len) <= (tf->length - len))) {
if (lpc_iap_call(f, NULL, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ)) /* Write payload to target ram */
return -2; /* 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; return 0;
} }

View File

@ -72,6 +72,7 @@ struct lpc_flash {
struct target_flash f; struct target_flash f;
uint8_t base_sector; uint8_t base_sector;
uint8_t bank; uint8_t bank;
uint8_t reserved_pages;
/* Info filled in by specific driver */ /* Info filled in by specific driver */
void (*wdt_kick)(target *t); void (*wdt_kick)(target *t);
uint32_t iap_entry; 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); 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, ...); 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_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, int lpc_flash_write_magic_vect(struct target_flash *f,
target_addr dest, const void *src, size_t len); target_addr dest, const void *src, size_t len);