lpc: Care for protected pages on LPC80x devices.
This commit is contained in:
parent
f7b4697280
commit
891633322a
|
@ -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,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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…
Reference in New Issue