aboutsummaryrefslogtreecommitdiff
path: root/src/flash
diff options
context:
space:
mode:
authorZale Yu <cyyu@nuvoton.com>2022-11-06 23:32:22 +0800
committerAntonio Borneo <borneo.antonio@gmail.com>2023-01-15 15:03:09 +0000
commitd1b0cb2b774c1033a6ca8e531781df82baac40f7 (patch)
treed742ed80cd49bf243516a4f22fc9d7938c0595d7 /src/flash
parent776e045de0a2ce6644ae19de99820f02628dfbcc (diff)
downloadriscv-openocd-d1b0cb2b774c1033a6ca8e531781df82baac40f7.zip
riscv-openocd-d1b0cb2b774c1033a6ca8e531781df82baac40f7.tar.gz
riscv-openocd-d1b0cb2b774c1033a6ca8e531781df82baac40f7.tar.bz2
flash: support Nuvoton M541 & NUC442/472 series
This patch is picked from the flash part of OpenOCD-Nuvoton's commit ("flash: supported Nuvoton M4 series. jtag: Used HW reset instead of auto reset. tcl: added a configuration file for Nuvoton M4 series.") [1] to support flashing Nuvoton's Cortex-M4 chips: M541 & NUC442/472 series. The code comes from the commit basically. Jian-Hong Pan tweaked for the compatibility with current OpenOCD. So, leave the author as Zale Yu. [1]: https://github.com/OpenNuvoton/OpenOCD-Nuvoton/commit/c2d5b8bfc705 Signed-off-by: Zale Yu <cyyu@nuvoton.com> Signed-off-by: Jian-Hong Pan <chienhung.pan@gmail.com> Change-Id: I9dc69eccb851df14c1b0ce2f619d7b3da0aa92aa Reviewed-on: https://review.openocd.org/c/openocd/+/7329 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Diffstat (limited to 'src/flash')
-rw-r--r--src/flash/nor/numicro.c334
1 files changed, 253 insertions, 81 deletions
diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c
index bafad80..2bba7b7 100644
--- a/src/flash/nor/numicro.c
+++ b/src/flash/nor/numicro.c
@@ -466,6 +466,65 @@ static const struct numicro_cpu_type numicro_parts[] = {
{"NUC240SE3AE", 0x10024027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)},
{"NUC240VE3AE", 0x10024018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)},
+ /* M451 */
+ {"M451LC3AE", 0x00945101, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451LD3AE", 0x00945100, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451LE6AE", 0x00845101, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451LG6AE", 0x00845100, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451MLC3AE", 0x00945001, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451MLD3AE", 0x00945000, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451MLE6AE", 0x00845001, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451MLG6AE", 0x00845000, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451MSC3AE", 0x00945011, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451MSD3AE", 0x00945010, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451RC3AE", 0x00945121, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451RD3AE", 0x00945120, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451RE6AE", 0x00845121, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451RG6AE", 0x00845120, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451VE6AE", 0x00845131, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M451VG6AE", 0x00845130, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452LC3AE", 0x00945201, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452LD3AE", 0x00945200, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452LE6AE", 0x00845201, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452LG6AE", 0x00845200, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452RD3AE", 0x00945220, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452RE6AE", 0x00845221, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M452RG6AE", 0x00845220, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453LC3AE", 0x00945301, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453LD3AE", 0x00945300, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453LE6AE", 0x00845301, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453LG6AE", 0x00845300, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453RD3AE", 0x00945320, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453RE6AE", 0x00845321, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453RG6AE", 0x00845320, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453VD3AE", 0x00945330, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453VE6AE", 0x00845331, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M453VG6AE", 0x00845330, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M4TKVG6AE", 0x00845430, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M4TKVE6AE", 0x00845431, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M4TKRG6AE", 0x00845420, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M4TKRE6AE", 0x00845421, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M4TKLG6AE", 0x00845400, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)},
+ {"M4TKLE6AE", 0x00845401, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)},
+
+ /* NUC442_472 */
+ {"NUC442JG8AE", 0x00044203, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442JI8AE", 0x00044201, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442KG8AE", 0x00044206, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442KI8AE", 0x00044204, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442RG8AE", 0x00044212, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442RI8AE", 0x00044210, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442VG8AE", 0x00044209, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC442VI8AE", 0x00044207, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472HG8AE", 0x00047203, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472HI8AE", 0x00047201, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472JG8AE", 0x00047206, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472JI8AE", 0x00047204, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472KG8AE", 0x00047209, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472KI8AE", 0x00047207, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472VG8AE", 0x00047212, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)},
+ {"NUC472VI8AE", 0x00047210, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)},
+
{"UNKNOWN", 0x00000000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 16 * 1024, 8)},
};
@@ -476,32 +535,53 @@ struct numicro_flash_bank {
const struct numicro_cpu_type *cpu;
};
+/* Private variables */
+uint32_t m_page_size = NUMICRO_PAGESIZE;
+uint32_t m_address_bias_offset;
+
/* Private methods */
+static int numicro_get_arm_arch(struct target *target)
+{
+ struct armv7m_common *armv7m = target_to_armv7m(target);
+
+ if (armv7m->arm.arch != ARM_ARCH_V6M) {
+ LOG_DEBUG("NuMicro arm architecture: armv7m\n");
+ m_page_size = NUMICRO_PAGESIZE * 4;
+ m_address_bias_offset = 0x10000000;
+ } else {
+ LOG_DEBUG("NuMicro arm architecture: armv6m\n");
+ m_page_size = NUMICRO_PAGESIZE;
+ m_address_bias_offset = 0x0;
+ }
+
+ return ERROR_OK;
+}
+
static int numicro_reg_unlock(struct target *target)
{
uint32_t is_protected;
int retval = ERROR_OK;
/* Check to see if NUC is register unlocked or not */
- retval = target_read_u32(target, NUMICRO_SYS_WRPROT, &is_protected);
+ retval = target_read_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, &is_protected);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected);
if (is_protected == 0) { /* means protected - so unlock it */
/* unlock flash registers */
- retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY1);
+ retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY2);
+ retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY3);
+ retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY3);
if (retval != ERROR_OK)
return retval;
}
/* Check that unlock worked */
- retval = target_read_u32(target, NUMICRO_SYS_WRPROT, &is_protected);
+ retval = target_read_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, &is_protected);
if (retval != ERROR_OK)
return retval;
@@ -529,27 +609,27 @@ static int numicro_init_isp(struct target *target)
return retval;
/* Enable ISP/SRAM/TICK Clock */
- retval = target_read_u32(target, NUMICRO_SYSCLK_AHBCLK, &reg_stat);
+ retval = target_read_u32(target, NUMICRO_SYSCLK_AHBCLK - m_address_bias_offset, &reg_stat);
if (retval != ERROR_OK)
return retval;
reg_stat |= AHBCLK_ISP_EN | AHBCLK_SRAM_EN | AHBCLK_TICK_EN;
- retval = target_write_u32(target, NUMICRO_SYSCLK_AHBCLK, reg_stat);
+ retval = target_write_u32(target, NUMICRO_SYSCLK_AHBCLK - m_address_bias_offset, reg_stat);
if (retval != ERROR_OK)
return retval;
/* Enable ISP */
- retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &reg_stat);
+ retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &reg_stat);
if (retval != ERROR_OK)
return retval;
reg_stat |= ISPCON_ISPFF | ISPCON_LDUEN | ISPCON_APUEN | ISPCON_CFGUEN | ISPCON_ISPEN;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, reg_stat);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, reg_stat);
if (retval != ERROR_OK)
return retval;
/* Write one to undocumented flash control register */
- retval = target_write_u32(target, NUMICRO_FLASH_CHEAT, 1);
+ retval = target_write_u32(target, NUMICRO_FLASH_CHEAT - m_address_bias_offset, 1);
if (retval != ERROR_OK)
return retval;
@@ -561,29 +641,28 @@ static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t ad
uint32_t timeout, status;
int retval = ERROR_OK;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, cmd);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, cmd);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPDAT, wdata);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, wdata);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, addr);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPADR - m_address_bias_offset, addr);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, ISPTRG_ISPGO);
if (retval != ERROR_OK)
return retval;
/* Wait for busy to clear - check the GO flag */
timeout = 100;
for (;;) {
- retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
+ retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
if ((status & (ISPTRG_ISPGO)) == 0)
break;
if (timeout-- <= 0) {
@@ -593,79 +672,138 @@ static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t ad
busy_sleep(1); /* can use busy sleep for short times. */
}
- retval = target_read_u32(target, NUMICRO_FLASH_ISPDAT, rdata);
+ retval = target_read_u32(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, rdata);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
-
/* NuMicro Program-LongWord Microcodes */
static const uint8_t numicro_flash_write_code[] = {
- /* Params:
- * r0 - workarea buffer / result
- * r1 - target address
- * r2 - wordcount
- * Clobbered:
- * r4 - tmp
- * r5 - tmp
- * r6 - tmp
- * r7 - tmp
- */
-
- /* .L1: */
- /* for(register uint32_t i=0;i<wcount;i++){ */
+ /* Params:
+ * r0 - workarea buffer / result
+ * r1 - target address
+ * r2 - wordcount
+ * Clobbered:
+ * r4 - tmp
+ * r5 - tmp
+ * r6 - tmp
+ * r7 - tmp
+ */
+
+ /* .L1: */
+ /* for(register uint32_t i=0;i<wcount;i++){ */
0x04, 0x1C, /* mov r4, r0 */
0x00, 0x23, /* mov r3, #0 */
- /* .L2: */
+ /* .L2: */
0x0D, 0x1A, /* sub r5, r1, r0 */
0x67, 0x19, /* add r7, r4, r7 */
0x93, 0x42, /* cmp r3, r2 */
0x0C, 0xD0, /* beq .L7 */
- /* .L4: */
- /* NUMICRO_FLASH_ISPADR = faddr; */
+ /* .L4: */
+ /* NUMICRO_FLASH_ISPADR = faddr; */
0x08, 0x4E, /* ldr r6, .L8 */
0x37, 0x60, /* str r7, [r6] */
- /* NUMICRO_FLASH_ISPDAT = *pLW; */
+ /* NUMICRO_FLASH_ISPDAT = *pLW; */
0x80, 0xCC, /* ldmia r4!, {r7} */
0x08, 0x4D, /* ldr r5, .L8+4 */
0x2F, 0x60, /* str r7, [r5] */
- /* faddr += 4; */
- /* pLW++; */
- /* Trigger write action */
- /* NUMICRO_FLASH_ISPTRG = ISPTRG_ISPGO; */
+ /* faddr += 4; */
+ /* pLW++; */
+ /* Trigger write action */
+ /* NUMICRO_FLASH_ISPTRG = ISPTRG_ISPGO; */
0x08, 0x4D, /* ldr r5, .L8+8 */
0x01, 0x26, /* mov r6, #1 */
0x2E, 0x60, /* str r6, [r5] */
- /* .L3: */
- /* while((NUMICRO_FLASH_ISPTRG & ISPTRG_ISPGO) == ISPTRG_ISPGO){}; */
+ /* .L3: */
+ /* while((NUMICRO_FLASH_ISPTRG & ISPTRG_ISPGO) == ISPTRG_ISPGO){}; */
0x2F, 0x68, /* ldr r7, [r5] */
0xFF, 0x07, /* lsl r7, r7, #31 */
0xFC, 0xD4, /* bmi .L3 */
0x01, 0x33, /* add r3, r3, #1 */
0xEE, 0xE7, /* b .L2 */
- /* .L7: */
- /* return (NUMICRO_FLASH_ISPCON & ISPCON_ISPFF); */
+ /* .L7: */
+ /* return (NUMICRO_FLASH_ISPCON & ISPCON_ISPFF); */
0x05, 0x4B, /* ldr r3, .L8+12 */
0x18, 0x68, /* ldr r0, [r3] */
0x40, 0x21, /* mov r1, #64 */
0x08, 0x40, /* and r0, r1 */
- /* .L9: */
+ /* .L9: */
0x00, 0xBE, /* bkpt #0 */
- /* .L8: */
+ /* .L8: */
0x04, 0xC0, 0x00, 0x50,/* .word 1342226436 */
0x08, 0xC0, 0x00, 0x50,/* .word 1342226440 */
0x10, 0xC0, 0x00, 0x50,/* .word 1342226448 */
0x00, 0xC0, 0x00, 0x50 /* .word 1342226432 */
};
+
+static const uint8_t numicro_m4_flash_write_code[] = {
+ /* Params:
+ * r0 - workarea buffer / result
+ * r1 - target address
+ * r2 - wordcount
+ * Clobbered:
+ * r4 - tmp
+ * r5 - tmp
+ * r6 - tmp
+ * r7 - tmp
+ */
+
+ /* .L1: */
+ /* for(register uint32_t i=0;i<wcount;i++){ */
+ 0x04, 0x1C, /* mov r4, r0 */
+ 0x00, 0x23, /* mov r3, #0 */
+ /* .L2: */
+ 0x0D, 0x1A, /* sub r5, r1, r0 */
+ 0x67, 0x19, /* add r7, r4, r7 */
+ 0x93, 0x42, /* cmp r3, r2 */
+ 0x0C, 0xD0, /* beq .L7 */
+ /* .L4: */
+ /* NUMICRO_FLASH_ISPADR = faddr; */
+ 0x08, 0x4E, /* ldr r6, .L8 */
+ 0x37, 0x60, /* str r7, [r6] */
+ /* NUMICRO_FLASH_ISPDAT = *pLW; */
+ 0x80, 0xCC, /* ldmia r4!, {r7} */
+ 0x08, 0x4D, /* ldr r5, .L8+4 */
+ 0x2F, 0x60, /* str r7, [r5] */
+ /* faddr += 4; */
+ /* pLW++; */
+ /* Trigger write action */
+ /* NUMICRO_FLASH_ISPTRG = ISPTRG_ISPGO; */
+ 0x08, 0x4D, /* ldr r5, .L8+8 */
+ 0x01, 0x26, /* mov r6, #1 */
+ 0x2E, 0x60, /* str r6, [r5] */
+ /* .L3: */
+ /* while((NUMICRO_FLASH_ISPTRG & ISPTRG_ISPGO) == ISPTRG_ISPGO){}; */
+ 0x2F, 0x68, /* ldr r7, [r5] */
+ 0xFF, 0x07, /* lsl r7, r7, #31 */
+ 0xFC, 0xD4, /* bmi .L3 */
+
+ 0x01, 0x33, /* add r3, r3, #1 */
+ 0xEE, 0xE7, /* b .L2 */
+ /* .L7: */
+ /* return (NUMICRO_FLASH_ISPCON & ISPCON_ISPFF); */
+ 0x05, 0x4B, /* ldr r3, .L8+12 */
+ 0x18, 0x68, /* ldr r0, [r3] */
+ 0x40, 0x21, /* mov r1, #64 */
+ 0x08, 0x40, /* and r0, r1 */
+ /* .L9: */
+ 0x00, 0xBE, /* bkpt #0 */
+ /* .L8: */
+ 0x04, 0xC0, 0x00, 0x40,/* .word 0x4000C004 */
+ 0x08, 0xC0, 0x00, 0x40,/* .word 0x4000C008 */
+ 0x10, 0xC0, 0x00, 0x40,/* .word 0x4000C010 */
+ 0x00, 0xC0, 0x00, 0x40 /* .word 0x4000C000 */
+};
+
/* Program LongWord Block Write */
static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- uint32_t buffer_size = 1024; /* Default minimum value */
+ uint32_t buffer_size = 1024; /* Default minimum value */
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
@@ -693,18 +831,34 @@ static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer,
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
+ /* Difference between M0 and M4 */
+ if (m_page_size == NUMICRO_PAGESIZE) {
+ /* allocate working area with flash programming code */
+ if (target_alloc_working_area(target, sizeof(numicro_flash_write_code),
+ &write_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
- /* allocate working area with flash programming code */
- if (target_alloc_working_area(target, sizeof(numicro_flash_write_code),
+ retval = target_write_buffer(target, write_algorithm->address,
+ sizeof(numicro_flash_write_code), numicro_flash_write_code);
+ if (retval != ERROR_OK)
+ return retval;
+ } else { /* for M4 */
+ /* allocate working area with flash programming code */
+ if (target_alloc_working_area(target, sizeof(numicro_m4_flash_write_code),
&write_algorithm) != ERROR_OK) {
- LOG_WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
- retval = target_write_buffer(target, write_algorithm->address,
- sizeof(numicro_flash_write_code), numicro_flash_write_code);
- if (retval != ERROR_OK)
- return retval;
+ retval = target_write_buffer(target, write_algorithm->address,
+ sizeof(numicro_m4_flash_write_code), numicro_m4_flash_write_code);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer_size = m_page_size;
+ }
/* memory buffer */
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
@@ -775,13 +929,14 @@ static int numicro_protect_check(struct flash_bank *bank)
LOG_INFO("Nuvoton NuMicro: Flash Lock Check...");
+ numicro_get_arm_arch(target);
retval = numicro_init_isp(target);
if (retval != ERROR_OK)
return retval;
/* Read CONFIG0,CONFIG1 */
- numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0, 0 , &config[0]);
- numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1, 0 , &config[1]);
+ numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0 - m_address_bias_offset, 0, &config[0]);
+ numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1 - m_address_bias_offset, 0, &config[1]);
LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32 "", config[0], config[1]);
@@ -821,31 +976,34 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first,
LOG_INFO("Nuvoton NuMicro: Sector Erase ... (%u to %u)", first, last);
+ numicro_get_arm_arch(target);
retval = numicro_init_isp(target);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, ISPCMD_ERASE);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, ISPCMD_ERASE);
if (retval != ERROR_OK)
return retval;
for (unsigned int i = first; i <= last; i++) {
- LOG_DEBUG("erasing sector %u at address " TARGET_ADDR_FMT, i,
- bank->base + bank->sectors[i].offset);
- retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + bank->sectors[i].offset);
+ LOG_DEBUG("erasing sector %u at address " TARGET_ADDR_FMT, i, bank->base + bank->sectors[i].offset);
+ retval = target_write_u32(target,
+ NUMICRO_FLASH_ISPADR - m_address_bias_offset,
+ bank->base + bank->sectors[i].offset);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); /* This is the only bit available */
+ retval = target_write_u32(target,
+ NUMICRO_FLASH_ISPTRG - m_address_bias_offset,
+ ISPTRG_ISPGO); /* This is the only bit available */
if (retval != ERROR_OK)
return retval;
/* wait for busy to clear - check the GO flag */
timeout = 100;
for (;;) {
- retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
+ retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
if (status == 0)
break;
if (timeout-- <= 0) {
@@ -856,13 +1014,13 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first,
}
/* check for failure */
- retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &status);
+ retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &status);
if (retval != ERROR_OK)
return retval;
if ((status & ISPCON_ISPFF) != 0) {
LOG_DEBUG("failure: 0x%" PRIx32 "", status);
/* if bit is set, then must write to it to clear it. */
- retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, (status | ISPCON_ISPFF));
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, (status | ISPCON_ISPFF));
if (retval != ERROR_OK)
return retval;
}
@@ -889,11 +1047,12 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_INFO("Nuvoton NuMicro: Flash Write ...");
+ numicro_get_arm_arch(target);
retval = numicro_init_isp(target);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, ISPCMD_WRITE);
+ retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, ISPCMD_WRITE);
if (retval != ERROR_OK)
return retval;
@@ -913,26 +1072,34 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
/* program command */
for (uint32_t i = 0; i < count; i += 4) {
+ /* write 4 bytes each time with 0xff padding to avoid unaligned case */
+ uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
+ memcpy(padding, buffer + i, MIN(4, count - i));
- LOG_DEBUG("write longword @ %08" PRIX32, offset + i);
-
- retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i);
+ retval = target_write_u32(target,
+ NUMICRO_FLASH_ISPADR - m_address_bias_offset,
+ bank->base + offset + i);
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i);
+ retval = target_write_memory(target,
+ NUMICRO_FLASH_ISPDAT - m_address_bias_offset,
+ 4, 1, padding);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
+ retval = target_write_u32(target,
+ NUMICRO_FLASH_ISPTRG - m_address_bias_offset,
+ ISPTRG_ISPGO);
if (retval != ERROR_OK)
return retval;
/* wait for busy to clear - check the GO flag */
timeout = 100;
for (;;) {
- retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
+ retval = target_read_u32(target,
+ NUMICRO_FLASH_ISPTRG - m_address_bias_offset,
+ &status);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
if (status == 0)
break;
if (timeout-- <= 0) {
@@ -946,13 +1113,15 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* check for failure */
- retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &status);
+ retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &status);
if (retval != ERROR_OK)
return retval;
if ((status & ISPCON_ISPFF) != 0) {
LOG_DEBUG("failure: 0x%" PRIx32 "", status);
/* if bit is set, then must write to it to clear it. */
- retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, (status | ISPCON_ISPFF));
+ retval = target_write_u32(target,
+ NUMICRO_FLASH_ISPCON - m_address_bias_offset,
+ (status | ISPCON_ISPFF));
if (retval != ERROR_OK)
return retval;
} else {
@@ -970,8 +1139,9 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_
uint32_t part_id;
int retval = ERROR_OK;
+ numicro_get_arm_arch(target);
/* Read NuMicro PartID */
- retval = target_read_u32(target, NUMICRO_SYS_BASE, &part_id);
+ retval = target_read_u32(target, NUMICRO_SYS_BASE - m_address_bias_offset, &part_id);
if (retval != ERROR_OK) {
LOG_WARNING("NuMicro flash driver: Failed to Get PartID\n");
return ERROR_FLASH_OPERATION_FAILED;
@@ -1023,7 +1193,7 @@ static int numicro_probe(struct flash_bank *bank)
return ERROR_FLASH_OPERATION_FAILED;
}
- num_pages = flash_size / NUMICRO_PAGESIZE;
+ num_pages = flash_size / m_page_size;
bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
@@ -1031,10 +1201,10 @@ static int numicro_probe(struct flash_bank *bank)
for (int i = 0; i < num_pages; i++) {
bank->sectors[i].offset = offset;
- bank->sectors[i].size = NUMICRO_PAGESIZE;
+ bank->sectors[i].size = m_page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
- offset += NUMICRO_PAGESIZE;
+ offset += m_page_size;
}
struct numicro_flash_bank *numicro_info = bank->driver_priv;
@@ -1073,7 +1243,6 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command)
bank->write_start_alignment = bank->write_end_alignment = 4;
return ERROR_OK;
-
}
COMMAND_HANDLER(numicro_handle_read_isp_command)
@@ -1089,6 +1258,7 @@ COMMAND_HANDLER(numicro_handle_read_isp_command)
struct target *target = get_current_target(CMD_CTX);
+ numicro_get_arm_arch(target);
retval = numicro_init_isp(target);
if (retval != ERROR_OK)
return retval;
@@ -1116,6 +1286,7 @@ COMMAND_HANDLER(numicro_handle_write_isp_command)
struct target *target = get_current_target(CMD_CTX);
+ numicro_get_arm_arch(target);
retval = numicro_init_isp(target);
if (retval != ERROR_OK)
return retval;
@@ -1138,6 +1309,7 @@ COMMAND_HANDLER(numicro_handle_chip_erase_command)
struct target *target = get_current_target(CMD_CTX);
+ numicro_get_arm_arch(target);
retval = numicro_init_isp(target);
if (retval != ERROR_OK)
return retval;