diff options
Diffstat (limited to 'src/flash/nor')
-rw-r--r-- | src/flash/nor/Makefile.am | 3 | ||||
-rw-r--r-- | src/flash/nor/drivers.c | 4 | ||||
-rw-r--r-- | src/flash/nor/efm32.c | 99 | ||||
-rw-r--r-- | src/flash/nor/kinetis.c | 3 | ||||
-rw-r--r-- | src/flash/nor/nrf5.c (renamed from src/flash/nor/nrf51.c) | 815 | ||||
-rw-r--r-- | src/flash/nor/spi.c | 100 | ||||
-rw-r--r-- | src/flash/nor/stm32f2x.c | 17 | ||||
-rw-r--r-- | src/flash/nor/stm32h7x.c | 1183 | ||||
-rw-r--r-- | src/flash/nor/stm32lx.c | 15 | ||||
-rw-r--r-- | src/flash/nor/xmc4xxx.c | 4 |
10 files changed, 1647 insertions, 596 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index c647cbb..8a57f4f 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -37,7 +37,7 @@ NOR_DRIVERS = \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ - %D%/nrf51.c \ + %D%/nrf5.c \ %D%/numicro.c \ %D%/ocl.c \ %D%/pic32mx.c \ @@ -50,6 +50,7 @@ NOR_DRIVERS = \ %D%/stm32f2x.c \ %D%/stm32lx.c \ %D%/stm32l4x.c \ + %D%/stm32h7x.c \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 56b451c..3f0c3c7 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -49,6 +49,7 @@ extern struct flash_driver lpcspifi_flash; extern struct flash_driver mdr_flash; extern struct flash_driver mrvlqspi_flash; extern struct flash_driver niietcm4_flash; +extern struct flash_driver nrf5_flash; extern struct flash_driver nrf51_flash; extern struct flash_driver numicro_flash; extern struct flash_driver ocl_flash; @@ -60,6 +61,7 @@ extern struct flash_driver stm32f1x_flash; extern struct flash_driver stm32f2x_flash; extern struct flash_driver stm32lx_flash; extern struct flash_driver stm32l4x_flash; +extern struct flash_driver stm32h7x_flash; extern struct flash_driver stmsmi_flash; extern struct flash_driver str7x_flash; extern struct flash_driver str9x_flash; @@ -103,6 +105,7 @@ static struct flash_driver *flash_drivers[] = { &mdr_flash, &mrvlqspi_flash, &niietcm4_flash, + &nrf5_flash, &nrf51_flash, &numicro_flash, &ocl_flash, @@ -114,6 +117,7 @@ static struct flash_driver *flash_drivers[] = { &stm32f2x_flash, &stm32lx_flash, &stm32l4x_flash, + &stm32h7x_flash, &stmsmi_flash, &str7x_flash, &str9x_flash, diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 117cd8a..b8453e1 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -49,6 +49,8 @@ #define EZR_FAMILY_ID_WONDER_GECKO 120 #define EZR_FAMILY_ID_LEOPARD_GECKO 121 #define EZR_FAMILY_ID_HAPPY_GECKO 122 +#define EFR_FAMILY_ID_MIGHTY_GECKO 16 +#define EFR_FAMILY_ID_BLUE_GECKO 20 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 @@ -72,27 +74,31 @@ #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 -#define EFM32_MSC_WRITECTRL (EFM32_MSC_REGBASE+0x008) +#define EFR32_MSC_REGBASE 0x400e0000 +#define EFM32_MSC_REG_WRITECTRL 0x008 #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 -#define EFM32_MSC_WRITECMD (EFM32_MSC_REGBASE+0x00c) +#define EFM32_MSC_REG_WRITECMD 0x00c #define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1 #define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2 #define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8 -#define EFM32_MSC_ADDRB (EFM32_MSC_REGBASE+0x010) -#define EFM32_MSC_WDATA (EFM32_MSC_REGBASE+0x018) -#define EFM32_MSC_STATUS (EFM32_MSC_REGBASE+0x01c) +#define EFM32_MSC_REG_ADDRB 0x010 +#define EFM32_MSC_REG_WDATA 0x018 +#define EFM32_MSC_REG_STATUS 0x01c #define EFM32_MSC_STATUS_BUSY_MASK 0x1 #define EFM32_MSC_STATUS_LOCKED_MASK 0x2 #define EFM32_MSC_STATUS_INVADDR_MASK 0x4 #define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8 #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 -#define EFM32_MSC_LOCK (EFM32_MSC_REGBASE+0x03c) +#define EFM32_MSC_REG_LOCK 0x03c +#define EFR32_MSC_REG_LOCK 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 struct efm32x_flash_bank { int probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; + uint32_t reg_base; + uint32_t reg_lock; }; struct efm32_info { @@ -132,11 +138,30 @@ static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev); } +static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t *value) +{ + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + uint32_t base = efm32x_info->reg_base; + + return target_read_u32(bank->target, base + offset, value); +} + +static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t value) +{ + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + uint32_t base = efm32x_info->reg_base; + + return target_write_u32(bank->target, base + offset, value); +} + static int efm32x_read_info(struct flash_bank *bank, struct efm32_info *efm32_info) { int ret; uint32_t cpuid = 0; + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; memset(efm32_info, 0, sizeof(struct efm32_info)); @@ -175,6 +200,15 @@ static int efm32x_read_info(struct flash_bank *bank, if (ERROR_OK != ret) return ret; + if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { + efm32x_info->reg_base = EFR32_MSC_REGBASE; + efm32x_info->reg_lock = EFR32_MSC_REG_LOCK; + } else { + efm32x_info->reg_base = EFM32_MSC_REGBASE; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + } + if (EFM_FAMILY_ID_GECKO == efm32_info->part_family || EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) efm32_info->page_size = 512; @@ -208,7 +242,9 @@ static int efm32x_read_info(struct flash_bank *bank, } } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { + EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); @@ -241,6 +277,10 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "EZR32 "); break; + case EFR_FAMILY_ID_MIGHTY_GECKO: + case EFR_FAMILY_ID_BLUE_GECKO: + printed = snprintf(buf, buf_size, "EFR32 "); + break; default: printed = snprintf(buf, buf_size, "EFM32 "); } @@ -276,6 +316,12 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "Happy Gecko"); break; + case EFR_FAMILY_ID_BLUE_GECKO: + printed = snprintf(buf, buf_size, "Blue Gecko"); + break; + case EFR_FAMILY_ID_MIGHTY_GECKO: + printed = snprintf(buf, buf_size, "Mighty Gecko"); + break; } buf += printed; @@ -319,7 +365,7 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, int ret = 0; uint32_t reg_val = 0; - ret = target_read_u32(bank->target, reg, ®_val); + ret = efm32x_read_reg_u32(bank, reg, ®_val); if (ERROR_OK != ret) return ret; @@ -328,18 +374,19 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, else reg_val &= ~bitmask; - return target_write_u32(bank->target, reg, reg_val); + return efm32x_write_reg_u32(bank, reg, reg_val); } static int efm32x_set_wren(struct flash_bank *bank, int write_enable) { - return efm32x_set_reg_bits(bank, EFM32_MSC_WRITECTRL, + return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL, EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); } static int efm32x_msc_lock(struct flash_bank *bank, int lock) { - return target_write_u32(bank->target, EFM32_MSC_LOCK, + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + return efm32x_write_reg_u32(bank, efm32x_info->reg_lock, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } @@ -350,7 +397,7 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout, uint32_t status = 0; while (1) { - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) break; @@ -389,16 +436,16 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); - ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ERROR_OK != ret) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) return ret; @@ -412,7 +459,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) return ERROR_FAIL; } - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); if (ERROR_OK != ret) return ret; @@ -589,6 +636,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ @@ -598,10 +646,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */ /* #define EFM32_MSC_WDATA_OFFSET 0x018 */ /* #define EFM32_MSC_STATUS_OFFSET 0x01c */ - /* #define EFM32_MSC_LOCK_OFFSET 0x03c */ - 0x15, 0x4e, /* ldr r6, =#0x1b71 */ - 0xc6, 0x63, /* str r6, [r0, #EFM32_MSC_LOCK_OFFSET] */ 0x01, 0x26, /* movs r6, #1 */ 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */ @@ -660,11 +705,9 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xbe, /* bkpt #0 */ - - /* LOCKKEY */ - 0x71, 0x1b, 0x00, 0x00 }; + /* flash write code */ if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code), &write_algorithm) != ERROR_OK) { @@ -697,7 +740,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ - buf_set_u32(reg_params[0].value, 0, 32, EFM32_MSC_REGBASE); + buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); @@ -762,16 +805,16 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, /* if not called, GDB errors will be reported during large writes */ keep_alive(); - ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ERROR_OK != ret) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) return ret; @@ -792,13 +835,13 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ret; } - ret = target_write_u32(bank->target, EFM32_MSC_WDATA, val); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val); if (ERROR_OK != ret) { LOG_ERROR("WDATA write failed"); return ret; } - ret = target_write_u32(bank->target, EFM32_MSC_WRITECMD, + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_WRITEONCE_MASK); if (ERROR_OK != ret) { LOG_ERROR("WRITECMD write failed"); diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 4ef4385..5c0ffbd 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1959,7 +1959,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned cpu_mhz = 120; unsigned idx; bool use_nvm_marking = false; - char flash_marking[8], nvm_marking[2]; + char flash_marking[11], nvm_marking[2]; char name[40]; k_chip->probed = false; @@ -2126,6 +2126,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX1: /* errata 7534 - should be K63 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ subfamid += 2; /* errata 7534 fix */ + /* fallthrough */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: /* K63FN1M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX4: diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf5.c index 7b7acf4..11e5729 100644 --- a/src/flash/nor/nrf51.c +++ b/src/flash/nor/nrf5.c @@ -28,97 +28,97 @@ #include <helper/types.h> enum { - NRF51_FLASH_BASE = 0x00000000, + NRF5_FLASH_BASE = 0x00000000, }; -enum nrf51_ficr_registers { - NRF51_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ - -#define NRF51_FICR_REG(offset) (NRF51_FICR_BASE + offset) - - NRF51_FICR_CODEPAGESIZE = NRF51_FICR_REG(0x010), - NRF51_FICR_CODESIZE = NRF51_FICR_REG(0x014), - NRF51_FICR_CLENR0 = NRF51_FICR_REG(0x028), - NRF51_FICR_PPFC = NRF51_FICR_REG(0x02C), - NRF51_FICR_NUMRAMBLOCK = NRF51_FICR_REG(0x034), - NRF51_FICR_SIZERAMBLOCK0 = NRF51_FICR_REG(0x038), - NRF51_FICR_SIZERAMBLOCK1 = NRF51_FICR_REG(0x03C), - NRF51_FICR_SIZERAMBLOCK2 = NRF51_FICR_REG(0x040), - NRF51_FICR_SIZERAMBLOCK3 = NRF51_FICR_REG(0x044), - NRF51_FICR_CONFIGID = NRF51_FICR_REG(0x05C), - NRF51_FICR_DEVICEID0 = NRF51_FICR_REG(0x060), - NRF51_FICR_DEVICEID1 = NRF51_FICR_REG(0x064), - NRF51_FICR_ER0 = NRF51_FICR_REG(0x080), - NRF51_FICR_ER1 = NRF51_FICR_REG(0x084), - NRF51_FICR_ER2 = NRF51_FICR_REG(0x088), - NRF51_FICR_ER3 = NRF51_FICR_REG(0x08C), - NRF51_FICR_IR0 = NRF51_FICR_REG(0x090), - NRF51_FICR_IR1 = NRF51_FICR_REG(0x094), - NRF51_FICR_IR2 = NRF51_FICR_REG(0x098), - NRF51_FICR_IR3 = NRF51_FICR_REG(0x09C), - NRF51_FICR_DEVICEADDRTYPE = NRF51_FICR_REG(0x0A0), - NRF51_FICR_DEVICEADDR0 = NRF51_FICR_REG(0x0A4), - NRF51_FICR_DEVICEADDR1 = NRF51_FICR_REG(0x0A8), - NRF51_FICR_OVERRIDEN = NRF51_FICR_REG(0x0AC), - NRF51_FICR_NRF_1MBIT0 = NRF51_FICR_REG(0x0B0), - NRF51_FICR_NRF_1MBIT1 = NRF51_FICR_REG(0x0B4), - NRF51_FICR_NRF_1MBIT2 = NRF51_FICR_REG(0x0B8), - NRF51_FICR_NRF_1MBIT3 = NRF51_FICR_REG(0x0BC), - NRF51_FICR_NRF_1MBIT4 = NRF51_FICR_REG(0x0C0), - NRF51_FICR_BLE_1MBIT0 = NRF51_FICR_REG(0x0EC), - NRF51_FICR_BLE_1MBIT1 = NRF51_FICR_REG(0x0F0), - NRF51_FICR_BLE_1MBIT2 = NRF51_FICR_REG(0x0F4), - NRF51_FICR_BLE_1MBIT3 = NRF51_FICR_REG(0x0F8), - NRF51_FICR_BLE_1MBIT4 = NRF51_FICR_REG(0x0FC), +enum nrf5_ficr_registers { + NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ + +#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset) + + NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), + NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), + NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028), + NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C), + NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), + NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), + NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), + NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), + NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), + NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), + NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), + NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), + NRF5_FICR_ER0 = NRF5_FICR_REG(0x080), + NRF5_FICR_ER1 = NRF5_FICR_REG(0x084), + NRF5_FICR_ER2 = NRF5_FICR_REG(0x088), + NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C), + NRF5_FICR_IR0 = NRF5_FICR_REG(0x090), + NRF5_FICR_IR1 = NRF5_FICR_REG(0x094), + NRF5_FICR_IR2 = NRF5_FICR_REG(0x098), + NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C), + NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), + NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), + NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), + NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), + NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), + NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), + NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), + NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), + NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), + NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), + NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), + NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), + NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), + NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), }; -enum nrf51_uicr_registers { - NRF51_UICR_BASE = 0x10001000, /* User Information +enum nrf5_uicr_registers { + NRF5_UICR_BASE = 0x10001000, /* User Information * Configuration Regsters */ - NRF51_UICR_SIZE = 0x100, + NRF5_UICR_SIZE = 0x100, -#define NRF51_UICR_REG(offset) (NRF51_UICR_BASE + offset) +#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) - NRF51_UICR_CLENR0 = NRF51_UICR_REG(0x000), - NRF51_UICR_RBPCONF = NRF51_UICR_REG(0x004), - NRF51_UICR_XTALFREQ = NRF51_UICR_REG(0x008), - NRF51_UICR_FWID = NRF51_UICR_REG(0x010), + NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000), + NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004), + NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008), + NRF5_UICR_FWID = NRF5_UICR_REG(0x010), }; -enum nrf51_nvmc_registers { - NRF51_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory +enum nrf5_nvmc_registers { + NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory * Controller Regsters */ -#define NRF51_NVMC_REG(offset) (NRF51_NVMC_BASE + offset) +#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) - NRF51_NVMC_READY = NRF51_NVMC_REG(0x400), - NRF51_NVMC_CONFIG = NRF51_NVMC_REG(0x504), - NRF51_NVMC_ERASEPAGE = NRF51_NVMC_REG(0x508), - NRF51_NVMC_ERASEALL = NRF51_NVMC_REG(0x50C), - NRF51_NVMC_ERASEUICR = NRF51_NVMC_REG(0x514), + NRF5_NVMC_READY = NRF5_NVMC_REG(0x400), + NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504), + NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), + NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), + NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), }; -enum nrf51_nvmc_config_bits { - NRF51_NVMC_CONFIG_REN = 0x00, - NRF51_NVMC_CONFIG_WEN = 0x01, - NRF51_NVMC_CONFIG_EEN = 0x02, +enum nrf5_nvmc_config_bits { + NRF5_NVMC_CONFIG_REN = 0x00, + NRF5_NVMC_CONFIG_WEN = 0x01, + NRF5_NVMC_CONFIG_EEN = 0x02, }; -struct nrf51_info { +struct nrf5_info { uint32_t code_page_size; struct { bool probed; int (*write) (struct flash_bank *bank, - struct nrf51_info *chip, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count); } bank[2]; struct target *target; }; -struct nrf51_device_spec { +struct nrf5_device_spec { uint16_t hwid; const char *part; const char *variant; @@ -126,6 +126,15 @@ struct nrf51_device_spec { unsigned int flash_size_kb; }; +#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \ +{ \ +.hwid = (id), \ +.part = pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +} + /* The known devices table below is derived from the "nRF51 Series * Compatibility Matrix" document, which can be found by searching for * ATTN-51 on the Nordic Semi website: @@ -138,294 +147,74 @@ struct nrf51_device_spec { * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is * for x==0, x!=0 means different (unspecified) HWIDs. */ -static const struct nrf51_device_spec nrf51_known_devices_table[] = { +static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - { - .hwid = 0x001D, - .part = "51822", - .variant = "QFAA", - .build_code = "CA/C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0026, - .part = "51822", - .variant = "QFAB", - .build_code = "AA", - .flash_size_kb = 128, - }, - { - .hwid = 0x0027, - .part = "51822", - .variant = "QFAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0020, - .part = "51822", - .variant = "CEAA", - .build_code = "BA", - .flash_size_kb = 256, - }, - { - .hwid = 0x002F, - .part = "51822", - .variant = "CEAA", - .build_code = "B0", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* nRF51822 Devices (IC rev 2). */ - { - .hwid = 0x002A, - .part = "51822", - .variant = "QFAA", - .build_code = "FA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0044, - .part = "51822", - .variant = "QFAA", - .build_code = "GC0", - .flash_size_kb = 256, - }, - { - .hwid = 0x003C, - .part = "51822", - .variant = "QFAA", - .build_code = "G0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0057, - .part = "51822", - .variant = "QFAA", - .build_code = "G2", - .flash_size_kb = 256, - }, - { - .hwid = 0x0058, - .part = "51822", - .variant = "QFAA", - .build_code = "G3", - .flash_size_kb = 256, - }, - { - .hwid = 0x004C, - .part = "51822", - .variant = "QFAB", - .build_code = "B0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0040, - .part = "51822", - .variant = "CEAA", - .build_code = "CA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0047, - .part = "51822", - .variant = "CEAA", - .build_code = "DA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x004D, - .part = "51822", - .variant = "CEAA", - .build_code = "D00", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - { - .hwid = 0x0072, - .part = "51822", - .variant = "QFAA", - .build_code = "H0", - .flash_size_kb = 256, - }, - { - .hwid = 0x007B, - .part = "51822", - .variant = "QFAB", - .build_code = "C0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0083, - .part = "51822", - .variant = "QFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0084, - .part = "51822", - .variant = "QFAC", - .build_code = "A1", - .flash_size_kb = 256, - }, - { - .hwid = 0x007D, - .part = "51822", - .variant = "CDAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0079, - .part = "51822", - .variant = "CEAA", - .build_code = "E0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0087, - .part = "51822", - .variant = "CFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x008F, - .part = "51822", - .variant = "QFAA", - .build_code = "H1", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), /* nRF51422 Devices (IC rev 1). */ - { - .hwid = 0x001E, - .part = "51422", - .variant = "QFAA", - .build_code = "CA", - .flash_size_kb = 256, - }, - { - .hwid = 0x0024, - .part = "51422", - .variant = "QFAA", - .build_code = "C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0031, - .part = "51422", - .variant = "CEAA", - .build_code = "A0A", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - { - .hwid = 0x002D, - .part = "51422", - .variant = "QFAA", - .build_code = "DAA", - .flash_size_kb = 256, - }, - { - .hwid = 0x002E, - .part = "51422", - .variant = "QFAA", - .build_code = "E0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0061, - .part = "51422", - .variant = "QFAB", - .build_code = "A00", - .flash_size_kb = 128, - }, - { - .hwid = 0x0050, - .part = "51422", - .variant = "CEAA", - .build_code = "B0", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - { - .hwid = 0x0073, - .part = "51422", - .variant = "QFAA", - .build_code = "F0", - .flash_size_kb = 256, - }, - { - .hwid = 0x007C, - .part = "51422", - .variant = "QFAB", - .build_code = "B0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0085, - .part = "51422", - .variant = "QFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0086, - .part = "51422", - .variant = "QFAC", - .build_code = "A1", - .flash_size_kb = 256, - }, - { - .hwid = 0x007E, - .part = "51422", - .variant = "CDAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x007A, - .part = "51422", - .variant = "CEAA", - .build_code = "C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0088, - .part = "51422", - .variant = "CFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + + /* nRF52832 Devices */ + NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ - { - .hwid = 0x0071, - .part = "51822", - .variant = "QFAC", - .build_code = "AB", - .flash_size_kb = 256, - }, + NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; -static int nrf51_bank_is_probed(struct flash_bank *bank) +static int nrf5_bank_is_probed(struct flash_bank *bank) { - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; assert(chip != NULL); return chip->bank[bank->bank_number].probed; } -static int nrf51_probe(struct flash_bank *bank); +static int nrf5_probe(struct flash_bank *bank); -static int nrf51_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf51_info **chip) +static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -434,23 +223,23 @@ static int nrf51_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf51 *chip = bank->driver_priv; - int probed = nrf51_bank_is_probed(bank); + int probed = nrf5_bank_is_probed(bank); if (probed < 0) return probed; else if (!probed) - return nrf51_probe(bank); + return nrf5_probe(bank); else return ERROR_OK; } -static int nrf51_wait_for_nvmc(struct nrf51_info *chip) +static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { uint32_t ready; int res; int timeout = 100; do { - res = target_read_u32(chip->target, NRF51_NVMC_READY, &ready); + res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); if (res != ERROR_OK) { LOG_ERROR("Couldn't read NVMC_READY register"); return res; @@ -466,12 +255,12 @@ static int nrf51_wait_for_nvmc(struct nrf51_info *chip) return ERROR_FLASH_BUSY; } -static int nrf51_nvmc_erase_enable(struct nrf51_info *chip) +static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_EEN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_EEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable erase operation"); @@ -482,19 +271,19 @@ static int nrf51_nvmc_erase_enable(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Erase enable did not complete"); return res; } -static int nrf51_nvmc_write_enable(struct nrf51_info *chip) +static int nrf5_nvmc_write_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_WEN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_WEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable write operation"); @@ -505,19 +294,19 @@ static int nrf51_nvmc_write_enable(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Write enable did not complete"); return res; } -static int nrf51_nvmc_read_only(struct nrf51_info *chip) +static int nrf5_nvmc_read_only(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_REN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_REN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable read-only operation"); @@ -527,19 +316,19 @@ static int nrf51_nvmc_read_only(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Read only enable did not complete"); return res; } -static int nrf51_nvmc_generic_erase(struct nrf51_info *chip, +static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, uint32_t erase_register, uint32_t erase_value) { int res; - res = nrf51_nvmc_erase_enable(chip); + res = nrf5_nvmc_erase_enable(chip); if (res != ERROR_OK) goto error; @@ -549,34 +338,34 @@ static int nrf51_nvmc_generic_erase(struct nrf51_info *chip, if (res != ERROR_OK) goto set_read_only; - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) goto set_read_only; - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); set_read_only: - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); error: LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, erase_register, erase_value); return ERROR_FAIL; } -static int nrf51_protect_check(struct flash_bank *bank) +static int nrf5_protect_check(struct flash_bank *bank) { int res; uint32_t clenr0; /* UICR cannot be write protected so just return early */ - if (bank->base == NRF51_UICR_BASE) + if (bank->base == NRF5_UICR_BASE) return ERROR_OK; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; assert(chip != NULL); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, + res = target_read_u32(chip->target, NRF5_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); @@ -584,7 +373,7 @@ static int nrf51_protect_check(struct flash_bank *bank) } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(chip->target, NRF5_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -599,17 +388,17 @@ static int nrf51_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) +static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) { int res; uint32_t clenr0, ppfc; - struct nrf51_info *chip; + struct nrf5_info *chip; /* UICR cannot be write protected so just bail out early */ - if (bank->base == NRF51_UICR_BASE) + if (bank->base == NRF5_UICR_BASE) return ERROR_FAIL; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -618,7 +407,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(chip->target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -630,7 +419,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(chip->target, NRF5_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -638,7 +427,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) } if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF51_UICR_CLENR0, + res = target_write_u32(chip->target, NRF5_UICR_CLENR0, clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't write code region 0 size[UICR]"); @@ -649,18 +438,18 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) LOG_ERROR("You need to perform chip erase before changing the protection settings"); } - nrf51_protect_check(bank); + nrf5_protect_check(bank); return ERROR_OK; } -static int nrf51_probe(struct flash_bank *bank) +static int nrf5_probe(struct flash_bank *bank) { uint32_t hwid; int res; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; - res = target_read_u32(chip->target, NRF51_FICR_CONFIGID, &hwid); + res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; @@ -669,10 +458,10 @@ static int nrf51_probe(struct flash_bank *bank) hwid &= 0xFFFF; /* HWID is stored in the lower two * bytes of the CONFIGID register */ - const struct nrf51_device_spec *spec = NULL; - for (size_t i = 0; i < ARRAY_SIZE(nrf51_known_devices_table); i++) { - if (hwid == nrf51_known_devices_table[i].hwid) { - spec = &nrf51_known_devices_table[i]; + const struct nrf5_device_spec *spec = NULL; + for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { + if (hwid == nrf5_known_devices_table[i].hwid) { + spec = &nrf5_known_devices_table[i]; break; } } @@ -686,9 +475,9 @@ static int nrf51_probe(struct flash_bank *bank) LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid); } - if (bank->base == NRF51_FLASH_BASE) { - /* The value stored in NRF51_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ - res = target_read_u32(chip->target, NRF51_FICR_CODEPAGESIZE, + if (bank->base == NRF5_FLASH_BASE) { + /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, &chip->code_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); @@ -696,9 +485,9 @@ static int nrf51_probe(struct flash_bank *bank) } /* Note the register name is misleading, - * NRF51_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ uint32_t num_sectors; - res = target_read_u32(chip->target, NRF51_FICR_CODESIZE, &num_sectors); + res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; @@ -715,7 +504,7 @@ static int nrf51_probe(struct flash_bank *bank) if (!bank->sectors) return ERROR_FLASH_BANK_NOT_PROBED; - /* Fill out the sector information: all NRF51 sectors are the same size and + /* Fill out the sector information: all NRF5 sectors are the same size and * there is always a fixed number of them. */ for (int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = chip->code_page_size; @@ -726,11 +515,11 @@ static int nrf51_probe(struct flash_bank *bank) bank->sectors[i].is_protected = -1; } - nrf51_protect_check(bank); + nrf5_protect_check(bank); chip->bank[0].probed = true; } else { - bank->size = NRF51_UICR_SIZE; + bank->size = NRF5_UICR_SIZE; bank->num_sectors = 1; bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0])); @@ -750,21 +539,21 @@ static int nrf51_probe(struct flash_bank *bank) return ERROR_OK; } -static int nrf51_auto_probe(struct flash_bank *bank) +static int nrf5_auto_probe(struct flash_bank *bank) { - int probed = nrf51_bank_is_probed(bank); + int probed = nrf5_bank_is_probed(bank); if (probed < 0) return probed; else if (probed) return ERROR_OK; else - return nrf51_probe(bank); + return nrf5_probe(bank); } -static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank, uint32_t address) +static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address) { - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; for (int i = 0; i < bank->num_sectors; i++) if (bank->sectors[i].offset <= address && @@ -773,16 +562,16 @@ static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank return NULL; } -static int nrf51_erase_all(struct nrf51_info *chip) +static int nrf5_erase_all(struct nrf5_info *chip) { LOG_DEBUG("Erasing all non-volatile memory"); - return nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEALL, + return nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEALL, 0x00000001); } -static int nrf51_erase_page(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_erase_page(struct flash_bank *bank, + struct nrf5_info *chip, struct flash_sector *sector) { int res; @@ -793,9 +582,9 @@ static int nrf51_erase_page(struct flash_bank *bank, return ERROR_FAIL; } - if (bank->base == NRF51_UICR_BASE) { + if (bank->base == NRF5_UICR_BASE) { uint32_t ppfc; - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(chip->target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -813,14 +602,14 @@ static int nrf51_erase_page(struct flash_bank *bank, return ERROR_FAIL; } - res = nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEUICR, + res = nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEUICR, 0x00000001); } else { - res = nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEPAGE, + res = nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEPAGE, sector->offset); } @@ -830,7 +619,7 @@ static int nrf51_erase_page(struct flash_bank *bank, return res; } -static const uint8_t nrf51_flash_write_code[] = { +static const uint8_t nrf5_flash_write_code[] = { /* See contrib/loaders/flash/cortex-m0.S */ /* <wait_fifo>: */ 0x0d, 0x68, /* ldr r5, [r1, #0] */ @@ -855,13 +644,13 @@ static const uint8_t nrf51_flash_write_code[] = { /* Start a low level flash write for the specified region */ -static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) +static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; - uint32_t address = NRF51_FLASH_BASE + offset; + uint32_t address = NRF5_FLASH_BASE + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -871,7 +660,7 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const assert(bytes % 4 == 0); /* allocate working area with flash programming code */ - if (target_alloc_working_area(target, sizeof(nrf51_flash_write_code), + if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); @@ -880,7 +669,7 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const if (retval != ERROR_OK) return retval; - retval = nrf51_wait_for_nvmc(chip); + retval = nrf5_wait_for_nvmc(chip); if (retval != ERROR_OK) return retval; @@ -893,11 +682,11 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const LOG_WARNING("using fast async flash loader. This is currently supported"); LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add"); - LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg to disable it"); + LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it"); retval = target_write_buffer(target, write_algorithm->address, - sizeof(nrf51_flash_write_code), - nrf51_flash_write_code); + sizeof(nrf5_flash_write_code), + nrf5_flash_write_code); if (retval != ERROR_OK) return retval; @@ -948,10 +737,10 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const /* Check and erase flash sectors in specified range then start a low level page write. start/end must be sector aligned. */ -static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) +static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) { int res = ERROR_FAIL; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; struct flash_sector *sector; uint32_t offset; @@ -960,7 +749,7 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e /* Erase all sectors */ for (offset = start; offset < end; offset += chip->code_page_size) { - sector = nrf51_find_sector_by_address(bank, offset); + sector = nrf5_find_sector_by_address(bank, offset); if (!sector) { LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset); return ERROR_FLASH_SECTOR_INVALID; @@ -972,7 +761,7 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e } if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */ - res = nrf51_erase_page(bank, chip, sector); + res = nrf5_erase_page(bank, chip, sector); if (res != ERROR_OK) { LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset); goto error; @@ -981,41 +770,41 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e sector->is_erased = 0; } - res = nrf51_nvmc_write_enable(chip); + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; - res = nrf51_ll_flash_write(chip, start, buffer, (end - start)); + res = nrf5_ll_flash_write(chip, start, buffer, (end - start)); if (res != ERROR_OK) goto set_read_only; - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); set_read_only: - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); error: - LOG_ERROR("Failed to write to nrf51 flash"); + LOG_ERROR("Failed to write to nrf5 flash"); return res; } -static int nrf51_erase(struct flash_bank *bank, int first, int last) +static int nrf5_erase(struct flash_bank *bank, int first, int last) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; /* For each sector to be erased */ for (int s = first; s <= last && res == ERROR_OK; s++) - res = nrf51_erase_page(bank, chip, &bank->sectors[s]); + res = nrf5_erase_page(bank, chip, &bank->sectors[s]); return res; } -static int nrf51_code_flash_write(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_code_flash_write(struct flash_bank *bank, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -1062,58 +851,58 @@ static int nrf51_code_flash_write(struct flash_bank *bank, return res; } - return nrf51_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); + return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); } -static int nrf51_uicr_flash_write(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_uicr_flash_write(struct flash_bank *bank, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; - uint8_t uicr[NRF51_UICR_SIZE]; + uint8_t uicr[NRF5_UICR_SIZE]; struct flash_sector *sector = &bank->sectors[0]; - if ((offset + count) > NRF51_UICR_SIZE) + if ((offset + count) > NRF5_UICR_SIZE) return ERROR_FAIL; res = target_read_memory(bank->target, - NRF51_UICR_BASE, + NRF5_UICR_BASE, 1, - NRF51_UICR_SIZE, + NRF5_UICR_SIZE, uicr); if (res != ERROR_OK) return res; if (sector->is_erased != 1) { - res = nrf51_erase_page(bank, chip, sector); + res = nrf5_erase_page(bank, chip, sector); if (res != ERROR_OK) return res; } - res = nrf51_nvmc_write_enable(chip); + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) return res; memcpy(&uicr[offset], buffer, count); - res = nrf51_ll_flash_write(chip, NRF51_UICR_BASE, uicr, NRF51_UICR_SIZE); + res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE); if (res != ERROR_OK) { - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); return res; } - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); } -static int nrf51_write(struct flash_bank *bank, const uint8_t *buffer, +static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -1121,15 +910,15 @@ static int nrf51_write(struct flash_bank *bank, const uint8_t *buffer, } -FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { - static struct nrf51_info *chip; + static struct nrf5_info *chip; switch (bank->base) { - case NRF51_FLASH_BASE: + case NRF5_FLASH_BASE: bank->bank_number = 0; break; - case NRF51_UICR_BASE: + case NRF5_UICR_BASE: bank->bank_number = 1; break; default: @@ -1147,11 +936,11 @@ FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) } switch (bank->base) { - case NRF51_FLASH_BASE: - chip->bank[bank->bank_number].write = nrf51_code_flash_write; + case NRF5_FLASH_BASE: + chip->bank[bank->bank_number].write = nrf5_code_flash_write; break; - case NRF51_UICR_BASE: - chip->bank[bank->bank_number].write = nrf51_uicr_flash_write; + case NRF5_UICR_BASE: + chip->bank[bank->bank_number].write = nrf5_uicr_flash_write; break; } @@ -1161,27 +950,27 @@ FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) return ERROR_OK; } -COMMAND_HANDLER(nrf51_handle_mass_erase_command) +COMMAND_HANDLER(nrf5_handle_mass_erase_command) { int res; struct flash_bank *bank = NULL; struct target *target = get_current_target(CMD_CTX); - res = get_flash_bank_by_addr(target, NRF51_FLASH_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank != NULL); - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; uint32_t ppfc; - res = target_read_u32(target, NRF51_FICR_PPFC, + res = target_read_u32(target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -1194,23 +983,23 @@ COMMAND_HANDLER(nrf51_handle_mass_erase_command) return ERROR_FAIL; } - res = nrf51_erase_all(chip); + res = nrf5_erase_all(chip); if (res != ERROR_OK) { LOG_ERROR("Failed to erase the chip"); - nrf51_protect_check(bank); + nrf5_protect_check(bank); return res; } for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; - res = nrf51_protect_check(bank); + res = nrf5_protect_check(bank); if (res != ERROR_OK) { LOG_ERROR("Failed to check chip's write protection"); return res; } - res = get_flash_bank_by_addr(target, NRF51_UICR_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank); if (res != ERROR_OK) return res; @@ -1219,13 +1008,13 @@ COMMAND_HANDLER(nrf51_handle_mass_erase_command) return ERROR_OK; } -static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) +static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -1233,45 +1022,45 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) const uint32_t address; uint32_t value; } ficr[] = { - { .address = NRF51_FICR_CODEPAGESIZE }, - { .address = NRF51_FICR_CODESIZE }, - { .address = NRF51_FICR_CLENR0 }, - { .address = NRF51_FICR_PPFC }, - { .address = NRF51_FICR_NUMRAMBLOCK }, - { .address = NRF51_FICR_SIZERAMBLOCK0 }, - { .address = NRF51_FICR_SIZERAMBLOCK1 }, - { .address = NRF51_FICR_SIZERAMBLOCK2 }, - { .address = NRF51_FICR_SIZERAMBLOCK3 }, - { .address = NRF51_FICR_CONFIGID }, - { .address = NRF51_FICR_DEVICEID0 }, - { .address = NRF51_FICR_DEVICEID1 }, - { .address = NRF51_FICR_ER0 }, - { .address = NRF51_FICR_ER1 }, - { .address = NRF51_FICR_ER2 }, - { .address = NRF51_FICR_ER3 }, - { .address = NRF51_FICR_IR0 }, - { .address = NRF51_FICR_IR1 }, - { .address = NRF51_FICR_IR2 }, - { .address = NRF51_FICR_IR3 }, - { .address = NRF51_FICR_DEVICEADDRTYPE }, - { .address = NRF51_FICR_DEVICEADDR0 }, - { .address = NRF51_FICR_DEVICEADDR1 }, - { .address = NRF51_FICR_OVERRIDEN }, - { .address = NRF51_FICR_NRF_1MBIT0 }, - { .address = NRF51_FICR_NRF_1MBIT1 }, - { .address = NRF51_FICR_NRF_1MBIT2 }, - { .address = NRF51_FICR_NRF_1MBIT3 }, - { .address = NRF51_FICR_NRF_1MBIT4 }, - { .address = NRF51_FICR_BLE_1MBIT0 }, - { .address = NRF51_FICR_BLE_1MBIT1 }, - { .address = NRF51_FICR_BLE_1MBIT2 }, - { .address = NRF51_FICR_BLE_1MBIT3 }, - { .address = NRF51_FICR_BLE_1MBIT4 }, + { .address = NRF5_FICR_CODEPAGESIZE }, + { .address = NRF5_FICR_CODESIZE }, + { .address = NRF5_FICR_CLENR0 }, + { .address = NRF5_FICR_PPFC }, + { .address = NRF5_FICR_NUMRAMBLOCK }, + { .address = NRF5_FICR_SIZERAMBLOCK0 }, + { .address = NRF5_FICR_SIZERAMBLOCK1 }, + { .address = NRF5_FICR_SIZERAMBLOCK2 }, + { .address = NRF5_FICR_SIZERAMBLOCK3 }, + { .address = NRF5_FICR_CONFIGID }, + { .address = NRF5_FICR_DEVICEID0 }, + { .address = NRF5_FICR_DEVICEID1 }, + { .address = NRF5_FICR_ER0 }, + { .address = NRF5_FICR_ER1 }, + { .address = NRF5_FICR_ER2 }, + { .address = NRF5_FICR_ER3 }, + { .address = NRF5_FICR_IR0 }, + { .address = NRF5_FICR_IR1 }, + { .address = NRF5_FICR_IR2 }, + { .address = NRF5_FICR_IR3 }, + { .address = NRF5_FICR_DEVICEADDRTYPE }, + { .address = NRF5_FICR_DEVICEADDR0 }, + { .address = NRF5_FICR_DEVICEADDR1 }, + { .address = NRF5_FICR_OVERRIDEN }, + { .address = NRF5_FICR_NRF_1MBIT0 }, + { .address = NRF5_FICR_NRF_1MBIT1 }, + { .address = NRF5_FICR_NRF_1MBIT2 }, + { .address = NRF5_FICR_NRF_1MBIT3 }, + { .address = NRF5_FICR_NRF_1MBIT4 }, + { .address = NRF5_FICR_BLE_1MBIT0 }, + { .address = NRF5_FICR_BLE_1MBIT1 }, + { .address = NRF5_FICR_BLE_1MBIT2 }, + { .address = NRF5_FICR_BLE_1MBIT3 }, + { .address = NRF5_FICR_BLE_1MBIT4 }, }, uicr[] = { - { .address = NRF51_UICR_CLENR0, }, - { .address = NRF51_UICR_RBPCONF }, - { .address = NRF51_UICR_XTALFREQ }, - { .address = NRF51_UICR_FWID }, + { .address = NRF5_UICR_CLENR0, }, + { .address = NRF5_UICR_RBPCONF }, + { .address = NRF5_UICR_XTALFREQ }, + { .address = NRF5_UICR_FWID }, }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { @@ -1343,38 +1132,62 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -static const struct command_registration nrf51_exec_command_handlers[] = { +static const struct command_registration nrf5_exec_command_handlers[] = { { .name = "mass_erase", - .handler = nrf51_handle_mass_erase_command, + .handler = nrf5_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase all flash contents of the chip.", }, COMMAND_REGISTRATION_DONE }; -static const struct command_registration nrf51_command_handlers[] = { +static const struct command_registration nrf5_command_handlers[] = { + { + .name = "nrf5", + .mode = COMMAND_ANY, + .help = "nrf5 flash command group", + .usage = "", + .chain = nrf5_exec_command_handlers, + }, { .name = "nrf51", .mode = COMMAND_ANY, .help = "nrf51 flash command group", .usage = "", - .chain = nrf51_exec_command_handlers, + .chain = nrf5_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; +struct flash_driver nrf5_flash = { + .name = "nrf5", + .commands = nrf5_command_handlers, + .flash_bank_command = nrf5_flash_bank_command, + .info = nrf5_info, + .erase = nrf5_erase, + .protect = nrf5_protect, + .write = nrf5_write, + .read = default_flash_read, + .probe = nrf5_probe, + .auto_probe = nrf5_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = nrf5_protect_check, +}; + +/* We need to retain the flash-driver name as well as the commands + * for backwards compatability */ struct flash_driver nrf51_flash = { .name = "nrf51", - .commands = nrf51_command_handlers, - .flash_bank_command = nrf51_flash_bank_command, - .info = nrf51_info, - .erase = nrf51_erase, - .protect = nrf51_protect, - .write = nrf51_write, + .commands = nrf5_command_handlers, + .flash_bank_command = nrf5_flash_bank_command, + .info = nrf5_info, + .erase = nrf5_erase, + .protect = nrf5_protect, + .write = nrf5_write, .read = default_flash_read, - .probe = nrf51_probe, - .auto_probe = nrf51_auto_probe, + .probe = nrf5_probe, + .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, - .protect_check = nrf51_protect_check, + .protect_check = nrf5_protect_check, }; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index c8239d2..ac5ef6b 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -31,53 +31,55 @@ * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { /* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */ - FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), - FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), - FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), - FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), - FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), - FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), - FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), - FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), - FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), - FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), - FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), - FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), - FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), - FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), - FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), - FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), - FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), - FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), - FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), - FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), - FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), - FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), - FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), - FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), - FLASH_ID("issi is25lp128", 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000), - FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), - FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), - FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), - FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), - FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), - FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), - FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), - FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) + FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), + FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), + FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), + FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), + FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), + FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), + FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), + FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), + FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), + FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), + FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), + FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), + FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), + FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), + FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), + FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), + FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), + FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), + FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), + FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), + FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), + FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), + FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), + FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), + FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), + FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), + FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), + FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), + FLASH_ID("micron n25q256 3v", 0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000), + FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), + FLASH_ID("issi is25lp128", 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000), + FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), + FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), + FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), + FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), + FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), + FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), + FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), + FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) }; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 65cb212..b0992b4 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -143,9 +143,8 @@ #define FLASH_PSIZE_16 (1 << 8) #define FLASH_PSIZE_32 (2 << 8) #define FLASH_PSIZE_64 (3 << 8) -/* The sector number encoding is not straight binary for dual bank flash. - * Warning: evaluates the argument multiple times */ -#define FLASH_SNB(a) ((((a) >= 12) ? 0x10 | ((a) - 12) : (a)) << 3) +/* The sector number encoding is not straight binary for dual bank flash. */ +#define FLASH_SNB(a) ((a) << 3) #define FLASH_LOCK (1 << 31) /* FLASH_SR register bits */ @@ -489,6 +488,7 @@ static int stm32x_protect_check(struct flash_bank *bank) static int stm32x_erase(struct flash_bank *bank, int first, int last) { + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; int i; @@ -516,8 +516,14 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ for (i = first; i <= last; i++) { + int snb; + if (stm32x_info->has_large_mem && i >= 12) + snb = (i - 12) | 0x10; + else + snb = i; + retval = target_write_u32(target, - stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(i) | FLASH_STRT); + stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(snb) | FLASH_STRT); if (retval != ERROR_OK) return retval; @@ -1047,7 +1053,8 @@ static int stm32x_probe(struct flash_bank *bank) if (device_id == 0x451) { for (i = 0; i < num_prot_blocks; i++) { bank->prot_blocks[i].offset = bank->sectors[i << 1].offset; - bank->prot_blocks[i].size = bank->sectors[i << 1].size << 1; + bank->prot_blocks[i].size = bank->sectors[i << 1].size + + bank->sectors[(i << 1) + 1].size; } } } else { diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c new file mode 100644 index 0000000..01e6f06 --- /dev/null +++ b/src/flash/nor/stm32h7x.c @@ -0,0 +1,1183 @@ +/*************************************************************************** + * Copyright (C) 2017 by STMicroelectronics * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include <target/armv7m.h> + + +/* Erase time can be as high as 1000ms, 10x this and it's toast... */ +#define FLASH_ERASE_TIMEOUT 10000 +#define FLASH_WRITE_TIMEOUT 5 + +/* RM 433 */ +/* Same Flash registers for both banks, */ +/* access depends on Flash Base address */ +#define FLASH_ACR 0x00 +#define FLASH_KEYR 0x04 +#define FLASH_OPTKEYR 0x08 +#define FLASH_CR 0x0C +#define FLASH_SR 0x10 +#define FLASH_CCR 0x14 +#define FLASH_OPTCR 0x18 +#define FLASH_OPTCUR 0x1C +#define FLASH_OPTPRG 0x20 +#define FLASH_OPTCCR 0x24 +#define FLASH_WPSNCUR 0x38 +#define FLASH_WPSNPRG 0x3C + + +/* FLASH_CR register bits */ +#define FLASH_LOCK (1 << 0) +#define FLASH_PG (1 << 1) +#define FLASH_SER (1 << 2) +#define FLASH_BER_CMD (1 << 3) +#define FLASH_PSIZE_8 (0 << 4) +#define FLASH_PSIZE_16 (1 << 4) +#define FLASH_PSIZE_32 (2 << 4) +#define FLASH_PSIZE_64 (3 << 4) +#define FLASH_FW (1 << 6) +#define FLASH_START (1 << 7) + +#define FLASH_SNB(a) ((a) << 8) + +/* FLASH_SR register bits */ +#define FLASH_BSY (1 << 0) /* Operation in progress */ +#define FLASH_WRPERR (1 << 17) /* Write protection error */ +#define FLASH_PGSERR (1 << 18) /* Programming sequence error */ +#define FLASH_STRBERR (1 << 19) /* Strobe error */ +#define FLASH_INCERR (1 << 21) /* Increment error */ +#define FLASH_OPERR (1 << 22) /* Operation error */ +#define FLASH_RDPERR (1 << 23) /* Read Protection error */ +#define FLASH_RDSERR (1 << 24) /* Secure Protection error */ +#define FLASH_SNECCERR (1 << 25) /* Single ECC error */ +#define FLASH_DBECCERR (1 << 26) /* Double ECC error */ + +#define FLASH_ERROR (FLASH_WRPERR | FLASH_PGSERR | FLASH_STRBERR | FLASH_INCERR | FLASH_OPERR | \ + FLASH_RDPERR | FLASH_RDSERR | FLASH_SNECCERR | FLASH_DBECCERR) + +/* FLASH_OPTCR register bits */ +#define OPT_LOCK (1 << 0) +#define OPT_START (1 << 1) + +/* FLASH_OPTCUR bit definitions (reading) */ +#define IWDG1_HW (1 << 4) + +/* register unlock keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* option register unlock key */ +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define DBGMCU_IDCODE_REGISTER 0x5C001000 +#define FLASH_BANK0_ADDRESS 0x08000000 +#define FLASH_BANK1_ADDRESS 0x08100000 +#define FLASH_REG_BASE_B0 0x52002000 +#define FLASH_REG_BASE_B1 0x52002100 +#define FLASH_SIZE_ADDRESS 0x1FF1E880 +#define FLASH_BLOCK_SIZE 32 + +struct stm32h7x_rev { + uint16_t rev; + const char *str; +}; + +struct stm32x_options { + uint8_t RDP; + uint32_t protection; /* bank1 WRP */ + uint32_t protection2; /* bank2 WRP */ + uint8_t user_options; + uint8_t user2_options; + uint8_t user3_options; + uint8_t independent_watchdog_selection; +}; + +struct stm32h7x_part_info { + uint16_t id; + const char *device_str; + const struct stm32h7x_rev *revs; + size_t num_revs; + unsigned int page_size; + unsigned int pages_per_sector; + uint16_t max_flash_size_kb; + uint8_t has_dual_bank; + uint16_t first_bank_size_kb; /* Used when has_dual_bank is true */ + uint32_t flash_base; /* Flash controller registers location */ + uint32_t fsize_base; /* Location of FSIZE register */ +}; + +struct stm32h7x_flash_bank { + int probed; + uint32_t idcode; + uint32_t user_bank_size; + uint32_t flash_base; /* Address of flash reg controller */ + struct stm32x_options option_bytes; + const struct stm32h7x_part_info *part_info; +}; + +static const struct stm32h7x_rev stm32_450_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, +}; + +static const struct stm32h7x_part_info stm32h7x_parts[] = { + { + .id = 0x450, + .revs = stm32_450_revs, + .num_revs = ARRAY_SIZE(stm32_450_revs), + .device_str = "STM32H7xx 2M", + .page_size = 128, /* 128 KB */ + .max_flash_size_kb = 2048, + .first_bank_size_kb = 1024, + .has_dual_bank = 1, + .flash_base = FLASH_REG_BASE_B0, + .fsize_base = FLASH_SIZE_ADDRESS, + }, +}; + +static int stm32x_unlock_reg(struct flash_bank *bank); +static int stm32x_lock_reg(struct flash_bank *bank); +static int stm32x_probe(struct flash_bank *bank); + +/* flash bank stm32x <base> <size> 0 0 <target#> */ + +FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) +{ + struct stm32h7x_flash_bank *stm32x_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); + bank->driver_priv = stm32x_info; + + stm32x_info->probed = 0; + stm32x_info->user_bank_size = bank->size; + + return ERROR_OK; +} + +static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + return reg + stm32x_info->flash_base; +} + +static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) +{ + struct target *target = bank->target; + return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status); +} + +static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + uint32_t status; + int retval; + + /* wait for busy to clear */ + for (;;) { + retval = stm32x_get_flash_status(bank, &status); + if (retval != ERROR_OK) { + LOG_INFO("wait_status_busy, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); + return retval; + } + + if ((status & FLASH_BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + return ERROR_FAIL; + } + alive_sleep(1); + } + + if (status & FLASH_WRPERR) { + LOG_INFO("wait_status_busy, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); + retval = ERROR_FAIL; + } + + /* Clear error + EOP flags but report errors */ + if (status & FLASH_ERROR) { + /* If this operation fails, we ignore it and report the original retval */ + target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status); + } + return retval; +} + +static int stm32x_unlock_reg(struct flash_bank *bank) +{ + uint32_t ctrl; + struct target *target = bank->target; + + /* first check if not already unlocked + * otherwise writing on FLASH_KEYR will fail + */ + int retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & FLASH_LOCK) == 0) + return ERROR_OK; + + /* unlock flash registers for bank */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_LOCK) { + LOG_ERROR("flash not unlocked STM32_FLASH_CRx: %" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + return ERROR_OK; +} + +static int stm32x_unlock_option_reg(struct flash_bank *bank) +{ + uint32_t ctrl; + struct target *target = bank->target; + + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & OPT_LOCK) == 0) + return ERROR_OK; + + /* unlock option registers */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & OPT_LOCK) { + LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + + return ERROR_OK; +} + +static int stm32x_lock_reg(struct flash_bank *bank) +{ + struct target *target = bank->target; + + /* Lock bank reg */ + int retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_read_options(struct flash_bank *bank) +{ + uint32_t optiondata; + struct stm32h7x_flash_bank *stm32x_info = NULL; + struct target *target = bank->target; + + stm32x_info = bank->driver_priv; + + /* read current option bytes */ + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + + /* decode option data */ + stm32x_info->option_bytes.user_options = optiondata & 0xfc; + stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; + stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff; + stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0x83; + + if (optiondata & IWDG1_HW) + stm32x_info->option_bytes.independent_watchdog_selection = 1; + else + stm32x_info->option_bytes.independent_watchdog_selection = 0; + + if (stm32x_info->option_bytes.RDP != 0xAA) + LOG_INFO("Device Security Bit Set"); + + /* read current WPSN option bytes */ + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + stm32x_info->option_bytes.protection = optiondata & 0xff; + + /* read current WPSN2 option bytes */ + retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + stm32x_info->option_bytes.protection2 = optiondata & 0xff; + + return ERROR_OK; +} + +static int stm32x_write_options(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = NULL; + struct target *target = bank->target; + uint32_t optiondata; + + stm32x_info = bank->driver_priv; + + int retval = stm32x_unlock_option_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* rebuild option data */ + optiondata = stm32x_info->option_bytes.user_options; + optiondata |= (stm32x_info->option_bytes.RDP << 8); + optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16; + optiondata |= (stm32x_info->option_bytes.user3_options & 0x83) << 24; + + if (stm32x_info->option_bytes.independent_watchdog_selection) + optiondata |= IWDG1_HW; + else + optiondata &= ~IWDG1_HW; + + /* program options */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = stm32x_info->option_bytes.protection & 0xff; + /* Program protection WPSNPRG */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = stm32x_info->option_bytes.protection2 & 0xff; + /* Program protection WPSNPRG2 */ + retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = 0x40000000; + /* Remove OPT error flag before programming */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata); + if (retval != ERROR_OK) + return retval; + + /* start programming cycle */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START); + if (retval != ERROR_OK) + return retval; + + /* wait for completion */ + int timeout = FLASH_ERASE_TIMEOUT; + for (;;) { + uint32_t status; + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status); + if (retval != ERROR_OK) { + LOG_INFO("stm32x_write_options: wait_status_busy : error"); + return retval; + } + if ((status & FLASH_BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + return ERROR_FAIL; + } + alive_sleep(1); + } + + /* relock option registers */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_protect_check(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + /* read 'write protection' settings */ + int retval = stm32x_read_options(bank); + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read option bytes"); + return retval; + } + + for (int i = 0; i < bank->num_sectors; i++) { + if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { + if (stm32x_info->option_bytes.protection & (1 << i)) + bank->sectors[i].is_protected = 0; + else + bank->sectors[i].is_protected = 1; + } else { + if (stm32x_info->option_bytes.protection2 & (1 << i)) + bank->sectors[i].is_protected = 0; + else + bank->sectors[i].is_protected = 1; + } + } + return ERROR_OK; +} + +static int stm32x_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + int retval; + + assert(first < bank->num_sectors); + assert(last < bank->num_sectors); + + if (bank->target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* + Sector Erase + To erase a sector, follow the procedure below: + 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the + FLASH_SR register + 2. Set the SER bit and select the sector + you wish to erase (SNB) in the FLASH_CR register + 3. Set the STRT bit in the FLASH_CR register + 4. Wait for the BSY bit to be cleared + */ + for (int i = first; i <= last; i++) { + LOG_DEBUG("erase sector %d", i); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64); + if (retval != ERROR_OK) { + LOG_ERROR("Error erase sector %d", i); + return retval; + } + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START); + if (retval != ERROR_OK) { + LOG_ERROR("Error erase sector %d", i); + return retval; + } + retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + + if (retval != ERROR_OK) { + LOG_ERROR("erase time-out error sector %d", i); + return retval; + } + bank->sectors[i].is_erased = 1; + } + + retval = stm32x_lock_reg(bank); + if (retval != ERROR_OK) { + LOG_ERROR("error during the lock of flash"); + return retval; + } + + return ERROR_OK; +} + +static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + /* read protection settings */ + int retval = stm32x_read_options(bank); + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read option bytes"); + return retval; + } + + for (int i = first; i <= last; i++) { + if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { + if (set) + stm32x_info->option_bytes.protection &= ~(1 << i); + else + stm32x_info->option_bytes.protection |= (1 << i); + } else { + if (set) + stm32x_info->option_bytes.protection2 &= ~(1 << i); + else + stm32x_info->option_bytes.protection2 |= (1 << i); + } + } + + LOG_INFO("stm32x_protect, option_bytes written WRP1 0x%x , WRP2 0x%x", + (stm32x_info->option_bytes.protection & 0xff), (stm32x_info->option_bytes.protection2 & 0xff)); + + retval = stm32x_write_options(bank); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + /* + * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get + * "corrupted fifo read" pointer in target_run_flash_async_algorithm() + */ + uint32_t data_size = 512 * FLASH_BLOCK_SIZE; /* 16384 */ + uint32_t buffer_size = 8 + data_size; + struct working_area *write_algorithm; + struct working_area *source; + uint32_t address = bank->base + offset; + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int retval = ERROR_OK; + + /* see contrib/loaders/flash/smt32h7x.S for src */ + static const uint8_t stm32x_flash_write_code[] = { + /* <code>: */ + 0x45, 0x68, /* ldr r5, [r0, #4] */ + /* <wait_fifo>: */ + 0x06, 0x68, /* ldr r6, [r0, #0] */ + 0x26, 0xb3, /* cbz r6, <exit> */ + 0x76, 0x1b, /* subs r6, r6, r5 */ + 0x42, 0xbf, /* ittt mi */ + 0x76, 0x18, /* addmi r6, r6, r1 */ + 0x36, 0x1a, /* submi r6, r6, r0 */ + 0x08, 0x3e, /* submi r6, #8 */ + 0x20, 0x2e, /* cmp r6, #32 */ + 0xf6, 0xd3, /* bcc.n <wait_fifo> */ + 0x4f, 0xf0, 0x32, 0x06, /* mov.w r6, #STM32_PROG */ + 0xe6, 0x60, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ + 0x4f, 0xf0, 0x08, 0x07, /* mov.w r7, #8 */ + /* <write_flash>: */ + 0x55, 0xf8, 0x04, 0x6b, /* ldr.w r6, [r5], #4 */ + 0x42, 0xf8, 0x04, 0x6b, /* str.w r6, [r2], #4 */ + 0xbf, 0xf3, 0x4f, 0x8f, /* dsb sy */ + 0x8d, 0x42, /* cmp r5, r1 */ + 0x28, 0xbf, /* it cs */ + 0x00, 0xf1, 0x08, 0x05, /* addcs.w r5, r0, #8 */ + 0x01, 0x3f, /* subs r7, #1 */ + 0xf3, 0xd1, /* bne.n <write_flash> */ + /* <busy>: */ + 0x26, 0x69, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ + 0x16, 0xf0, 0x01, 0x0f, /* tst.w r6, #STM32_SR_BUSY_MASK */ + 0xfb, 0xd1, /* bne.n <busy> */ + 0x05, 0x4f, /* ldr r7, [pc, #20] ; (<stm32_sr_error_mask>) */ + 0x3e, 0x42, /* tst r6, r7 */ + 0x03, 0xd1, /* bne.n <error> */ + 0x45, 0x60, /* str r5, [r0, #4] */ + 0x01, 0x3b, /* subs r3, #1 */ + 0xdb, 0xd1, /* bne.n <wait_fifo> */ + 0x01, 0xe0, /* b.n <exit> */ + /* <error>: */ + 0x00, 0x27, /* movs r7, #0 */ + 0x47, 0x60, /* str r7, [r0, #4] */ + /* <exit>: */ + 0x30, 0x46, /* mov r0, r6 */ + 0x00, 0xbe, /* bkpt 0x0000 */ + /* <stm32_sr_error_mask>: */ + 0x00, 0x00, 0xee, 0x03 /* .word 0x03ee0000 ; (STM32_SR_ERROR_MASK) */ + }; + + if (target_alloc_working_area(target, sizeof(stm32x_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; + } + + retval = target_write_buffer(target, write_algorithm->address, + sizeof(stm32x_flash_write_code), + stm32x_flash_write_code); + if (retval != ERROR_OK) + return retval; + + /* memory buffer */ + while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + data_size /= 2; + buffer_size = 8 + data_size; + if (data_size <= 256) { + /* we already allocated the writing code, but failed to get a + * buffer, free the algorithm */ + target_free_working_area(target, write_algorithm); + + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (word-256 bits) */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash reg base */ + + buf_set_u32(reg_params[0].value, 0, 32, source->address); + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + buf_set_u32(reg_params[2].value, 0, 32, address); + buf_set_u32(reg_params[3].value, 0, 32, count); + buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->flash_base); + + retval = target_run_flash_async_algorithm(target, + buffer, + count, + FLASH_BLOCK_SIZE, + 0, NULL, + 5, reg_params, + source->address, source->size, + write_algorithm->address, 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_INFO("error executing stm32h7x flash write algorithm"); + + uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); + + if (flash_sr & FLASH_WRPERR) + LOG_ERROR("flash memory write protected"); + + if ((flash_sr & FLASH_ERROR) != 0) { + LOG_ERROR("flash write failed, FLASH_SR = %08" PRIx32, flash_sr); + /* Clear error + EOP flags but report errors */ + target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), flash_sr); + retval = ERROR_FAIL; + } + } + + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + return retval; +} + +static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t address = bank->base + offset; + int retval, retval2; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset % FLASH_BLOCK_SIZE) { + LOG_WARNING("offset 0x%" PRIx32 " breaks required 32-byte alignment", offset); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE; + uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE; + + /* multiple words (32-bytes) to be programmed in block */ + if (blocks_remaining) { + retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); + if (retval != ERROR_OK) { + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* if block write failed (no sufficient working area), + * we use normal (slow) dword accesses */ + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); + } + } else { + buffer += blocks_remaining * FLASH_BLOCK_SIZE; + address += blocks_remaining * FLASH_BLOCK_SIZE; + blocks_remaining = 0; + } + if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) + goto flash_lock; + } + + /* + Standard programming + The Flash memory programming sequence is as follows: + 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the + FLASH_SR register. + 2. Set the PG bit in the FLASH_CR register + 3. 8 x Word access (or Force Write FW) + 4. Wait for the BSY bit to be cleared + */ + while (blocks_remaining > 0) { + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + if (retval != ERROR_OK) + goto flash_lock; + + retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer); + if (retval != ERROR_OK) + goto flash_lock; + + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto flash_lock; + + buffer += FLASH_BLOCK_SIZE; + address += FLASH_BLOCK_SIZE; + blocks_remaining--; + } + + if (bytes_remaining) { + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + if (retval != ERROR_OK) + goto flash_lock; + + retval = target_write_buffer(target, address, bytes_remaining, buffer); + if (retval != ERROR_OK) + goto flash_lock; + + /* Force Write buffer of FLASH_BLOCK_SIZE = 32 bytes */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64 | FLASH_FW); + if (retval != ERROR_OK) + goto flash_lock; + + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto flash_lock; + } + +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) + LOG_ERROR("error during the lock of flash"); + + if (retval == ERROR_OK) + retval = retval2; + + return retval; +} + +static void setup_sector(struct flash_bank *bank, int start, int num, int size) +{ + for (int i = start; i < (start + num) ; i++) { + assert(i < bank->num_sectors); + bank->sectors[i].offset = bank->size; + bank->sectors[i].size = size; + bank->size += bank->sectors[i].size; + } +} + +static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) +{ + /* read stm32 device id register */ + int retval = target_read_u32(bank->target, DBGMCU_IDCODE_REGISTER, id); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +} + +static int stm32x_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int i; + uint16_t flash_size_in_kb; + uint32_t device_id; + uint32_t base_address = FLASH_BANK0_ADDRESS; + uint32_t second_bank_base; + + stm32x_info->probed = 0; + stm32x_info->part_info = NULL; + + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("device id = 0x%08" PRIx32 "", stm32x_info->idcode); + + device_id = stm32x_info->idcode & 0xfff; + + for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7x_parts); n++) { + if (device_id == stm32h7x_parts[n].id) + stm32x_info->part_info = &stm32h7x_parts[n]; + } + if (!stm32x_info->part_info) { + LOG_WARNING("Cannot identify target as a STM32H7xx family."); + return ERROR_FAIL; + } else { + LOG_INFO("Device: %s", stm32x_info->part_info->device_str); + } + + /* update the address of controller from data base */ + stm32x_info->flash_base = stm32x_info->part_info->flash_base; + + /* get flash size from target */ + retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb); + if (retval != ERROR_OK) { + /* read error when device has invalid value, set max flash size */ + flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + } else + LOG_INFO("flash size probed value %d", flash_size_in_kb); + + /* Lower flash size devices are single bank */ + if (stm32x_info->part_info->has_dual_bank && (flash_size_in_kb > stm32x_info->part_info->first_bank_size_kb)) { + /* Use the configured base address to determine if this is the first or second flash bank. + * Verify that the base address is reasonably correct and determine the flash bank size + */ + second_bank_base = base_address + stm32x_info->part_info->first_bank_size_kb * 1024; + if (bank->base == second_bank_base) { + /* This is the second bank */ + base_address = second_bank_base; + flash_size_in_kb = flash_size_in_kb - stm32x_info->part_info->first_bank_size_kb; + /* bank1 also uses a register offset */ + stm32x_info->flash_base = FLASH_REG_BASE_B1; + } else if (bank->base == base_address) { + /* This is the first bank */ + flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb; + } else { + LOG_WARNING("STM32H flash bank base address config is incorrect." + " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, + bank->base, base_address, second_bank_base); + return ERROR_FAIL; + } + LOG_INFO("STM32H flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32, + bank->bank_number, flash_size_in_kb, base_address); + } else { + LOG_INFO("STM32H flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address); + } + + /* if the user sets the size manually then ignore the probed value + * this allows us to work around devices that have an invalid flash size register value */ + if (stm32x_info->user_bank_size) { + LOG_INFO("ignoring flash probed value, using configured bank size"); + flash_size_in_kb = stm32x_info->user_bank_size / 1024; + } else if (flash_size_in_kb == 0xffff) { + /* die flash size */ + flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + } + + /* did we assign flash size? */ + assert(flash_size_in_kb != 0xffff); + + /* calculate numbers of pages */ + int num_pages = flash_size_in_kb / stm32x_info->part_info->page_size; + + /* check that calculation result makes sense */ + assert(num_pages > 0); + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + bank->base = base_address; + bank->num_sectors = num_pages; + bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + if (bank->sectors == NULL) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } + bank->size = 0; + + /* fixed memory */ + setup_sector(bank, 0, num_pages, stm32x_info->part_info->page_size * 1024); + + for (i = 0; i < num_pages; i++) { + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + stm32x_info->probed = 1; + return ERROR_OK; +} + +static int stm32x_auto_probe(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + if (stm32x_info->probed) + return ERROR_OK; + + return stm32x_probe(bank); +} + +/* This method must return a string displaying information about the bank */ +static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + const struct stm32h7x_part_info *info = stm32x_info->part_info; + + if (!stm32x_info->probed) { + int retval = stm32x_probe(bank); + if (retval != ERROR_OK) { + snprintf(buf, buf_size, "Unable to find bank information."); + return retval; + } + } + + if (info) { + const char *rev_str = NULL; + uint16_t rev_id = stm32x_info->idcode >> 16; + + for (unsigned int i = 0; i < info->num_revs; i++) + if (rev_id == info->revs[i].rev) + rev_str = info->revs[i].str; + + if (rev_str != NULL) { + snprintf(buf, buf_size, "%s - Rev: %s", + stm32x_info->part_info->device_str, rev_str); + } else { + snprintf(buf, buf_size, + "%s - Rev: unknown (0x%04x)", + stm32x_info->part_info->device_str, rev_id); + } + } else { + snprintf(buf, buf_size, "Cannot identify target as a STM32H7x"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_lock_command) +{ + struct target *target = NULL; + struct stm32h7x_flash_bank *stm32x_info = NULL; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + stm32x_info = bank->driver_priv; + target = bank->target; + + /* if we have a dual flash bank device then + * we need to perform option byte lock on bank0 only */ + if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Lock Operation must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32x_read_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to read options", + bank->driver->name); + return ERROR_OK; + } + /* set readout protection */ + stm32x_info->option_bytes.RDP = 0; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to lock device", + bank->driver->name); + return ERROR_OK; + } + command_print(CMD_CTX, "%s locked", bank->driver->name); + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_unlock_command) +{ + struct target *target = NULL; + struct stm32h7x_flash_bank *stm32x_info = NULL; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + stm32x_info = bank->driver_priv; + target = bank->target; + + /* if we have a dual flash bank device then + * we need to perform option byte unlock on bank0 only */ + if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Unlock Operation must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32x_read_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to read options", bank->driver->name); + return ERROR_OK; + } + + /* clear readout protection option byte + * this will also force a device unlock if set */ + stm32x_info->option_bytes.RDP = 0xAA; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); + return ERROR_OK; + } + command_print(CMD_CTX, "%s unlocked.\n", bank->driver->name); + + return ERROR_OK; +} + +static int stm32x_mass_erase(struct flash_bank *bank) +{ + int retval; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* mass erase flash memory bank */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER_CMD | FLASH_PSIZE_64); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_BER_CMD | FLASH_PSIZE_64 | FLASH_START); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_wait_status_busy(bank, 30000); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_lock_reg(bank); + if (retval != ERROR_OK) { + LOG_ERROR("error during the lock of flash"); + return retval; + } + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_mass_erase_command) +{ + int i; + + if (CMD_ARGC < 1) { + command_print(CMD_CTX, "stm32h7x mass_erase <bank>"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + retval = stm32x_mass_erase(bank); + if (retval == ERROR_OK) { + /* set all sectors as erased */ + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = 1; + + command_print(CMD_CTX, "stm32h7x mass erase complete"); + } else { + command_print(CMD_CTX, "stm32h7x mass erase failed"); + } + + return retval; +} + +static const struct command_registration stm32x_exec_command_handlers[] = { + { + .name = "lock", + .handler = stm32x_handle_lock_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Lock entire flash device.", + }, + { + .name = "unlock", + .handler = stm32x_handle_unlock_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Unlock entire protected flash device.", + }, + { + .name = "mass_erase", + .handler = stm32x_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Erase entire flash device.", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration stm32x_command_handlers[] = { + { + .name = "stm32h7x", + .mode = COMMAND_ANY, + .help = "stm32h7x flash command group", + .usage = "", + .chain = stm32x_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver stm32h7x_flash = { + .name = "stm32h7x", + .commands = stm32x_command_handlers, + .flash_bank_command = stm32x_flash_bank_command, + .erase = stm32x_erase, + .protect = stm32x_protect, + .write = stm32x_write, + .read = default_flash_read, + .probe = stm32x_probe, + .auto_probe = stm32x_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = stm32x_protect_check, + .info = stm32x_get_info, +}; diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 0c2fddc..fdfaad4 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -726,16 +726,13 @@ reset_pg_and_lock: static int stm32lx_read_id_code(struct target *target, uint32_t *id) { - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, id); - if (retval != ERROR_OK) - return retval; - - /* STM32L0 parts will have 0 there, try reading the L0's location for - * DBG_IDCODE in case this is an L0 part. */ - if (*id == 0) + struct armv7m_common *armv7m = target_to_armv7m(target); + int retval; + if (armv7m->arm.is_armv6m == true) retval = target_read_u32(target, DBGMCU_IDCODE_L0, id); - + else + /* read stm32 device id register */ + retval = target_read_u32(target, DBGMCU_IDCODE, id); return retval; } diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 02df46a..5677ef0 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -931,13 +931,13 @@ static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_ /* If OTP Write protection is enabled (User 2), list each * sector that has it enabled */ - char otp_str[8]; + char otp_str[14]; if (otp_enabled) { strcat(prot_str, "\nOTP Protection is enabled for sectors:\n"); for (int i = 0; i < bank->num_sectors; i++) { if (fb->write_prot_otp[i]) { snprintf(otp_str, sizeof(otp_str), "- %d\n", i); - strncat(prot_str, otp_str, ARRAY_SIZE(otp_str)); + strncat(prot_str, otp_str, sizeof(prot_str) - strlen(prot_str) - 1); } } } |