Browse Source

lpc: Care for protected pages on LPC80x devices.

pull/894/head
Uwe Bonnes 3 years ago
committed by UweBonnes
parent
commit
891633322a
  1. 33
      src/target/lpc11xx.c
  2. 70
      src/target/lpc_common.c
  3. 3
      src/target/lpc_common.h

33
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) {

70
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;
}

3
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);

Loading…
Cancel
Save