diff options
Diffstat (limited to 'src/flash')
47 files changed, 4404 insertions, 2013 deletions
diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index b9ac793..baef5d5 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -263,6 +263,7 @@ int nand_read_status(struct nand_device *nand, uint8_t *status) return ERROR_NAND_DEVICE_NOT_PROBED; /* Send read status command */ + /* FIXME: errors returned from nand->controller are mostly ignored! */ nand->controller->command(nand, NAND_CMD_STATUS); alive_sleep(1); @@ -301,7 +302,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout) int nand_probe(struct nand_device *nand) { uint8_t manufacturer_id, device_id; - uint8_t id_buff[6]; + uint8_t id_buff[6] = { 0 }; /* zero buff to silence false warning + * from clang static analyzer */ int retval; int i; @@ -392,19 +394,34 @@ int nand_probe(struct nand_device *nand) if (nand->device->page_size == 0 || nand->device->erase_size == 0) { if (nand->bus_width == 8) { - nand->controller->read_data(nand, id_buff + 3); - nand->controller->read_data(nand, id_buff + 4); - nand->controller->read_data(nand, id_buff + 5); + retval = nand->controller->read_data(nand, id_buff + 3); + if (retval != ERROR_OK) + return retval; + + retval = nand->controller->read_data(nand, id_buff + 4); + if (retval != ERROR_OK) + return retval; + + retval = nand->controller->read_data(nand, id_buff + 5); + if (retval != ERROR_OK) + return retval; + } else { uint16_t data_buf; - nand->controller->read_data(nand, &data_buf); + retval = nand->controller->read_data(nand, &data_buf); + if (retval != ERROR_OK) + return retval; id_buff[3] = data_buf; - nand->controller->read_data(nand, &data_buf); + retval = nand->controller->read_data(nand, &data_buf); + if (retval != ERROR_OK) + return retval; id_buff[4] = data_buf; - nand->controller->read_data(nand, &data_buf); + retval = nand->controller->read_data(nand, &data_buf); + if (retval != ERROR_OK) + return retval; id_buff[5] = data_buf >> 8; } } diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index 17e6f68..167b401 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -730,7 +730,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) goto fail; } - info = calloc(1, sizeof *info); + info = calloc(1, sizeof(*info)); if (info == NULL) goto fail; diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index 5fdc923..da141b7 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -685,7 +685,6 @@ static int do_data_output(struct nand_device *nand) case 2 << 2: LOG_DEBUG("main area readed with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } switch (ecc_status & 0x0003) { case 1: @@ -694,7 +693,6 @@ static int do_data_output(struct nand_device *nand) case 2: LOG_DEBUG("main area readed with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } } break; diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c index b541157..ee093c0 100644 --- a/src/flash/nand/mxc.c +++ b/src/flash/nand/mxc.c @@ -874,7 +874,6 @@ int ecc_status_v1(struct nand_device *nand) case 2 << 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } switch (ecc_status & 0x0003) { case 1: @@ -883,7 +882,6 @@ int ecc_status_v1(struct nand_device *nand) case 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } return ERROR_OK; } diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 34f91ce..b95b003 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -51,6 +51,8 @@ NOR_DRIVERS = \ %D%/psoc4.c \ %D%/psoc5lp.c \ %D%/psoc6.c \ + %D%/renesas_rpchf.c \ + %D%/sh_qspi.c \ %D%/sim3x.c \ %D%/spi.c \ %D%/stmsmi.c \ @@ -74,6 +76,7 @@ NOR_DRIVERS = \ NORHEADERS = \ %D%/core.h \ %D%/cc3220sf.h \ + %D%/bluenrg-x.h \ %D%/cc26xx.h \ %D%/cfi.h \ %D%/driver.h \ @@ -81,4 +84,5 @@ NORHEADERS = \ %D%/non_cfi.h \ %D%/ocl.h \ %D%/spi.h \ + %D%/stm32l4x.h \ %D%/msp432.h diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c index f468c89..7c5596d 100644 --- a/src/flash/nor/aducm360.c +++ b/src/flash/nor/aducm360.c @@ -434,10 +434,8 @@ static int aducm360_write_block(struct flash_bank *bank, switch (choice) { case 0: return aducm360_write_block_sync(bank, buffer, offset, count); - break; case 1: return aducm360_write_block_async(bank, buffer, offset, count); - break; default: LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index b1e3e72..b41b15c 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -253,8 +253,7 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) } - if (ambiqmicro_info->target_class < - (sizeof(ambiqmicroParts)/sizeof(ambiqmicroParts[0]))) + if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicroParts)) ambiqmicro_info->target_name = ambiqmicroParts[ambiqmicro_info->target_class].partname; else diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index 2457c15..c9ffa65 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -3068,7 +3068,6 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) ((unsigned int)(FLASH_BANK1_BASE_256K_AX)), ((unsigned int)(FLASH_BANK1_BASE_512K_AX))); return ERROR_FAIL; - break; /* at91sam3s and at91sam3n series only has bank 0*/ /* at91sam3u and at91sam3ax series has the same address for bank 0*/ @@ -3621,10 +3620,8 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; - break; case 0: goto showall; - break; case 1: who = -1; break; @@ -3653,7 +3650,8 @@ showall: } if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); - command_print(CMD, "sam3-gpnvm%u: %u", who, v); + if (r == ERROR_OK) + command_print(CMD, "sam3-gpnvm%u: %u", who, v); return r; } else { command_print(CMD, "sam3-gpnvm invalid GPNVM: %u", who); @@ -3707,7 +3705,6 @@ COMMAND_HANDLER(sam3_handle_slowclk_command) /* error */ command_print(CMD, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; - break; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(pChip->cfg.slow_freq / 1000), @@ -3729,7 +3726,7 @@ static const struct command_registration at91sam3_exec_command_handlers[] = { .name = "info", .handler = sam3_handle_info_command, .mode = COMMAND_EXEC, - .help = "Print information about the current at91sam3 chip" + .help = "Print information about the current at91sam3 chip " "and its flash configuration.", .usage = "", }, diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 621754c..5b56c42 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -2482,7 +2482,6 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) ((unsigned int)(bank->base)), ((unsigned int)(FLASH_BANK_BASE_S))); return ERROR_FAIL; - break; /* at91sam4s series only has bank 0*/ /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ @@ -3101,10 +3100,8 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; - break; case 0: goto showall; - break; case 1: who = -1; break; @@ -3188,7 +3185,6 @@ COMMAND_HANDLER(sam4_handle_slowclk_command) /* error */ command_print(CMD, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; - break; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(pChip->cfg.slow_freq / 1000), @@ -3210,7 +3206,7 @@ static const struct command_registration at91sam4_exec_command_handlers[] = { .name = "info", .handler = sam4_handle_info_command, .mode = COMMAND_EXEC, - .help = "Print information about the current at91sam4 chip" + .help = "Print information about the current at91sam4 chip " "and its flash configuration.", .usage = "", }, diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index d356398..d4bfe53 100644 --- a/src/flash/nor/at91sam4l.c +++ b/src/flash/nor/at91sam4l.c @@ -601,6 +601,7 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer, /* There's at least one aligned page to write out. */ if (count >= chip->page_size) { + assert(chip->page_size > 0); int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0); for (int i = 0; i < np; i++) { diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 232260b..039746c 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -711,8 +711,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) uint16_t page_size; uint16_t num_nvmbits; - char *target_name_t; - int bnk, sec; at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank)); @@ -753,9 +751,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) return ERROR_OK; } - target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char)); - strcpy(target_name_t, CMD_ARGV[7]); - /* calculate bank size */ bank_size = num_sectors * pages_per_sector * page_size; @@ -794,7 +789,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) at91sam7_info = t_bank->driver_priv; - at91sam7_info->target_name = target_name_t; + at91sam7_info->target_name = strdup(CMD_ARGV[7]); at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = ext_freq; at91sam7_info->num_nvmbits = num_nvmbits; diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index b6cff9a..6e89099 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -181,6 +181,23 @@ static const struct samd_part samd21_parts[] = { { 0x26, "SAMD21E16B", 64, 8 }, { 0x27, "SAMD21E15B", 32, 4 }, + /* SAMD21 D and L Variants (from Errata) + http://ww1.microchip.com/downloads/en/DeviceDoc/ + SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */ + { 0x55, "SAMD21E16BU", 64, 8 }, + { 0x56, "SAMD21E15BU", 32, 4 }, + { 0x57, "SAMD21G16L", 64, 8 }, + { 0x3E, "SAMD21E16L", 64, 8 }, + { 0x3F, "SAMD21E15L", 32, 4 }, + { 0x62, "SAMD21E16CU", 64, 8 }, + { 0x63, "SAMD21E15CU", 32, 4 }, + { 0x92, "SAMD21J17D", 128, 16 }, + { 0x93, "SAMD21G17D", 128, 16 }, + { 0x94, "SAMD21E17D", 128, 16 }, + { 0x95, "SAMD21E17DU", 128, 16 }, + { 0x96, "SAMD21G17L", 128, 16 }, + { 0x97, "SAMD21E17L", 128, 16 }, + /* Known SAMDA1 parts. SAMD-A1 series uses the same series identifier like the SAMD21 taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */ diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index d6f1a0a..9a53369 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -375,7 +375,6 @@ static int samv_probe(struct flash_bank *bank) default: LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); return ERROR_FAIL; - break; } struct samv_flash_bank *samv_info = bank->driver_priv; @@ -645,7 +644,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) switch (CMD_ARGC) { case 0: goto showall; - break; case 1: who = -1; break; @@ -660,7 +658,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) break; default: return ERROR_COMMAND_SYNTAX_ERROR; - break; } uint32_t v; diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 178567e..93f6872 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -58,7 +58,7 @@ struct avrf_type { struct avrf_flash_bank { int ppage_size; - int probed; + bool probed; }; static const struct avrf_type avft_chips_info[] = { @@ -67,6 +67,7 @@ static const struct avrf_type avft_chips_info[] = { */ {"atmega128", 0x9702, 256, 512, 8, 512}, {"atmega128rfa1", 0xa701, 128, 512, 8, 512}, + {"atmega256rfr2", 0xa802, 256, 1024, 8, 1024}, {"at90can128", 0x9781, 256, 512, 8, 512}, {"at90usb128", 0x9782, 256, 512, 8, 512}, {"atmega164p", 0x940a, 128, 128, 4, 128}, @@ -142,16 +143,24 @@ static int avr_jtagprg_chiperase(struct avr_common *avr) } static int avr_jtagprg_writeflashpage(struct avr_common *avr, + const bool ext_addressing, const uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size) { - uint32_t i, poll_value; + uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len); + /* load extended high byte */ + if (ext_addressing) + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x0b00 | ((addr >> 17) & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + /* load addr high byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, @@ -166,7 +175,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD); - for (i = 0; i < page_size; i++) { + for (uint32_t i = 0; i < page_size; i++) { if (i < buf_size) avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8); else @@ -204,7 +213,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command) avrf_info = malloc(sizeof(struct avrf_flash_bank)); bank->driver_priv = avrf_info; - avrf_info->probed = 0; + avrf_info->probed = false; return ERROR_OK; } @@ -238,6 +247,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o struct target *target = bank->target; struct avr_common *avr = target->arch_info; uint32_t cur_size, cur_buffer_size, page_size; + bool ext_addressing; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -258,6 +268,11 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o if (ERROR_OK != avr_jtagprg_enterprogmode(avr)) return ERROR_FAIL; + if (bank->size > 0x20000) + ext_addressing = true; + else + ext_addressing = false; + cur_size = 0; while (count > 0) { if (count > page_size) @@ -265,6 +280,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o else cur_buffer_size = count; avr_jtagprg_writeflashpage(avr, + ext_addressing, buffer + cur_size, cur_buffer_size, offset + cur_size, @@ -288,7 +304,6 @@ static int avrf_probe(struct flash_bank *bank) struct avrf_flash_bank *avrf_info = bank->driver_priv; struct avr_common *avr = target->arch_info; const struct avrf_type *avr_info = NULL; - int i; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { @@ -296,7 +311,7 @@ static int avrf_probe(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - avrf_info->probed = 0; + avrf_info->probed = false; avr_jtag_read_jtagid(avr, &device_id); if (ERROR_OK != mcu_execute_queue()) @@ -308,7 +323,7 @@ static int avrf_probe(struct flash_bank *bank) EXTRACT_MFG(device_id), 0x1F); - for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) { + for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); @@ -328,20 +343,20 @@ static int avrf_probe(struct flash_bank *bank) bank->num_sectors = avr_info->flash_page_num; bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num); - for (i = 0; i < avr_info->flash_page_num; i++) { + for (int i = 0; i < avr_info->flash_page_num; i++) { bank->sectors[i].offset = i * avr_info->flash_page_size; bank->sectors[i].size = avr_info->flash_page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } - avrf_info->probed = 1; + avrf_info->probed = true; return ERROR_OK; } else { /* chip not supported */ LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id)); - avrf_info->probed = 1; + avrf_info->probed = true; return ERROR_FAIL; } } @@ -359,7 +374,6 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) struct target *target = bank->target; struct avr_common *avr = target->arch_info; const struct avrf_type *avr_info = NULL; - int i; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { @@ -377,7 +391,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) EXTRACT_MFG(device_id), 0x1F); - for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) { + for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); @@ -418,8 +432,6 @@ static int avrf_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(avrf_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -430,7 +442,7 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command) if (avrf_mass_erase(bank) == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "avr mass erase complete"); diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index f6a2492..fbce20d 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -24,35 +24,62 @@ #include <target/armv7m.h> #include <target/cortex_m.h> #include "imp.h" +#include "bluenrg-x.h" + +#define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg) +#define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg) + +#define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg) +#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) +#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size) + +struct flash_ctrl_priv_data { + uint32_t die_id_reg; + uint32_t jtag_idcode_reg; + uint32_t flash_base; + uint32_t flash_regs_base; + uint32_t flash_page_size; + uint32_t jtag_idcode; + char *part_name; +}; + +const struct flash_ctrl_priv_data flash_priv_data_1 = { + .die_id_reg = 0x4090001C, + .jtag_idcode_reg = 0x40900028, + .flash_base = 0x10040000, + .flash_regs_base = 0x40100000, + .flash_page_size = 2048, + .jtag_idcode = 0x00000000, + .part_name = "BLUENRG-1", +}; -#define FLASH_SIZE_REG (0x40100014) -#define DIE_ID_REG (0x4090001C) -#define JTAG_IDCODE_REG (0x40900028) -#define BLUENRG2_IDCODE (0x0200A041) -#define FLASH_BASE (0x10040000) -#define FLASH_PAGE_SIZE (2048) -#define FLASH_REG_COMMAND (0x40100000) -#define FLASH_REG_IRQRAW (0x40100010) -#define FLASH_REG_ADDRESS (0x40100018) -#define FLASH_REG_DATA (0x40100040) -#define FLASH_CMD_ERASE_PAGE 0x11 -#define FLASH_CMD_MASSERASE 0x22 -#define FLASH_CMD_WRITE 0x33 -#define FLASH_CMD_BURSTWRITE 0xCC -#define FLASH_INT_CMDDONE 0x01 -#define FLASH_WORD_LEN 4 +const struct flash_ctrl_priv_data flash_priv_data_2 = { + .die_id_reg = 0x4090001C, + .jtag_idcode_reg = 0x40900028, + .flash_base = 0x10040000, + .flash_regs_base = 0x40100000, + .flash_page_size = 2048, + .jtag_idcode = 0x0200A041, + .part_name = "BLUENRG-2", +}; + +const struct flash_ctrl_priv_data flash_priv_data_lp = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x0201E041, + .part_name = "BLUENRG-LP", +}; struct bluenrgx_flash_bank { - int probed; - uint32_t idcode; + bool probed; uint32_t die_id; + const struct flash_ctrl_priv_data *flash_ptr; }; -static int bluenrgx_protect_check(struct flash_bank *bank) -{ - /* Nothing to do. Protection is only handled in SW. */ - return ERROR_OK; -} +const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp}; /* flash_bank bluenrg-x 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) @@ -67,9 +94,12 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) return ERROR_FAIL; } + bank->write_start_alignment = 16; + bank->write_end_alignment = 16; + bank->driver_priv = bluenrgx_info; - bluenrgx_info->probed = 0; + bluenrgx_info->probed = false; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; @@ -77,6 +107,22 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) return ERROR_OK; } +static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset; +} + +static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) +{ + return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); +} + +static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); +} + static int bluenrgx_erase(struct flash_bank *bank, int first, int last) { int retval = ERROR_OK; @@ -87,7 +133,7 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) uint32_t address, command; /* check preconditions */ - if (bluenrgx_info->probed == 0) + if (!bluenrgx_info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { @@ -103,24 +149,25 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) if (mass_erase) { command = FLASH_CMD_MASSERASE; address = bank->base; - if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, + (address - bank->base) >> 2) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - for (int i = 0; i < 100; i++) { + for (unsigned int i = 0; i < 100; i++) { uint32_t value; - if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } @@ -135,26 +182,28 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) } else { command = FLASH_CMD_ERASE_PAGE; for (int i = first; i <= last; i++) { - address = bank->base+i*FLASH_PAGE_SIZE; + address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info); + LOG_DEBUG("address = %08x, index = %d", address, i); - if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, + (address - bank->base) >> 2) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) { LOG_ERROR("Failed"); return ERROR_FAIL; } - for (int j = 0; j < 100; j++) { + for (unsigned int j = 0; j < 100; j++) { uint32_t value; - if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } @@ -172,140 +221,10 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) } -static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last) -{ - /* Protection is only handled in software: no hardware write protection - available in BlueNRG-x devices */ - int sector; - - for (sector = first; sector <= last; sector++) - bank->sectors[sector].is_protected = set; - return ERROR_OK; -} -static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count) -{ - int retval = ERROR_OK; - - retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - for (uint32_t i = 0; i < count; i++) { - uint32_t address = address_base + i * FLASH_WORD_LEN; - - retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - for (int j = 0; j < 100; j++) { - uint32_t reg_value; - retval = target_read_u32(target, FLASH_REG_IRQRAW, ®_value); - - if (retval != ERROR_OK) { - LOG_ERROR("Register read failed, error code: %d", retval); - return retval; - } - - if (reg_value & FLASH_INT_CMDDONE) - break; - - if (j == 99) { - LOG_ERROR("Write command failed (timeout)"); - return ERROR_FAIL; - } - } - } - return retval; -} - -static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count) -{ - int retval = ERROR_OK; - uint8_t *new_buffer = NULL; - uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address; - - if (count == 0) { - /* Just return if there are no bytes to write */ - return retval; - } - - if (address_base & 3) { - pre_bytes = address_base & 3; - pre_address = address_base - pre_bytes; - } - - if ((count + pre_bytes) & 3) { - post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes); - post_address = (address_base + count) & ~3; - } - - if (pre_bytes || post_bytes) { - uint32_t old_count = count; - - count = old_count + pre_bytes + post_bytes; - - new_buffer = malloc(count); - - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory " - "for padding buffer"); - return ERROR_FAIL; - } - - LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %" - PRIu32 " ", old_count, count); - - if (pre_bytes) { - if (target_read_u32(target, pre_address, &pre_word)) { - LOG_ERROR("Memory read failed"); - free(new_buffer); - return ERROR_FAIL; - } - - } - - if (post_bytes) { - if (target_read_u32(target, post_address, &post_word)) { - LOG_ERROR("Memory read failed"); - free(new_buffer); - return ERROR_FAIL; - } - - } - - memcpy(new_buffer, &pre_word, pre_bytes); - memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4); - memcpy(new_buffer+pre_bytes, buffer, old_count); - buffer = new_buffer; - } - - retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4); - - if (new_buffer) - free(new_buffer); - - return retval; -} - static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384 + 8; struct working_area *write_algorithm; @@ -313,10 +232,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; + struct mem_param mem_params[1]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - uint32_t pre_size = 0, fast_size = 0, post_size = 0; - uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0; /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and * hints how to generate the data! @@ -325,6 +243,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" }; + /* check preconditions */ + if (!bluenrgx_info->probed) + return ERROR_FLASH_BANK_NOT_PROBED; + if ((offset + count) > bank->size) { LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d", (offset + count), @@ -337,132 +259,105 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - /* We are good here and we need to compute pre_size, fast_size, post_size */ - pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset); - pre_offset = offset; - fast_size = 16*((count - pre_size) / 16); - fast_offset = offset + pre_size; - post_size = (count-pre_size-fast_size) % 16; - post_offset = fast_offset + fast_size; - - LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset); - LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset); - LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset); - - /* Program initial chunk not 16 bytes aligned */ - retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size); - if (retval) { - LOG_ERROR("bluenrgx_write_bytes failed %d", retval); - return ERROR_FAIL; + if (target_alloc_working_area(target, sizeof(bluenrgx_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; } - /* Program chunk 16 bytes aligned in fast mode */ - if (fast_size) { - - if (target_alloc_working_area(target, sizeof(bluenrgx_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(bluenrgx_flash_write_code), - bluenrgx_flash_write_code); - if (retval != ERROR_OK) - return retval; + retval = target_write_buffer(target, write_algorithm->address, + sizeof(bluenrgx_flash_write_code), + bluenrgx_flash_write_code); + if (retval != ERROR_OK) + return retval; - /* memory buffer */ - if (target_alloc_working_area(target, buffer_size, &source)) { - LOG_WARNING("no large enough working area available"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* memory buffer */ + if (target_alloc_working_area(target, buffer_size, &source)) { + LOG_WARNING("no large enough working area available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - /* Stack pointer area */ - if (target_alloc_working_area(target, 64, - &write_algorithm_sp) != ERROR_OK) { - LOG_DEBUG("no working area for write code stack pointer"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* Stack pointer area */ + if (target_alloc_working_area(target, 128, + &write_algorithm_sp) != ERROR_OK) { + LOG_DEBUG("no working area for write code stack pointer"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - - init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); - init_reg_param(®_params[4], "sp", 32, PARAM_OUT); - - /* FIFO start address (first two words used for write and read pointers) */ - buf_set_u32(reg_params[0].value, 0, 32, source->address); - /* FIFO end address (first two words used for write and read pointers) */ - buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); - /* Flash memory address */ - buf_set_u32(reg_params[2].value, 0, 32, address+pre_size); - /* Number of bytes */ - buf_set_u32(reg_params[3].value, 0, 32, fast_size); - /* Stack pointer for program working area */ - buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); - - LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address); - LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size); - LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address); - LOG_DEBUG("address = %08x", address+pre_size); - LOG_DEBUG("count = %08x", count); - - retval = target_run_flash_async_algorithm(target, - buffer+pre_size, - fast_size/16, - 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ - 0, - NULL, - 5, - reg_params, - source->address, - source->size, - write_algorithm->address, - 0, - &armv7m_info); - - if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("error executing bluenrg-x flash write algorithm"); - - uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); - - if (error != 0) - LOG_ERROR("flash write failed = %08" PRIx32, error); - } + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); + /* Put the parameter at the first available stack location */ + init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT); + + /* FIFO start address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[0].value, 0, 32, source->address); + /* FIFO end address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + /* Flash memory address */ + buf_set_u32(reg_params[2].value, 0, 32, address); + /* Number of bytes */ + buf_set_u32(reg_params[3].value, 0, 32, count); + /* Stack pointer for program working area */ + buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); + /* Flash register base address */ + buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base); + + LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address); + LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size); + LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address); + LOG_DEBUG("address = %08x", address); + LOG_DEBUG("count = %08x", count); + + retval = target_run_flash_async_algorithm(target, + buffer, + count/16, + 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ + 1, + mem_params, + 5, + reg_params, + source->address, + source->size, + write_algorithm->address, + 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("error executing bluenrg-x flash write algorithm"); + + uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); + + if (error != 0) + LOG_ERROR("flash write failed = %08" PRIx32, error); + } + if (retval == ERROR_OK) { + uint32_t rp; + /* Read back rp and check that is valid */ + retval = target_read_u32(target, source->address+4, &rp); if (retval == ERROR_OK) { - uint32_t rp; - /* Read back rp and check that is valid */ - retval = target_read_u32(target, source->address+4, &rp); - if (retval == ERROR_OK) { - if ((rp < source->address+8) || (rp > (source->address + source->size))) { - LOG_ERROR("flash write failed = %08" PRIx32, rp); - retval = ERROR_FLASH_OPERATION_FAILED; - } + if ((rp < source->address+8) || (rp > (source->address + source->size))) { + LOG_ERROR("flash write failed = %08" PRIx32, rp); + retval = ERROR_FLASH_OPERATION_FAILED; } } - target_free_working_area(target, source); - target_free_working_area(target, write_algorithm); - target_free_working_area(target, write_algorithm_sp); - - 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]); - if (retval != ERROR_OK) - return retval; - } + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + target_free_working_area(target, write_algorithm_sp); + + 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]); + destroy_mem_param(&mem_params[0]); - /* Program chunk at end, not addressable by fast burst write algorithm */ - retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size); - if (retval) { - LOG_ERROR("bluenrgx_write_bytes failed %d", retval); - return ERROR_FAIL; - } return retval; } @@ -470,33 +365,50 @@ static int bluenrgx_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; uint32_t idcode, size_info, die_id; - int i; - int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode); + int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode); + if (retval != ERROR_OK) return retval; - retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info); + + if (idcode != flash_priv_data_lp.jtag_idcode) { + retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); + if (retval != ERROR_OK) + return retval; + } + + /* Default device is BlueNRG-1 */ + bluenrgx_info->flash_ptr = &flash_priv_data_1; + bank->base = flash_priv_data_1.flash_base; + + for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) { + if (idcode == (*flash_ctrl[i]).jtag_idcode) { + bluenrgx_info->flash_ptr = flash_ctrl[i]; + bank->base = (*flash_ctrl[i]).flash_base; + break; + } + } + retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info); if (retval != ERROR_OK) return retval; - retval = target_read_u32(bank->target, DIE_ID_REG, &die_id); + retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id); if (retval != ERROR_OK) return retval; - bank->size = (size_info + 1) * 4; - bank->base = FLASH_BASE; - bank->num_sectors = bank->size/FLASH_PAGE_SIZE; + bank->size = (size_info + 1) * FLASH_WORD_LEN; + bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); - for (i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].offset = i * FLASH_PAGE_SIZE; - bank->sectors[i].size = FLASH_PAGE_SIZE; + for (int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info); + bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } - bluenrgx_info->probed = 1; + bluenrgx_info->probed = true; bluenrgx_info->die_id = die_id; - bluenrgx_info->idcode = idcode; + return ERROR_OK; } @@ -515,7 +427,6 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; int mask_number, cut_number; - char *part_name; if (!bluenrgx_info->probed) { int retval = bluenrgx_probe(bank); @@ -526,16 +437,11 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) } } - if (bluenrgx_info->idcode == BLUENRG2_IDCODE) - part_name = "BLUENRG-2"; - else - part_name = "BLUENRG-1"; - mask_number = (bluenrgx_info->die_id >> 4) & 0xF; cut_number = bluenrgx_info->die_id & 0xF; snprintf(buf, buf_size, - "%s - Rev: %d.%d", part_name, mask_number, cut_number); + "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number); return ERROR_OK; } @@ -543,12 +449,12 @@ const struct flash_driver bluenrgx_flash = { .name = "bluenrg-x", .flash_bank_command = bluenrgx_flash_bank_command, .erase = bluenrgx_erase, - .protect = bluenrgx_protect, + .protect = NULL, .write = bluenrgx_write, .read = default_flash_read, .probe = bluenrgx_probe, .erase_check = default_flash_blank_check, - .protect_check = bluenrgx_protect_check, + .protect_check = NULL, .auto_probe = bluenrgx_auto_probe, .info = bluenrgx_get_info, }; diff --git a/src/flash/nor/bluenrg-x.h b/src/flash/nor/bluenrg-x.h new file mode 100644 index 0000000..3b84b8b --- /dev/null +++ b/src/flash/nor/bluenrg-x.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2019 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/>. * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_BLUENRGX_H +#define OPENOCD_FLASH_NOR_BLUENRGX_H + +/* Flash Controller registers offsets */ +#define FLASH_REG_COMMAND 0x00 +#define FLASH_REG_CONFIG 0x04 +#define FLASH_REG_IRQSTAT 0x08 +#define FLASH_REG_IRQMASK 0x0C +#define FLASH_REG_IRQRAW 0x10 +#define FLASH_REG_ADDRESS 0x18 +#define FLASH_REG_UNLOCKM 0x1C +#define FLASH_REG_UNLOCKL 0x20 +#define FLASH_REG_DATA0 0x40 +#define FLASH_REG_DATA1 0x44 +#define FLASH_REG_DATA2 0x48 +#define FLASH_REG_DATA3 0x4C +#define FLASH_SIZE_REG 0x14 + +/* Flash Controller commands */ +#define FLASH_CMD_ERASE_PAGE 0x11 +#define FLASH_CMD_MASSERASE 0x22 +#define FLASH_CMD_WRITE 0x33 +#define FLASH_CMD_BURSTWRITE 0xCC +#define FLASH_INT_CMDDONE 0x01 + +#define FLASH_WORD_LEN 4 + +#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */ diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c index afdb7f4..c8de7d0 100644 --- a/src/flash/nor/cc3220sf.c +++ b/src/flash/nor/cc3220sf.c @@ -363,6 +363,8 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, LOG_ERROR("cc3220sf: Flash operation failed"); break; } + + keep_alive(); } /* Do one word write for any final bytes less than a full word */ diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 04fa83b..50ab207 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -34,9 +34,6 @@ #include <helper/binarybuffer.h> #include <target/algorithm.h> -#define CFI_MAX_BUS_WIDTH 4 -#define CFI_MAX_CHIP_WIDTH 4 - /* defines internal maximum size for code fragment in cfi_intel_write_block() */ #define CFI_MAX_INTEL_CODESIZE 256 @@ -103,16 +100,15 @@ static const struct cfi_fixup cfi_0001_fixups[] = { static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups) { struct cfi_flash_bank *cfi_info = bank->driver_priv; - const struct cfi_fixup *f; - for (f = fixups; f->fixup; f++) { + for (const struct cfi_fixup *f = fixups; f->fixup; f++) { if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) && ((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id))) f->fixup(bank, f->param); } } -static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset) +uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -131,32 +127,55 @@ static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32 } } +static int cfi_target_write_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, const uint8_t *buffer) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + if (cfi_info->write_mem) { + return cfi_info->write_mem(bank, addr, count, buffer); + } else { + return target_write_memory(bank->target, addr, bank->bus_width, + count, buffer); + } +} + +int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + if (cfi_info->read_mem) { + return cfi_info->read_mem(bank, addr, count, buffer); + } else { + return target_read_memory(bank->target, addr, bank->bus_width, + count, buffer); + } +} + static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf) { - int i; struct cfi_flash_bank *cfi_info = bank->driver_priv; /* clear whole buffer, to ensure bits that exceed the bus_width * are set to zero */ - for (i = 0; i < CFI_MAX_BUS_WIDTH; i++) + for (size_t i = 0; i < CFI_MAX_BUS_WIDTH; i++) cmd_buf[i] = 0; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { - for (i = bank->bus_width; i > 0; i--) + for (int i = bank->bus_width; i > 0; i--) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } else { - for (i = 1; i <= bank->bus_width; i++) + for (int i = 1; i <= bank->bus_width; i++) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } } -static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address) +int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address) { uint8_t command[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, command); - return target_write_memory(bank->target, address, bank->bus_width, 1, command); + return cfi_target_write_memory(bank, address, 1, command); } /* read unsigned 8-bit value from the bank @@ -165,13 +184,12 @@ static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t addre */ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; int retval; - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 1, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 1, data); if (retval != ERROR_OK) return retval; @@ -189,25 +207,23 @@ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, ui */ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; - int i; int retval; - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 1, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 1, data); if (retval != ERROR_OK) return retval; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { - for (i = 0; i < bank->bus_width / bank->chip_width; i++) + for (int i = 0; i < bank->bus_width / bank->chip_width; i++) data[0] |= data[i]; *val = data[0]; } else { uint8_t value = 0; - for (i = 0; i < bank->bus_width / bank->chip_width; i++) + for (int i = 0; i < bank->bus_width / bank->chip_width; i++) value |= data[bank->bus_width - 1 - i]; *val = value; @@ -217,22 +233,20 @@ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, uint16_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 2]; int retval; if (cfi_info->x16_as_x8) { - uint8_t i; - for (i = 0; i < 2; i++) { - retval = target_read_memory(target, flash_address(bank, sector, offset + i), - bank->bus_width, 1, &data[i * bank->bus_width]); + for (uint8_t i = 0; i < 2; i++) { + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i), + 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 2, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 2, data); if (retval != ERROR_OK) return retval; } @@ -247,22 +261,20 @@ static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, u static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, uint32_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 4]; int retval; if (cfi_info->x16_as_x8) { - uint8_t i; - for (i = 0; i < 4; i++) { - retval = target_read_memory(target, flash_address(bank, sector, offset + i), - bank->bus_width, 1, &data[i * bank->bus_width]); + for (uint8_t i = 0; i < 4; i++) { + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i), + 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 4, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 4, data); if (retval != ERROR_OK) return retval; } @@ -278,16 +290,16 @@ static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, u return ERROR_OK; } -static int cfi_reset(struct flash_bank *bank) +int cfi_reset(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval = ERROR_OK; - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -295,7 +307,7 @@ static int cfi_reset(struct flash_bank *bank) (cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E)) { /* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state * so we send an extra 0xF0 reset to fix the bug */ - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x00)); if (retval != ERROR_OK) return retval; } @@ -305,7 +317,7 @@ static int cfi_reset(struct flash_bank *bank) static void cfi_intel_clear_status_register(struct flash_bank *bank) { - cfi_send_command(bank, 0x50, flash_address(bank, 0, 0x0)); + cfi_send_command(bank, 0x50, cfi_flash_address(bank, 0, 0x0)); } static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint8_t *val) @@ -359,7 +371,7 @@ static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint return retval; } -static int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout) +int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout) { uint8_t status, oldstatus; struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -534,7 +546,7 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank) pri_ext->_reversed_geometry = 0; if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read spansion bank information"); @@ -641,7 +653,7 @@ static int cfi_read_atmel_pri_ext(struct flash_bank *bank) if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I')) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read atmel bank information"); @@ -799,14 +811,12 @@ static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options] - */ -FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) +int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv) { struct cfi_flash_bank *cfi_info; int bus_swap = 0; - if (CMD_ARGC < 6) + if (argc < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* both widths must: @@ -826,7 +836,7 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) } cfi_info = malloc(sizeof(struct cfi_flash_bank)); - cfi_info->probed = 0; + cfi_info->probed = false; cfi_info->erase_region_info = NULL; cfi_info->pri_ext = NULL; bank->driver_priv = cfi_info; @@ -836,14 +846,14 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) cfi_info->not_cfi = 0; cfi_info->data_swap = 0; - for (unsigned i = 6; i < CMD_ARGC; i++) { - if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0) + for (unsigned i = 6; i < argc; i++) { + if (strcmp(argv[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = 1; - else if (strcmp(CMD_ARGV[i], "data_swap") == 0) + else if (strcmp(argv[i], "data_swap") == 0) cfi_info->data_swap = 1; - else if (strcmp(CMD_ARGV[i], "bus_swap") == 0) + else if (strcmp(argv[i], "bus_swap") == 0) bus_swap = 1; - else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0) + else if (strcmp(argv[i], "jedec_probe") == 0) cfi_info->jedec_probe = 1; } @@ -860,20 +870,26 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) return ERROR_OK; } +/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options] + */ +FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) +{ + return cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV); +} + static int cfi_intel_erase(struct flash_bank *bank, int first, int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - int i; cfi_intel_clear_status_register(bank); - for (i = first; i <= last; i++) { - retval = cfi_send_command(bank, 0x20, flash_address(bank, i, 0x0)); + for (int i = first; i <= last; i++) { + retval = cfi_send_command(bank, 0x20, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; @@ -885,7 +901,7 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last) if (status == 0x80) bank->sectors[i].is_erased = 1; else { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -895,45 +911,53 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last) } } - return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) +int cfi_spansion_unlock_seq(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - int i; - for (i = first; i <= last; i++) { - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; + retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, pri_ext->_unlock1)); + if (retval != ERROR_OK) + return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); - if (retval != ERROR_OK) - return retval; + retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, pri_ext->_unlock2)); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} - retval = cfi_send_command(bank, 0x80, flash_address(bank, 0, pri_ext->_unlock1)); +static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) +{ + int retval; + struct cfi_flash_bank *cfi_info = bank->driver_priv; + struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; + + for (int i = first; i <= last; i++) { + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); + retval = cfi_send_command(bank, 0x80, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x30, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x30, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK) bank->sectors[i].is_erased = 1; else { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -943,10 +967,10 @@ static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) } } - return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_erase(struct flash_bank *bank, int first, int last) +int cfi_erase(struct flash_bank *bank, int first, int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -965,10 +989,8 @@ static int cfi_erase(struct flash_bank *bank, int first, int last) case 1: case 3: return cfi_intel_erase(bank, first, last); - break; case 2: return cfi_spansion_erase(bank, first, last); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -983,7 +1005,6 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; int retry = 0; - int i; /* if the device supports neither legacy lock/unlock (bit 3) nor * instant individual block locking (bit 5). @@ -995,17 +1016,17 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la cfi_intel_clear_status_register(bank); - for (i = first; i <= last; i++) { - retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0)); + for (int i = first; i <= last; i++) { + retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (set) { - retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 1; } else { - retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 0; @@ -1022,7 +1043,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la } else { uint8_t block_status; /* read block lock bit, to verify status */ - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; retval = cfi_get_u8(bank, i, 0x2, &block_status); @@ -1033,7 +1054,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la LOG_ERROR( "couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); - retval = cfi_send_command(bank, 0x70, flash_address(bank, 0, 0x55)); + retval = cfi_send_command(bank, 0x70, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; uint8_t status; @@ -1066,15 +1087,15 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la * 3. re-protect what should be protected. * */ - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) { cfi_intel_clear_status_register(bank); - retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; @@ -1086,10 +1107,10 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la } } - return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_protect(struct flash_bank *bank, int set, int first, int last) +int cfi_protect(struct flash_bank *bank, int set, int first, int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -1105,7 +1126,6 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last) case 1: case 3: return cfi_intel_protect(bank, set, first, last); - break; default: LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); return ERROR_OK; @@ -1121,13 +1141,10 @@ static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd) switch (bank->bus_width) { case 1: return buf[0]; - break; case 2: return target_buffer_get_u16(target, buf); - break; case 4: return target_buffer_get_u32(target, buf); - break; default: LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); @@ -1558,9 +1575,9 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); - buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); + buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); - buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); + buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, @@ -1937,9 +1954,9 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); - buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); + buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); - buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); + buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, @@ -1981,14 +1998,13 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; cfi_intel_clear_status_register(bank); retval = cfi_send_command(bank, 0x40, address); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, 1, word); + retval = cfi_target_write_memory(bank, address, 1, word); if (retval != ERROR_OK) return retval; @@ -1997,7 +2013,7 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t if (retval != ERROR_OK) return retval; if (status != 0x80) { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2015,7 +2031,6 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) @@ -2052,7 +2067,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, if (retval != ERROR_OK) return retval; if (status != 0x80) { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2069,7 +2084,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word); + retval = cfi_target_write_memory(bank, address, bufferwsize, word); if (retval != ERROR_OK) return retval; @@ -2083,7 +2098,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, return retval; if (status != 0x80) { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2100,26 +2115,21 @@ static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint3 int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - struct target *target = bank->target; - - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xa0, flash_address(bank, 0, pri_ext->_unlock1)); + retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, 1, word); + retval = cfi_target_write_memory(bank, address, 1, word); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2136,8 +2146,6 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; - struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) @@ -2163,11 +2171,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word } /* Unlock */ - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; - - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; @@ -2181,7 +2185,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word); + retval = cfi_target_write_memory(bank, address, bufferwsize, word); if (retval != ERROR_OK) return retval; @@ -2191,7 +2195,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2204,7 +2208,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word return ERROR_OK; } -static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) +int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -2212,10 +2216,8 @@ static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t addre case 1: case 3: return cfi_intel_write_word(bank, word, address); - break; case 2: return cfi_spansion_write_word(bank, word, address); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -2239,10 +2241,8 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, case 1: case 3: return cfi_intel_write_words(bank, word, wordcount, address); - break; case 2: return cfi_spansion_write_words(bank, word, wordcount, address); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -2254,12 +2254,10 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; uint32_t address = bank->base + offset; uint32_t read_p; int align; /* number of unaligned bytes */ uint8_t current_word[CFI_MAX_BUS_WIDTH]; - int i; int retval; LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", @@ -2283,12 +2281,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u LOG_INFO("Fixup %d unaligned read head bytes", align); /* read a complete word from flash */ - retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, read_p, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ - for (i = align; (i < bank->bus_width) && (count > 0); i++, count--) + for (int i = align; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; read_p += bank->bus_width; @@ -2296,7 +2294,7 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u align = count / bank->bus_width; if (align) { - retval = target_read_memory(target, read_p, bank->bus_width, align, buffer); + retval = cfi_target_read_memory(bank, read_p, align, buffer); if (retval != ERROR_OK) return retval; @@ -2309,12 +2307,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u LOG_INFO("Fixup %" PRIu32 " unaligned read tail bytes", count); /* read a complete word from flash */ - retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, read_p, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ - for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) + for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; } @@ -2324,7 +2322,6 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; uint32_t address = bank->base + offset; /* address of first byte to be programmed */ uint32_t write_p; int align; /* number of unaligned bytes */ @@ -2333,7 +2330,6 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of *programmed */ uint8_t *swapped_buffer = NULL; const uint8_t *real_buffer = NULL; - int i; int retval; if (bank->target->state != TARGET_HALTED) { @@ -2354,12 +2350,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of LOG_INFO("Fixup %d unaligned head bytes", align); /* read a complete word from flash */ - retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ - for (i = align; + for (int i = align; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) @@ -2425,12 +2421,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of /* fall back to memory writes */ while (count >= (uint32_t)bank->bus_width) { - int fallback; + bool fallback; if ((write_p & 0xff) == 0) { LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" PRIx32 " bytes remaining", write_p, count); } - fallback = 1; + fallback = true; if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask)) { retval = cfi_write_words(bank, buffer, bufferwsize, write_p); @@ -2438,13 +2434,13 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of buffer += buffersize; write_p += buffersize; count -= buffersize; - fallback = 0; + fallback = false; } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) return retval; } /* try the slow way? */ if (fallback) { - for (i = 0; i < bank->bus_width; i++) + for (int i = 0; i < bank->bus_width; i++) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); @@ -2474,12 +2470,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count); /* read a complete word from flash */ - retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ - for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) + for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) /* data bytes are swapped (reverse endianness) */ current_word[bank->bus_width - i] = *buffer++; @@ -2506,7 +2502,6 @@ static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param) { - int i; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; (void) param; @@ -2514,7 +2509,7 @@ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *pa if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) { LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device"); - for (i = 0; i < cfi_info->num_erase_regions / 2; i++) { + for (unsigned int i = 0; i < cfi_info->num_erase_regions / 2; i++) { int j = (cfi_info->num_erase_regions - 1) - i; uint32_t swap; @@ -2549,7 +2544,7 @@ static int cfi_query_string(struct flash_bank *bank, int address) struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval; - retval = cfi_send_command(bank, 0x98, flash_address(bank, 0, address)); + retval = cfi_send_command(bank, 0x98, cfi_flash_address(bank, 0, address)); if (retval != ERROR_OK) return retval; @@ -2577,12 +2572,11 @@ static int cfi_query_string(struct flash_bank *bank, int address) return ERROR_OK; } -static int cfi_probe(struct flash_bank *bank) +int cfi_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; int num_sectors = 0; - int i; int sector = 0; uint32_t unlock1 = 0x555; uint32_t unlock2 = 0x2aa; @@ -2594,7 +2588,7 @@ static int cfi_probe(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - cfi_info->probed = 0; + cfi_info->probed = false; cfi_info->num_erase_regions = 0; if (bank->sectors) { free(bank->sectors); @@ -2614,22 +2608,22 @@ static int cfi_probe(struct flash_bank *bank) } /* switch to read identifier codes mode ("AUTOSELECT") */ - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, unlock1)); + retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, unlock2)); + retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, unlock2)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, unlock1)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; - retval = target_read_memory(target, flash_address(bank, 0, 0x00), - bank->bus_width, 1, value_buf0); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x00), + 1, value_buf0); if (retval != ERROR_OK) return retval; - retval = target_read_memory(target, flash_address(bank, 0, 0x01), - bank->bus_width, 1, value_buf1); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x01), + 1, value_buf1); if (retval != ERROR_OK) return retval; switch (bank->chip_width) { @@ -2766,7 +2760,7 @@ static int cfi_probe(struct flash_bank *bank) if (cfi_info->num_erase_regions) { cfi_info->erase_region_info = malloc(sizeof(*cfi_info->erase_region_info) * cfi_info->num_erase_regions); - for (i = 0; i < cfi_info->num_erase_regions; i++) { + for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) { retval = cfi_query_u32(bank, 0, 0x2d + (4 * i), @@ -2881,15 +2875,14 @@ static int cfi_probe(struct flash_bank *bank) } else { uint32_t offset = 0; - for (i = 0; i < cfi_info->num_erase_regions; i++) + for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - for (i = 0; i < cfi_info->num_erase_regions; i++) { - uint32_t j; - for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { + for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) { + for (uint32_t j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { bank->sectors[sector].offset = offset; bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) @@ -2902,18 +2895,18 @@ static int cfi_probe(struct flash_bank *bank) } if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) { LOG_WARNING( - "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \ + "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset); } } - cfi_info->probed = 1; + cfi_info->probed = true; return ERROR_OK; } -static int cfi_auto_probe(struct flash_bank *bank) +int cfi_auto_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->probed) @@ -2926,17 +2919,16 @@ static int cfi_intel_protect_check(struct flash_bank *bank) int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; - int i; /* check if block lock bits are supported on this device */ if (!(pri_ext->blk_status_reg_mask & 0x1)) return ERROR_FLASH_OPERATION_FAILED; - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) @@ -2948,7 +2940,7 @@ static int cfi_intel_protect_check(struct flash_bank *bank) bank->sectors[i].is_protected = 0; } - return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } static int cfi_spansion_protect_check(struct flash_bank *bank) @@ -2956,21 +2948,16 @@ static int cfi_spansion_protect_check(struct flash_bank *bank) int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - int i; - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; - - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) @@ -2982,10 +2969,10 @@ static int cfi_spansion_protect_check(struct flash_bank *bank) bank->sectors[i].is_protected = 0; } - return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_protect_check(struct flash_bank *bank) +int cfi_protect_check(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -3001,10 +2988,8 @@ static int cfi_protect_check(struct flash_bank *bank) case 1: case 3: return cfi_intel_protect_check(bank); - break; case 2: return cfi_spansion_protect_check(bank); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -3013,7 +2998,7 @@ static int cfi_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size) +int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -3124,6 +3109,6 @@ const struct flash_driver cfi_flash = { /* FIXME: access flash at bus_width size */ .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, - .info = get_cfi_info, + .info = cfi_get_info, .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index ed858a9..aef7a04 100644 --- a/src/flash/nor/cfi.h +++ b/src/flash/nor/cfi.h @@ -73,6 +73,12 @@ struct cfi_flash_bank { unsigned buf_write_timeout; unsigned block_erase_timeout; unsigned chip_erase_timeout; + + /* memory accessors */ + int (*write_mem)(struct flash_bank *bank, target_addr_t addr, + uint32_t count, const uint8_t *buffer); + int (*read_mem)(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer); }; /* Intel primary extended query table @@ -148,6 +154,24 @@ struct cfi_fixup { const void *param; }; +int cfi_erase(struct flash_bank *bank, int first, int last); +int cfi_protect(struct flash_bank *bank, int set, int first, int last); +int cfi_probe(struct flash_bank *bank); +int cfi_auto_probe(struct flash_bank *bank); +int cfi_protect_check(struct flash_bank *bank); +int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size); +int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv); + +uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset); +int cfi_spansion_unlock_seq(struct flash_bank *bank); +int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address); +int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address); +int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout); +int cfi_reset(struct flash_bank *bank); + +int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer); + #define CFI_MFR_AMD 0x0001 #define CFI_MFR_FUJITSU 0x0004 #define CFI_MFR_ATMEL 0x001F @@ -160,4 +184,7 @@ struct cfi_fixup { #define CFI_MFR_ANY 0xffff #define CFI_ID_ANY 0xffff +#define CFI_MAX_BUS_WIDTH 4 +#define CFI_MAX_CHIP_WIDTH 4 + #endif /* OPENOCD_FLASH_NOR_CFI_H */ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 551f389..d52e072 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -66,6 +66,8 @@ extern const struct flash_driver psoc5lp_flash; extern const struct flash_driver psoc5lp_eeprom_flash; extern const struct flash_driver psoc5lp_nvl_flash; extern const struct flash_driver psoc6_flash; +extern const struct flash_driver renesas_rpchf_flash; +extern const struct flash_driver sh_qspi_flash; extern const struct flash_driver sim3x_flash; extern const struct flash_driver stellaris_flash; extern const struct flash_driver stm32f1x_flash; @@ -136,6 +138,8 @@ static const struct flash_driver * const flash_drivers[] = { &psoc5lp_eeprom_flash, &psoc5lp_nvl_flash, &psoc6_flash, + &renesas_rpchf_flash, + &sh_qspi_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, diff --git a/src/flash/nor/dsp5680xx_flash.c b/src/flash/nor/dsp5680xx_flash.c index 37b60f0..da67585 100644 --- a/src/flash/nor/dsp5680xx_flash.c +++ b/src/flash/nor/dsp5680xx_flash.c @@ -154,7 +154,7 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first, * * @return */ -static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t* buffer, +static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 83d133f..fe4ddd4 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -99,7 +99,7 @@ struct efm32_family_data { }; struct efm32x_flash_bank { - int probed; + bool probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; uint32_t reg_base; uint32_t reg_lock; @@ -140,6 +140,7 @@ static const struct efm32_family_data efm32_families[] = { { 43, "EFR32BG13P Blue", .series = 1 }, { 44, "EFR32BG13B Blue", .series = 1 }, { 45, "EFR32BG13V Blue", .series = 1 }, + { 46, "EFR32ZG13P Zen", .series = 1 }, { 49, "EFR32FG13P Flex", .series = 1 }, { 50, "EFR32FG13B Flex", .series = 1 }, { 51, "EFR32FG13V Flex", .series = 1 }, @@ -149,6 +150,7 @@ static const struct efm32_family_data efm32_families[] = { { 55, "EFR32BG14P Blue", .series = 1 }, { 56, "EFR32BG14B Blue", .series = 1 }, { 57, "EFR32BG14V Blue", .series = 1 }, + { 58, "EFR32ZG14P Zen", .series = 1 }, { 61, "EFR32FG14P Flex", .series = 1 }, { 62, "EFR32FG14B Flex", .series = 1 }, { 63, "EFR32FG14V Flex", .series = 1 }, @@ -166,7 +168,8 @@ static const struct efm32_family_data efm32_families[] = { { 89, "EFM32PG13B Pearl", .series = 1 }, { 91, "EFM32JG13B Jade", .series = 1 }, { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 }, - { 103, "EFM32TG11B Tiny", .series = 1 }, + { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 }, + { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 }, { 120, "EZR32WG Wonder", .series = 0 }, { 121, "EZR32LG Leopard", .series = 0 }, { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, @@ -348,7 +351,7 @@ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) efm32x_info = malloc(sizeof(struct efm32x_flash_bank)); bank->driver_priv = efm32x_info; - efm32x_info->probed = 0; + efm32x_info->probed = false; memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); return ERROR_OK; @@ -467,7 +470,6 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) static int efm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; - int i = 0; int ret = 0; if (TARGET_HALTED != target->state) { @@ -482,7 +484,7 @@ static int efm32x_erase(struct flash_bank *bank, int first, int last) return ret; } - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { ret = efm32x_erase_page(bank, bank->sectors[i].offset); if (ERROR_OK != ret) LOG_ERROR("Failed to erase page %d", i); @@ -498,7 +500,6 @@ static int efm32x_read_lock_data(struct flash_bank *bank) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; struct target *target = bank->target; - int i = 0; int data_size = 0; uint32_t *ptr = NULL; int ret = 0; @@ -510,7 +511,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) ptr = efm32x_info->lb_page; - for (i = 0; i < data_size; i++, ptr++) { + for (int i = 0; i < data_size; i++, ptr++) { ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr); if (ERROR_OK != ret) { LOG_ERROR("Failed to read PLW %d", i); @@ -616,7 +617,6 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) static int efm32x_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; - int i = 0; int ret = 0; if (!set) { @@ -629,7 +629,7 @@ static int efm32x_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_TARGET_NOT_HALTED; } - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { ret = efm32x_set_page_lock(bank, i, set); if (ERROR_OK != ret) { LOG_ERROR("Failed to set lock on page %d", i); @@ -960,11 +960,10 @@ static int efm32x_probe(struct flash_bank *bank) struct efm32x_flash_bank *efm32x_info = bank->driver_priv; struct efm32_info efm32_mcu_info; int ret; - int i; uint32_t base_address = 0x00000000; char buf[256]; - efm32x_info->probed = 0; + efm32x_info->probed = false; memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); ret = efm32x_read_info(bank, &efm32_mcu_info); @@ -1003,14 +1002,14 @@ static int efm32x_probe(struct flash_bank *bank) bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - for (i = 0; i < num_pages; i++) { + for (int i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * efm32_mcu_info.page_size; bank->sectors[i].size = efm32_mcu_info.page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - efm32x_info->probed = 1; + efm32x_info->probed = true; return ERROR_OK; } @@ -1027,7 +1026,6 @@ static int efm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; int ret = 0; - int i = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1042,7 +1040,7 @@ static int efm32x_protect_check(struct flash_bank *bank) assert(NULL != bank->sectors); - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i); return ERROR_OK; diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 6b05332..bc192b6 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -183,7 +183,7 @@ static int fespi_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_ } static int fespi_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value) -{ \ +{ struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index a8877b4..7e3a1c5 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -207,7 +207,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2); uint32_t result; unsigned i; - int retval; + int retval, retval2 = ERROR_OK; const uint8_t write_block_code[] = { #include "../../../contrib/loaders/flash/fm4/write.inc" }; @@ -327,7 +327,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, err_run_ret: err_run: err_write_data: - retval = fm4_enter_flash_cpu_rom_mode(target); + retval2 = fm4_enter_flash_cpu_rom_mode(target); err_flash_mode: for (i = 0; i < ARRAY_SIZE(reg_params); i++) @@ -338,7 +338,9 @@ err_alloc_data: err_write_code: target_free_working_area(target, code_workarea); - return retval; + if (retval != ERROR_OK) + return retval; + return retval2; } static int mb9bf_probe(struct flash_bank *bank) diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index a9f2dd4..d841579 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -59,7 +59,7 @@ static void jtagspi_set_ir(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; struct scan_field field; - uint8_t buf[4]; + uint8_t buf[4] = { 0 }; LOG_DEBUG("loading jtagspi ir"); buf_set_u32(buf, 0, info->tap->ir_length, info->ir); @@ -153,12 +153,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, jtagspi_set_ir(bank); /* passing from an IR scan to SHIFT-DR clears BYPASS registers */ jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE); - jtag_execute_queue(); + int retval = jtag_execute_queue(); if (is_read) flip_u8(data_buf, data, lenb); free(data_buf); - return ERROR_OK; + return retval; } static int jtagspi_probe(struct flash_bank *bank) @@ -228,13 +228,16 @@ static int jtagspi_probe(struct flash_bank *bank) return ERROR_OK; } -static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status) +static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status) { uint8_t buf; - if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) { + int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8); + if (err == ERROR_OK) { *status = buf; /* LOG_DEBUG("status=0x%08" PRIx32, *status); */ } + + return err; } static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) @@ -245,7 +248,11 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) do { dt = timeval_ms() - t0; - jtagspi_read_status(bank, &status); + + int retval = jtagspi_read_status(bank, &status); + if (retval != ERROR_OK) + return retval; + if ((status & SPIFLASH_BSY_BIT) == 0) { LOG_DEBUG("waited %" PRId64 " ms", dt); return ERROR_OK; @@ -262,7 +269,11 @@ static int jtagspi_write_enable(struct flash_bank *bank) uint32_t status; jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0); - jtagspi_read_status(bank, &status); + + int retval = jtagspi_read_status(bank, &status); + if (retval != ERROR_OK) + return retval; + if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 687a337..084e009 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -787,9 +787,8 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) { uint32_t stats[32]; - int i; - for (i = 0; i < 32; i++) { + for (unsigned int i = 0; i < 32; i++) { stats[i] = MDM_STAT_FREADY; dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]); } @@ -798,7 +797,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) LOG_DEBUG("MDM: dap_run failed when validating secured state"); return ERROR_OK; } - for (i = 0; i < 32; i++) { + for (unsigned int i = 0; i < 32; i++) { if (stats[i] & MDM_STAT_SYSSEC) secured_score++; if (!(stats[i] & MDM_STAT_FREADY)) @@ -860,8 +859,7 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target) static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[]) { - int i; - for (i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-sim-base") == 0) { if (i + 1 < argc) k_chip->sim_base = strtoul(argv[++i], NULL, 0); @@ -933,7 +931,6 @@ static void kinetis_free_driver_priv(struct flash_bank *bank) static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) { - unsigned bank_idx; unsigned num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; @@ -968,7 +965,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) *p = '\0'; } - for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) { + for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank = k_bank->bank; @@ -1219,11 +1216,11 @@ static int kinetis_ftfx_clear_error(struct target *target) static int kinetis_ftfx_prepare(struct target *target) { - int result, i; + int result; uint8_t fstat; /* wait until busy */ - for (i = 0; i < 50; i++) { + for (unsigned int i = 0; i < 50; i++) { result = target_read_u8(target, FTFx_FSTAT, &fstat); if (result != ERROR_OK) return result; @@ -1343,8 +1340,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, static int kinetis_protect(struct flash_bank *bank, int set, int first, int last) { - int i; - if (allow_fcf_writes) { LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!"); return ERROR_FAIL; @@ -1355,7 +1350,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last return ERROR_FLASH_BANK_INVALID; } - for (i = first; i < bank->num_prot_blocks && i <= last; i++) + for (int i = first; i < bank->num_prot_blocks && i <= last; i++) bank->prot_blocks[i].is_protected = set; LOG_INFO("Protection bits will be written at the next FCF sector erase or write."); @@ -1369,7 +1364,7 @@ static int kinetis_protect_check(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; int result; - int i, b; + int b; uint32_t fprot; if (k_bank->flash_class == FC_PFLASH) { @@ -1397,7 +1392,7 @@ static int kinetis_protect_check(struct flash_bank *bank) } b = k_bank->protection_block; - for (i = 0; i < bank->num_prot_blocks; i++) { + for (int i = 0; i < bank->num_prot_blocks; i++) { if ((fprot >> b) & 1) bank->prot_blocks[i].is_protected = 0; else @@ -1415,8 +1410,6 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) uint32_t fprot = 0xffffffff; uint8_t fsec = 0xfe; /* set MCU unsecure */ uint8_t fdprot = 0xff; - int i; - unsigned bank_idx; unsigned num_blocks; uint32_t pflash_bit; uint8_t dflash_bit; @@ -1432,7 +1425,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) /* iterate over all kinetis banks */ /* current bank is bank 0, it contains FCF */ num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; - for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) { + for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank_iter = k_bank->bank; @@ -1443,8 +1436,10 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) kinetis_auto_probe(bank_iter); + assert(bank_iter->prot_blocks); + if (k_bank->flash_class == FC_PFLASH) { - for (i = 0; i < bank_iter->num_prot_blocks; i++) { + for (int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fprot &= ~pflash_bit; @@ -1452,7 +1447,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) } } else if (k_bank->flash_class == FC_FLEX_NVM) { - for (i = 0; i < bank_iter->num_prot_blocks; i++) { + for (int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fdprot &= ~dflash_bit; @@ -1540,7 +1535,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) static int kinetis_check_run_mode(struct kinetis_chip *k_chip) { - int result, i; + int result; uint8_t pmstat; struct target *target; @@ -1578,7 +1573,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip) if (result != ERROR_OK) return result; - for (i = 100; i; i--) { + for (unsigned int i = 100; i > 0; i--) { result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; @@ -1623,7 +1618,7 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip) static int kinetis_erase(struct flash_bank *bank, int first, int last) { - int result, i; + int result; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; @@ -1644,7 +1639,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) * requested erase is PFlash or NVM and encompasses the entire * block. Should be quicker. */ - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { /* set command and sector address */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, NULL); @@ -1798,6 +1793,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer buffer += size; offset += size; count -= size; + + keep_alive(); } free(buffer_aligned); @@ -1808,25 +1805,26 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - int result, fallback = 0; + int result; + bool fallback = false; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) { /* fallback to longword write */ - fallback = 1; + fallback = true; LOG_INFO("This device supports Program Longword execution only."); } else { result = kinetis_make_ram_ready(bank->target); if (result != ERROR_OK) { - fallback = 1; + fallback = true; LOG_WARNING("FlexRAM not ready, fallback to slow longword write."); } } LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset); - if (fallback == 0) { + if (!fallback) { /* program section command */ kinetis_write_sections(bank, buffer, offset, count); } else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) { @@ -1889,6 +1887,8 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, buffer += 4; offset += 4; words_remaining--; + + keep_alive(); } } free(new_buffer); @@ -2018,7 +2018,6 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned familyid = 0, subfamid = 0; unsigned cpu_mhz = 120; - unsigned idx; bool use_nvm_marking = false; char flash_marking[12], nvm_marking[2]; char name[40]; @@ -2113,7 +2112,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) LOG_ERROR("Unsupported K-family FAMID"); } - for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { + for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { if (kinetis_types_old[idx].sdid == mcu_type) { strcpy(name, kinetis_types_old[idx].name); use_nvm_marking = true; @@ -2619,12 +2618,15 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) static int kinetis_probe(struct flash_bank *bank) { - int result, i; + int result; uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; unsigned num_blocks, first_nvm_bank; uint32_t size_k; struct kinetis_flash_bank *k_bank = bank->driver_priv; - struct kinetis_chip *k_chip = k_bank->k_chip; + struct kinetis_chip *k_chip; + + assert(k_bank); + k_chip = k_bank->k_chip; k_bank->probed = false; @@ -2668,6 +2670,7 @@ static int kinetis_probe(struct flash_bank *bank) if (k_chip->dflash_size == 0) { k_bank->protection_size = 0; } else { + int i; for (i = k_chip->dflash_size; ~i & 1; i >>= 1) ; if (i == 1) @@ -2824,8 +2827,7 @@ static int kinetis_blank_check(struct flash_bank *bank) if (block_dirty) { /* the whole bank is not erased, check sector-by-sector */ - int i; - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { /* normal margin */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT, k_bank->prog_base + bank->sectors[i].offset, @@ -2841,8 +2843,7 @@ static int kinetis_blank_check(struct flash_bank *bank) } } else { /* the whole bank is erased, update all sectors */ - int i; - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; } } else { diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 27b6d3a..cfc0492 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -814,7 +814,7 @@ static int kinetis_ke_protect_check(struct flash_bank *bank) kinfo->protection_size = 0; } else { - LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", \ + LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", fpopen ? 1 : 0, fpldis ? 1 : 0, fphdis ? 1 : 0, fpls, fphs); /* Retrieve which region is protected and how much */ diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index 19d754b..04ac3bb 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -177,8 +177,8 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank) retval = target_alloc_working_area(target, sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm); if (retval != ERROR_OK) { - LOG_ERROR("Insufficient working area to initialize SPIFI "\ - "module. You must allocate at least %zdB of working "\ + LOG_ERROR("Insufficient working area to initialize SPIFI " + "module. You must allocate at least %zdB of working " "area in order to use this driver.", sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE ); @@ -452,7 +452,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last) * it, use a bulk erase instead of going sector-by-sector. */ if (first == 0 && last == (bank->num_sectors - 1) && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) { - LOG_DEBUG("Chip supports the bulk erase command."\ + LOG_DEBUG("Chip supports the bulk erase command." " Will use bulk erase instead of sector-by-sector erase."); retval = lpcspifi_bulk_erase(bank); @@ -525,7 +525,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last) retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code), &erase_algorithm); if (retval != ERROR_OK) { - LOG_ERROR("Insufficient working area. You must configure a working"\ + LOG_ERROR("Insufficient working area. You must configure a working" " area of at least %zdB in order to erase SPIFI flash.", sizeof(lpcspifi_flash_erase_code)); return retval; @@ -685,7 +685,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer, if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code), &write_algorithm) != ERROR_OK) { - LOG_ERROR("Insufficient working area. You must configure"\ + LOG_ERROR("Insufficient working area. You must configure" " a working area > %zdB in order to write to SPIFI flash.", sizeof(lpcspifi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -707,15 +707,15 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer, * space, free the algorithm */ target_free_working_area(target, write_algorithm); - LOG_ERROR("Insufficient working area. Please allocate at least"\ + LOG_ERROR("Insufficient working area. Please allocate at least" " %zdB of working area to enable flash writes.", sizeof(lpcspifi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) - LOG_WARNING("Working area size is limited; flash writes may be"\ - " slow. Increase working area size to at least %zdB"\ + LOG_WARNING("Working area size is limited; flash writes may be" + " slow. Increase working area size to at least %zdB" " to reduce write times.", (size_t)(sizeof(lpcspifi_flash_write_code) + page_size) ); diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index 803e84a..7a06b3d 100644 --- a/src/flash/nor/mrvlqspi.c +++ b/src/flash/nor/mrvlqspi.c @@ -563,7 +563,7 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last) if (first == 0 && last == (bank->num_sectors - 1) && mrvlqspi_info->dev->chip_erase_cmd != mrvlqspi_info->dev->erase_cmd) { - LOG_DEBUG("Chip supports the bulk erase command."\ + LOG_DEBUG("Chip supports the bulk erase command." " Will use bulk erase instead of sector-by-sector erase."); retval = mrvlqspi_bulk_erase(bank); if (retval == ERROR_OK) { @@ -681,7 +681,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code), &write_algorithm) != ERROR_OK) { - LOG_ERROR("Insufficient working area. You must configure"\ + LOG_ERROR("Insufficient working area. You must configure" " a working area > %zdB in order to write to SPIFI flash.", sizeof(mrvlqspi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -703,15 +703,15 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, * space, free the algorithm */ target_free_working_area(target, write_algorithm); - LOG_ERROR("Insufficient working area. Please allocate at least"\ + LOG_ERROR("Insufficient working area. Please allocate at least" " %zdB of working area to enable flash writes.", sizeof(mrvlqspi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) - LOG_WARNING("Working area size is limited; flash writes may be"\ - " slow. Increase working area size to at least %zdB"\ + LOG_WARNING("Working area size is limited; flash writes may be" + " slow. Increase working area size to at least %zdB" " to reduce write times.", (size_t)(sizeof(mrvlqspi_flash_write_code) + page_size) ); diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index e9e4be3..95c99b9 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -49,7 +49,8 @@ struct msp432_bank { int family_type; int device_type; uint32_t sector_length; - bool probed[2]; + bool probed_main; + bool probed_info; bool unlock_bsl; struct working_area *working_area; struct armv7m_algorithm armv7m_info; @@ -194,8 +195,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params return retval; /* Write out command to target memory */ - retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR, - sizeof(command), (uint8_t *)&command); + retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command); return retval; } @@ -210,8 +210,7 @@ static int msp432_wait_return_code(struct target *target) start_ms = timeval_ms(); while ((0 == return_code) || (FLASH_BUSY == return_code)) { - retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR, - sizeof(return_code), (uint8_t *)&return_code); + retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code); if (ERROR_OK != retval) return retval; @@ -253,8 +252,7 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) start_ms = timeval_ms(); while (BUFFER_INACTIVE != status_code) { - retval = target_read_buffer(target, status_addr, sizeof(status_code), - (uint8_t *)&status_code); + retval = target_read_u32(target, status_addr, &status_code); if (ERROR_OK != retval) return retval; @@ -477,15 +475,23 @@ COMMAND_HANDLER(msp432_mass_erase_command) struct flash_bank *bank; struct msp432_bank *msp432_bank; bool all; + int retval; - if (0 == CMD_ARGC) { + if (1 > CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + if (1 == CMD_ARGC) { all = false; - } else if (1 == CMD_ARGC) { + } else if (2 == CMD_ARGC) { /* Check argument for how much to erase */ - if (0 == strcmp(CMD_ARGV[0], "main")) + if (0 == strcmp(CMD_ARGV[1], "main")) all = false; - else if (0 == strcmp(CMD_ARGV[0], "all")) + else if (0 == strcmp(CMD_ARGV[1], "all")) all = true; else return ERROR_COMMAND_SYNTAX_ERROR; @@ -493,10 +499,6 @@ COMMAND_HANDLER(msp432_mass_erase_command) return ERROR_COMMAND_SYNTAX_ERROR; } - retval = get_flash_bank_by_num(0, &bank); - if (ERROR_OK != retval) - return retval; - msp432_bank = bank->driver_priv; if (MSP432E4 == msp432_bank->family_type) { @@ -513,7 +515,7 @@ COMMAND_HANDLER(msp432_mass_erase_command) LOG_INFO("msp432: Mass erase of flash is complete"); } else { LOG_INFO("msp432: Mass erase of %s is complete", - all ? "main + info flash" : "main flash"); + all ? "main + information flash" : "main flash"); } return ERROR_OK; @@ -523,13 +525,14 @@ COMMAND_HANDLER(msp432_bsl_command) { struct flash_bank *bank; struct msp432_bank *msp432_bank; + int retval; - if (1 < CMD_ARGC) + if (1 > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; - retval = get_flash_bank_by_num(0, &bank); - if (ERROR_OK != retval) + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) return retval; msp432_bank = bank->driver_priv; @@ -539,13 +542,16 @@ COMMAND_HANDLER(msp432_bsl_command) return ERROR_OK; } - if (1 == CMD_ARGC) { - if (0 == strcmp(CMD_ARGV[0], "lock")) + if (2 == CMD_ARGC) { + if (0 == strcmp(CMD_ARGV[1], "lock")) msp432_bank->unlock_bsl = false; - else if (0 == strcmp(CMD_ARGV[0], "unlock")) + else if (0 == strcmp(CMD_ARGV[1], "unlock")) msp432_bank->unlock_bsl = true; else return ERROR_COMMAND_SYNTAX_ERROR; + } else if (1 != CMD_ARGC) { + /* Extra, unknown argument passed in */ + return ERROR_COMMAND_SYNTAX_ERROR; } LOG_INFO("msp432: BSL flash region is currently %slocked", @@ -561,6 +567,7 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; + /* Create shared private struct for flash banks */ msp432_bank = malloc(sizeof(struct msp432_bank)); if (NULL == msp432_bank) return ERROR_FAIL; @@ -571,14 +578,14 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) msp432_bank->family_type = MSP432_NO_FAMILY; msp432_bank->device_type = MSP432_NO_TYPE; msp432_bank->sector_length = 0x1000; - msp432_bank->probed[0] = false; - msp432_bank->probed[1] = false; + msp432_bank->probed_main = false; + msp432_bank->probed_info = false; msp432_bank->unlock_bsl = false; msp432_bank->working_area = NULL; - /* Finish initialization of bank 0 (main flash) */ + /* Finish up initial settings here */ bank->driver_priv = msp432_bank; - bank->next = NULL; + bank->base = FLASH_BASE; return ERROR_OK; } @@ -589,6 +596,9 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; + bool is_main = FLASH_BASE == bank->base; + bool is_info = P4_FLASH_INFO_BASE == bank->base; + int retval; if (TARGET_HALTED != target->state) { @@ -597,8 +607,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) } /* Do a mass erase if user requested all sectors of main flash */ - if ((0 == bank->bank_number) && (first == 0) && - (last == (bank->num_sectors - 1))) { + if (is_main && (first == 0) && (last == (bank->num_sectors - 1))) { /* Request mass erase of main flash */ return msp432_mass_erase(bank, false); } @@ -611,7 +620,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) msp432_init_params(&algo_params); /* Adjust params if this is the info bank */ - if (1 == bank->bank_number) { + if (is_info) { buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO); /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) @@ -622,11 +631,11 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) for (int i = first; i <= last; i++) { /* Skip TVL (read-only) sector of the info bank */ - if (1 == bank->bank_number && 1 == i) + if (is_info && 1 == i) continue; /* Skip BSL sectors of info bank if locked */ - if (1 == bank->bank_number && (2 == i || 3 == i) && + if (is_info && (2 == i || 3 == i) && !msp432_bank->unlock_bsl) continue; @@ -666,6 +675,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, long long start_ms; long long elapsed_ms; + bool is_info = P4_FLASH_INFO_BASE == bank->base; + int retval; if (TARGET_HALTED != target->state) { @@ -679,7 +690,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, * The BSL region in sectors 2 and 3 of the info flash may be unlocked * The helper algorithm will hang on attempts to write to TVL */ - if (1 == bank->bank_number) { + if (is_info) { /* Set read-only start to TVL sector */ uint32_t start = 0x1000; /* Set read-only end after BSL region if locked */ @@ -722,7 +733,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, buf_set_u32(algo_params.length, 0, 32, count); /* Check if this is the info bank */ - if (1 == bank->bank_number) { + if (is_info) { /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); @@ -753,8 +764,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, } /* Signal the flash helper algorithm that data is ready to flash */ - retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR, - sizeof(data_ready), (uint8_t *)&data_ready); + retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR, + data_ready); if (ERROR_OK != retval) { (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; @@ -793,20 +804,23 @@ static int msp432_probe(struct flash_bank *bank) struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; - char *name; - uint32_t device_id; uint32_t hardware_rev; - uint32_t base; uint32_t sector_length; uint32_t size; int num_sectors; - int bank_id; + + bool is_main = FLASH_BASE == bank->base; + bool is_info = P4_FLASH_INFO_BASE == bank->base; int retval; - bank_id = bank->bank_number; + /* Check if this bank has already been successfully probed */ + if (is_main && msp432_bank->probed_main) + return ERROR_OK; + if (is_info && msp432_bank->probed_info) + return ERROR_OK; /* Read the flash size register to determine this is a P4 or not */ /* MSP432P4s will return the size of flash. MSP432E4s will return zero */ @@ -849,63 +863,16 @@ static int msp432_probe(struct flash_bank *bank) msp432_bank->device_type = msp432_device_type(msp432_bank->family_type, msp432_bank->device_id, msp432_bank->hardware_rev); - /* If not already allocated, create the info bank for MSP432P4 */ - /* We could not determine it was needed until device was probed */ - if (MSP432P4 == msp432_bank->family_type) { - /* If we've been given bank 1, then this was already done */ - if (0 == bank_id) { - /* And only allocate it if it doesn't exist yet */ - if (NULL == bank->next) { - struct flash_bank *info_bank; - info_bank = malloc(sizeof(struct flash_bank)); - if (NULL == info_bank) - return ERROR_FAIL; - - name = malloc(strlen(bank->name)+1); - if (NULL == name) { - free(info_bank); - return ERROR_FAIL; - } - strcpy(name, bank->name); - - /* Initialize bank 1 (info region) */ - info_bank->name = name; - info_bank->target = bank->target; - info_bank->driver = bank->driver; - info_bank->driver_priv = bank->driver_priv; - info_bank->bank_number = 1; - info_bank->base = 0x00200000; - info_bank->size = 0; - info_bank->chip_width = 0; - info_bank->bus_width = 0; - info_bank->erased_value = 0xff; - info_bank->default_padded_value = 0xff; - info_bank->write_start_alignment = 0; - info_bank->write_end_alignment = 0; - info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR; - info_bank->num_sectors = 0; - info_bank->sectors = NULL; - info_bank->num_prot_blocks = 0; - info_bank->prot_blocks = NULL; - info_bank->next = NULL; - - /* Enable the new bank */ - bank->next = info_bank; - } - } - } - if (MSP432P4 == msp432_bank->family_type) { /* Set up MSP432P4 specific flash parameters */ - if (0 == bank_id) { + if (is_main) { retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); if (ERROR_OK != retval) return retval; - base = P4_FLASH_MAIN_BASE; sector_length = P4_SECTOR_LENGTH; num_sectors = size / sector_length; - } else if (1 == bank_id) { + } else if (is_info) { if (msp432_bank->device_type == MSP432P411X || msp432_bank->device_type == MSP432P411X_GUESS) { /* MSP432P411x has an info size register, use that for size */ @@ -916,19 +883,22 @@ static int msp432_probe(struct flash_bank *bank) /* All other MSP432P401x devices have fixed info region size */ size = 0x4000; /* 16 KB info region */ } - base = P4_FLASH_INFO_BASE; sector_length = P4_SECTOR_LENGTH; num_sectors = size / sector_length; } else { - /* Invalid bank number somehow */ + /* Invalid bank somehow */ return ERROR_FAIL; } } else { /* Set up MSP432E4 specific flash parameters */ - base = E4_FLASH_BASE; - size = E4_FLASH_SIZE; - sector_length = E4_SECTOR_LENGTH; - num_sectors = size / sector_length; + if (is_main) { + size = E4_FLASH_SIZE; + sector_length = E4_SECTOR_LENGTH; + num_sectors = size / sector_length; + } else { + /* Invalid bank somehow */ + return ERROR_FAIL; + } } if (NULL != bank->sectors) { @@ -936,11 +906,12 @@ static int msp432_probe(struct flash_bank *bank) bank->sectors = NULL; } - bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - if (NULL == bank->sectors) - return ERROR_FAIL; + if (num_sectors > 0) { + bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); + if (NULL == bank->sectors) + return ERROR_FAIL; + } - bank->base = base; bank->size = size; bank->write_start_alignment = 0; bank->write_end_alignment = 0; @@ -955,7 +926,31 @@ static int msp432_probe(struct flash_bank *bank) } /* We've successfully determined the stats on this flash bank */ - msp432_bank->probed[bank_id] = true; + if (is_main) + msp432_bank->probed_main = true; + if (is_info) + msp432_bank->probed_info = true; + + if (is_main && MSP432P4 == msp432_bank->family_type) { + /* Create the info flash bank needed by MSP432P4 variants */ + struct flash_bank *info = calloc(sizeof(struct flash_bank), 1); + if (NULL == info) + return ERROR_FAIL; + + /* Create a name for the info bank, append "_1" to main name */ + char *name = malloc(strlen(bank->name) + 3); + strcpy(name, bank->name); + strcat(name, "_1"); + + /* Initialize info bank */ + info->name = name; + info->target = bank->target; + info->driver = bank->driver; + info->driver_priv = msp432_bank; + info->base = P4_FLASH_INFO_BASE; + + flash_bank_add(info); + } /* If we fall through to here, then all went well */ @@ -966,15 +961,17 @@ static int msp432_auto_probe(struct flash_bank *bank) { struct msp432_bank *msp432_bank = bank->driver_priv; - int retval = ERROR_OK; + bool is_main = FLASH_BASE == bank->base; + bool is_info = P4_FLASH_INFO_BASE == bank->base; - if (bank->bank_number < 0 || bank->bank_number > 1) { - /* Invalid bank number somehow */ - return ERROR_FAIL; - } + int retval = ERROR_OK; - if (!msp432_bank->probed[bank->bank_number]) - retval = msp432_probe(bank); + if (is_main) + if (!msp432_bank->probed_main) + retval = msp432_probe(bank); + if (is_info) + if (!msp432_bank->probed_info) + retval = msp432_probe(bank); return retval; } @@ -1036,12 +1033,21 @@ static int msp432_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } +static int msp432_protect_check(struct flash_bank *bank) +{ + /* Added to suppress warning, not needed for MSP432 flash */ + return ERROR_OK; +} + static void msp432_flash_free_driver_priv(struct flash_bank *bank) { + bool is_main = FLASH_BASE == bank->base; + /* A single private struct is shared between main and info banks */ - /* Only free it on the call for main bank (#0) */ - if ((0 == bank->bank_number) && (NULL != bank->driver_priv)) + /* Only free it on the call for main bank */ + if (is_main && (NULL != bank->driver_priv)) free(bank->driver_priv); + /* Forget about the private struct on both main and info banks */ bank->driver_priv = NULL; } @@ -1052,14 +1058,14 @@ static const struct command_registration msp432_exec_command_handlers[] = { .handler = msp432_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire flash memory on device.", - .usage = "['main' | 'all']", + .usage = "bank_id ['main' | 'all']", }, { .name = "bsl", .handler = msp432_bsl_command, .mode = COMMAND_EXEC, .help = "Allow BSL to be erased or written by flash commands.", - .usage = "['unlock' | 'lock']", + .usage = "bank_id ['unlock' | 'lock']", }, COMMAND_REGISTRATION_DONE }; @@ -1085,6 +1091,7 @@ const struct flash_driver msp432_flash = { .probe = msp432_probe, .auto_probe = msp432_auto_probe, .erase_check = default_flash_blank_check, + .protect_check = msp432_protect_check, .info = msp432_info, .free_driver_priv = msp432_flash_free_driver_priv, }; diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h index ffefa8f..663393b 100644 --- a/src/flash/nor/msp432.h +++ b/src/flash/nor/msp432.h @@ -34,14 +34,17 @@ #define MSP432E411Y 7 /* MSP432E401Y device */ #define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */ +/* Common MSP432 flash parameters */ +#define FLASH_BASE 0x00000000 + /* MSP432P4 flash parameters */ -#define P4_FLASH_MAIN_BASE 0x00000000 +#define P4_FLASH_MAIN_BASE FLASH_BASE #define P4_FLASH_INFO_BASE 0x00200000 #define P4_SECTOR_LENGTH 0x1000 #define P4_ALGO_ENTRY_ADDR 0x01000110 /* MSP432E4 flash paramters */ -#define E4_FLASH_BASE 0x00000000 +#define E4_FLASH_BASE FLASH_BASE #define E4_FLASH_SIZE 0x100000 #define E4_SECTOR_LENGTH 0x4000 #define E4_ALGO_ENTRY_ADDR 0x20000110 diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 4041bfb..fa67e2b 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -28,6 +28,10 @@ #include <helper/types.h> #include <helper/time_support.h> +/* Both those values are constant across the current spectrum ofr nRF5 devices */ +#define WATCHDOG_REFRESH_REGISTER 0x40010600 +#define WATCHDOG_REFRESH_VALUE 0x6e524635 + enum { NRF5_FLASH_BASE = 0x00000000, }; @@ -39,13 +43,15 @@ enum nrf5_ficr_registers { 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), + + NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028), + NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C), + NRF51_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), + NRF51_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), + NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), + NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), + NRF51_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), @@ -60,36 +66,42 @@ enum nrf5_ficr_registers { 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), + + NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), + NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), + NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), + NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), + NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), + NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), + NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), + NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), + NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), + NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), + NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), + + /* Following registers are available on nRF52 and on nRF51 since rev 3 */ + NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100), + NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104), + NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108), + NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C), + NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110), }; enum nrf5_uicr_registers { NRF5_UICR_BASE = 0x10001000, /* User Information * Configuration Regsters */ - NRF5_UICR_SIZE = 0x100, - #define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) - 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), + NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000), + NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004), + NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008), + NRF51_UICR_FWID = NRF5_UICR_REG(0x010), }; enum nrf5_nvmc_registers { NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory - * Controller Regsters */ + * Controller Registers */ #define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) @@ -98,6 +110,8 @@ enum nrf5_nvmc_registers { NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), + + NRF5_BPROT_BASE = 0x40000000, }; enum nrf5_nvmc_config_bits { @@ -107,17 +121,19 @@ enum nrf5_nvmc_config_bits { }; -struct nrf5_info { - uint32_t code_page_size; - uint32_t refcount; +struct nrf52_ficr_info { + uint32_t part; + uint32_t variant; + uint32_t package; + uint32_t ram; + uint32_t flash; +}; - struct { - bool probed; - int (*write) (struct flash_bank *bank, - struct nrf5_info *chip, - const uint8_t *buffer, uint32_t offset, uint32_t count); - } bank[2]; - struct target *target; +enum nrf5_features { + NRF5_FEATURE_SERIES_51 = 1 << 0, + NRF5_FEATURE_SERIES_52 = 1 << 1, + NRF5_FEATURE_BPROT = 1 << 2, + NRF5_FEATURE_ACL_PROT = 1 << 3, }; struct nrf5_device_spec { @@ -126,22 +142,58 @@ struct nrf5_device_spec { const char *variant; const char *build_code; unsigned int flash_size_kb; + enum nrf5_features features; }; -#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \ +struct nrf5_info { + uint32_t refcount; + + struct nrf5_bank { + struct nrf5_info *chip; + bool probed; + } bank[2]; + struct target *target; + + /* chip identification stored in nrf5_probe() for use in nrf5_info() */ + bool ficr_info_valid; + struct nrf52_ficr_info ficr_info; + const struct nrf5_device_spec *spec; + uint32_t hwid; + enum nrf5_features features; + unsigned int flash_size_kb; + unsigned int ram_size_kb; +}; + +#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ { \ .hwid = (id), \ .part = pt, \ .variant = var, \ .build_code = bcode, \ .flash_size_kb = (fsize), \ +.features = NRF5_FEATURE_SERIES_51, \ } -/* 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: +#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \ +{ \ +.hwid = (id), \ +.part = pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +.features = features, \ +} + +/* The known devices table below is derived from the "nRF5x series + * compatibility matrix" documents, which can be found in the "DocLib" of + * nordic: * - * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51 + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview * * Up to date with Matrix v2.0, plus some additional HWIDs. * @@ -151,79 +203,99 @@ struct nrf5_device_spec { */ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - 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), + NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* 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. */ - NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), + NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), /* nRF51822 Devices (IC rev 2). */ - 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), + NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), - NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 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), - NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), + NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF51_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256), + NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), + NRF51_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), /* nRF51422 Devices (IC rev 1). */ - NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), - NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), - NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), + NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - 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), + NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - 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), - + NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + + /* The driver fully autodects nRF52 series devices by FICR INFO, + * no need for nRF52xxx HWIDs in this table */ +#if 0 /* nRF52810 Devices */ - NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192), - NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192), + NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), + NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), /* nRF52832 Devices */ - NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), - NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512), - NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512), + NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), + NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), + NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), /* nRF52840 Devices */ - NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024), + NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT), +#endif +}; + +struct nrf5_device_package { + uint32_t package; + const char *code; }; +/* Newer devices have FICR INFO.PACKAGE. + * This table converts its value to two character code */ +static const struct nrf5_device_package nrf5_packages_table[] = { + { 0x2000, "QF" }, + { 0x2001, "CH" }, + { 0x2002, "CI" }, + { 0x2005, "CK" }, +}; + +const struct flash_driver nrf5_flash, nrf51_flash; + static int nrf5_bank_is_probed(struct flash_bank *bank) { - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; - assert(chip != NULL); + assert(nbank != NULL); - return chip->bank[bank->bank_number].probed; + return nbank->probed; } static int nrf5_probe(struct flash_bank *bank); @@ -234,7 +306,8 @@ static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_i return ERROR_TARGET_NOT_HALTED; } - *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; + *chip = nbank->chip; int probed = nrf5_bank_is_probed(bank); if (probed < 0) @@ -367,6 +440,33 @@ error: return ERROR_FAIL; } +static int nrf5_protect_check_bprot(struct flash_bank *bank) +{ + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + + assert(chip != NULL); + + static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; + uint32_t bprot_reg = 0; + int res; + + for (int i = 0; i < bank->num_sectors; i++) { + unsigned int bit = i % 32; + if (bit == 0) { + unsigned int n_reg = i / 32; + if (n_reg >= ARRAY_SIZE(nrf5_bprot_offsets)) + break; + + res = target_read_u32(chip->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg); + if (res != ERROR_OK) + return res; + } + bank->sectors[i].is_protected = (bprot_reg & (1 << bit)) ? 1 : 0; + } + return ERROR_OK; +} + static int nrf5_protect_check(struct flash_bank *bank) { int res; @@ -376,11 +476,20 @@ static int nrf5_protect_check(struct flash_bank *bank) if (bank->base == NRF5_UICR_BASE) return ERROR_OK; - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; assert(chip != NULL); - res = target_read_u32(chip->target, NRF5_FICR_CLENR0, + if (chip->features & NRF5_FEATURE_BPROT) + return nrf5_protect_check_bprot(bank); + + if (!(chip->features & NRF5_FEATURE_SERIES_51)) { + LOG_WARNING("Flash protection of this nRF device is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + res = target_read_u32(chip->target, NRF51_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); @@ -388,7 +497,7 @@ static int nrf5_protect_check(struct flash_bank *bank) } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF5_UICR_CLENR0, + res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -417,12 +526,17 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) if (res != ERROR_OK) return res; + if (!(chip->features & NRF5_FEATURE_SERIES_51)) { + LOG_ERROR("Flash protection setting of this nRF device is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + if (first != 0) { LOG_ERROR("Code region 0 must start at the begining of the bank"); return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF5_FICR_PPFC, + res = target_read_u32(chip->target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -434,7 +548,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF5_UICR_CLENR0, + res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -442,7 +556,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) } if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF5_UICR_CLENR0, + res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't write code region 0 size[UICR]"); @@ -458,93 +572,266 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_OK; } -static int nrf5_probe(struct flash_bank *bank) +static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) { - uint32_t hwid; + uint8_t b[4]; + + h_u32_to_be(b, variant); + if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) { + memcpy(bf, b, 4); + bf[4] = 0; + return true; + } + + strcpy(bf, "xxxx"); + return false; +} + +static const char *nrf5_decode_info_package(uint32_t package) +{ + for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) { + if (nrf5_packages_table[i].package == package) + return nrf5_packages_table[i].code; + } + return "xx"; +} + +static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; int res; - struct nrf5_info *chip = bank->driver_priv; - res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid); + if (chip->spec) { + res = snprintf(buf, buf_size, + "nRF%s-%s(build code: %s)", + chip->spec->part, chip->spec->variant, chip->spec->build_code); + + } else if (chip->ficr_info_valid) { + char variant[5]; + nrf5_info_variant_to_str(chip->ficr_info.variant, variant); + res = snprintf(buf, buf_size, + "nRF%" PRIx32 "-%s%.2s(build code: %s)", + chip->ficr_info.part, + nrf5_decode_info_package(chip->ficr_info.package), + variant, &variant[2]); + + } else { + res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")", + chip->hwid); + } + if (res <= 0) + return ERROR_FAIL; + + snprintf(buf + res, buf_size - res, " %ukB Flash, %ukB RAM", + chip->flash_size_kb, chip->ram_size_kb); + return ERROR_OK; +} + +static int nrf5_read_ficr_info(struct nrf5_info *chip) +{ + int res; + struct target *target = chip->target; + + chip->ficr_info_valid = false; + + res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part); if (res != ERROR_OK) { - LOG_ERROR("Couldn't read CONFIGID register"); + LOG_DEBUG("Couldn't read FICR INFO.PART register"); return res; } - hwid &= 0xFFFF; /* HWID is stored in the lower two - * bytes of the CONFIGID register */ + uint32_t series = chip->ficr_info.part & 0xfffff000; + switch (series) { + case 0x51000: + chip->features = NRF5_FEATURE_SERIES_51; + break; - 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]; + case 0x52000: + chip->features = NRF5_FEATURE_SERIES_52; + + switch (chip->ficr_info.part) { + case 0x52810: + case 0x52832: + chip->features |= NRF5_FEATURE_BPROT; + break; + + case 0x52840: + chip->features |= NRF5_FEATURE_ACL_PROT; break; } + break; + + default: + LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08" + PRIx32, chip->ficr_info.part); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - if (!chip->bank[0].probed && !chip->bank[1].probed) { - if (spec) - LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash", - spec->part, spec->variant, spec->build_code, - spec->flash_size_kb); - else - LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid); + /* Now we know the device has FICR INFO filled by something relevant: + * Although it is not documented, the tested nRF51 rev 3 devices + * have FICR INFO.PART, RAM and FLASH of the same format as nRF52. + * VARIANT and PACKAGE coding is unknown for a nRF51 device. + * nRF52 devices have FICR INFO documented and always filled. */ + + res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant); + if (res != ERROR_OK) + return res; + + res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package); + if (res != ERROR_OK) + return res; + + res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram); + if (res != ERROR_OK) + return res; + + res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash); + if (res != ERROR_OK) + return res; + + chip->ficr_info_valid = true; + return ERROR_OK; +} + +static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) +{ + int res; + + *ram_size = 0; + + uint32_t numramblock; + res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock); + if (res != ERROR_OK) { + LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); + return res; } - 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 (numramblock < 1 || numramblock > 4) { + LOG_DEBUG("FICR NUMRAMBLOCK strange value %" PRIx32, numramblock); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + for (unsigned int i = 0; i < numramblock; i++) { + uint32_t sizeramblock; + res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock); if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code page size"); + LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); return res; } + if (sizeramblock < 1024 || sizeramblock > 65536) + LOG_DEBUG("FICR SIZERAMBLOCK strange value %" PRIx32, sizeramblock); + else + *ram_size += sizeramblock; + } + return res; +} - /* Note the register name is misleading, - * 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, NRF5_FICR_CODESIZE, &num_sectors); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code memory size"); - return res; +static int nrf5_probe(struct flash_bank *bank) +{ + int res; + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + struct target *target = chip->target; + + res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read CONFIGID register"); + return res; + } + + chip->hwid &= 0xFFFF; /* HWID is stored in the lower two + * bytes of the CONFIGID register */ + + /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ + chip->features = NRF5_FEATURE_SERIES_51; + + /* Don't bail out on error for the case that some old engineering + * sample has FICR INFO registers unreadable. We can proceed anyway. */ + (void)nrf5_read_ficr_info(chip); + + chip->spec = NULL; + for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { + if (chip->hwid == nrf5_known_devices_table[i].hwid) { + chip->spec = &nrf5_known_devices_table[i]; + chip->features = chip->spec->features; + break; } + } - bank->num_sectors = num_sectors; - bank->size = num_sectors * chip->code_page_size; + if (chip->spec && chip->ficr_info_valid) { + /* check if HWID table gives the same part as FICR INFO */ + if (chip->ficr_info.part != strtoul(chip->spec->part, NULL, 16)) + LOG_WARNING("HWID 0x%04" PRIx32 " mismatch: FICR INFO.PART %" + PRIx32, chip->hwid, chip->ficr_info.part); + } - if (spec && bank->size / 1024 != spec->flash_size_kb) - LOG_WARNING("Chip's reported Flash capacity does not match expected one"); + if (chip->ficr_info_valid) { + chip->ram_size_kb = chip->ficr_info.ram; + } else { + uint32_t ram_size; + nrf5_get_ram_size(target, &ram_size); + chip->ram_size_kb = ram_size / 1024; + } - bank->sectors = calloc(bank->num_sectors, - sizeof((bank->sectors)[0])); - if (!bank->sectors) - return ERROR_FLASH_BANK_NOT_PROBED; + /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + uint32_t flash_page_size; + res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, + &flash_page_size); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code page size"); + return res; + } + + /* Note the register name is misleading, + * 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, NRF5_FICR_CODESIZE, &num_sectors); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code memory size"); + return res; + } - /* 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; - bank->sectors[i].offset = i * chip->code_page_size; + chip->flash_size_kb = num_sectors * flash_page_size / 1024; - /* mark as unknown */ - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = -1; + if (!chip->bank[0].probed && !chip->bank[1].probed) { + char buf[80]; + nrf5_info(bank, buf, sizeof(buf)); + if (!chip->spec && !chip->ficr_info_valid) { + LOG_INFO("Unknown device: %s", buf); + } else { + LOG_INFO("%s", buf); } + } + + free(bank->sectors); + + if (bank->base == NRF5_FLASH_BASE) { + /* Sanity check */ + if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) + LOG_WARNING("Chip's reported Flash capacity does not match expected one"); + if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash) + LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH"); + + bank->num_sectors = num_sectors; + bank->size = num_sectors * flash_page_size; + + bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + if (!bank->sectors) + return ERROR_FAIL; nrf5_protect_check(bank); chip->bank[0].probed = true; + } else { - bank->size = NRF5_UICR_SIZE; bank->num_sectors = 1; - bank->sectors = calloc(bank->num_sectors, - sizeof((bank->sectors)[0])); - if (!bank->sectors) - return ERROR_FLASH_BANK_NOT_PROBED; + bank->size = flash_page_size; - bank->sectors[0].size = bank->size; - bank->sectors[0].offset = 0; + bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + if (!bank->sectors) + return ERROR_FAIL; - bank->sectors[0].is_erased = 0; bank->sectors[0].is_protected = 0; chip->bank[1].probed = true; @@ -580,29 +867,27 @@ static int nrf5_erase_page(struct flash_bank *bank, int res; LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset); - if (sector->is_protected) { - LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset); - return ERROR_FAIL; - } if (bank->base == NRF5_UICR_BASE) { - uint32_t ppfc; - res = target_read_u32(chip->target, NRF5_FICR_PPFC, + if (chip->features & NRF5_FEATURE_SERIES_51) { + uint32_t ppfc; + res = target_read_u32(chip->target, NRF51_FICR_PPFC, &ppfc); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read PPFC register"); - return res; - } - - if ((ppfc & 0xFF) == 0xFF) { - /* We can't erase the UICR. Double-check to - see if it's already erased before complaining. */ - default_flash_blank_check(bank); - if (sector->is_erased == 1) - return ERROR_OK; - - LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); - return ERROR_FAIL; + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read PPFC register"); + return res; + } + + if ((ppfc & 0xFF) == 0xFF) { + /* We can't erase the UICR. Double-check to + see if it's already erased before complaining. */ + default_flash_blank_check(bank); + if (sector->is_erased == 1) + return ERROR_OK; + + LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); + return ERROR_FAIL; + } } res = nrf5_nvmc_generic_erase(chip, @@ -619,44 +904,22 @@ static int nrf5_erase_page(struct flash_bank *bank, return res; } -static const uint8_t nrf5_flash_write_code[] = { - /* See contrib/loaders/flash/cortex-m0.S */ -/* <wait_fifo>: */ - 0x0d, 0x68, /* ldr r5, [r1, #0] */ - 0x00, 0x2d, /* cmp r5, #0 */ - 0x0b, 0xd0, /* beq.n 1e <exit> */ - 0x4c, 0x68, /* ldr r4, [r1, #4] */ - 0xac, 0x42, /* cmp r4, r5 */ - 0xf9, 0xd0, /* beq.n 0 <wait_fifo> */ - 0x20, 0xcc, /* ldmia r4!, {r5} */ - 0x20, 0xc3, /* stmia r3!, {r5} */ - 0x94, 0x42, /* cmp r4, r2 */ - 0x01, 0xd3, /* bcc.n 18 <no_wrap> */ - 0x0c, 0x46, /* mov r4, r1 */ - 0x08, 0x34, /* adds r4, #8 */ -/* <no_wrap>: */ - 0x4c, 0x60, /* str r4, [r1, #4] */ - 0x04, 0x38, /* subs r0, #4 */ - 0xf0, 0xd1, /* bne.n 0 <wait_fifo> */ -/* <exit>: */ - 0x00, 0xbe /* bkpt 0x0000 */ -}; - - /* Start a low level flash write for the specified region */ -static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) +static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, 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 = NRF5_FLASH_BASE + offset; - struct reg_param reg_params[4]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; + static const uint8_t nrf5_flash_write_code[] = { +#include "../../../contrib/loaders/flash/nrf5/nrf5.inc" + }; - LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes); + LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes); assert(bytes % 4 == 0); /* allocate working area with flash programming code */ @@ -665,7 +928,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui LOG_WARNING("no working area available, falling back to slow memory writes"); for (; bytes > 0; bytes -= 4) { - retval = target_write_memory(chip->target, offset, 4, 1, buffer); + retval = target_write_memory(target, address, 4, 1, buffer); if (retval != ERROR_OK) return retval; @@ -673,17 +936,13 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui if (retval != ERROR_OK) return retval; - offset += 4; + address += 4; buffer += 4; } return ERROR_OK; } - 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/nrf52.cfg to disable it"); - retval = target_write_buffer(target, write_algorithm->address, sizeof(nrf5_flash_write_code), nrf5_flash_write_code); @@ -710,15 +969,19 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */ + init_reg_param(®_params[4], "r6", 32, PARAM_OUT); /* watchdog refresh value */ + init_reg_param(®_params[5], "r7", 32, PARAM_OUT); /* watchdog refresh register address */ buf_set_u32(reg_params[0].value, 0, 32, bytes); buf_set_u32(reg_params[1].value, 0, 32, source->address); buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[3].value, 0, 32, address); + buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE); + buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER); retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, 0, NULL, - 4, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -730,26 +993,29 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); return retval; } -/* Check and erase flash sectors in specified range then start a low level page write. - start/end must be sector aligned. -*/ -static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) +static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) { - int res = ERROR_FAIL; - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_info *chip; - assert(start % chip->code_page_size == 0); - assert(end % chip->code_page_size == 0); + int res = nrf5_get_probed_chip_if_halted(bank, &chip); + if (res != ERROR_OK) + return res; + + assert(offset % 4 == 0); + assert(count % 4 == 0); res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; - res = nrf5_ll_flash_write(chip, start, buffer, (end - start)); + res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count); if (res != ERROR_OK) goto error; @@ -777,139 +1043,57 @@ static int nrf5_erase(struct flash_bank *bank, int first, int last) return res; } -static int nrf5_code_flash_write(struct flash_bank *bank, - struct nrf5_info *chip, - const uint8_t *buffer, uint32_t offset, uint32_t count) -{ - - int res; - /* Need to perform reads to fill any gaps we need to preserve in the first page, - before the start of buffer, or in the last page, after the end of buffer */ - uint32_t first_page = offset/chip->code_page_size; - uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size); - - uint32_t first_page_offset = first_page * chip->code_page_size; - uint32_t last_page_offset = last_page * chip->code_page_size; - - LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32, - offset, offset+count, first_page_offset, last_page_offset); - - uint32_t page_cnt = last_page - first_page; - uint8_t buffer_to_flash[page_cnt*chip->code_page_size]; - - /* Fill in any space between start of first page and start of buffer */ - uint32_t pre = offset - first_page_offset; - if (pre > 0) { - res = target_read_memory(bank->target, - first_page_offset, - 1, - pre, - buffer_to_flash); - if (res != ERROR_OK) - return res; - } - - /* Fill in main contents of buffer */ - memcpy(buffer_to_flash+pre, buffer, count); - - /* Fill in any space between end of buffer and end of last page */ - uint32_t post = last_page_offset - (offset+count); - if (post > 0) { - /* Retrieve the full row contents from Flash */ - res = target_read_memory(bank->target, - offset + count, - 1, - post, - buffer_to_flash+pre+count); - if (res != ERROR_OK) - return res; - } - - return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); -} - -static int nrf5_uicr_flash_write(struct flash_bank *bank, - struct nrf5_info *chip, - const uint8_t *buffer, uint32_t offset, uint32_t count) +static void nrf5_free_driver_priv(struct flash_bank *bank) { - int res; - uint8_t uicr[NRF5_UICR_SIZE]; - struct flash_sector *sector = &bank->sectors[0]; - - if ((offset + count) > NRF5_UICR_SIZE) - return ERROR_FAIL; - - res = target_read_memory(bank->target, - NRF5_UICR_BASE, - 1, - NRF5_UICR_SIZE, - uicr); - - if (res != ERROR_OK) - return res; - - res = nrf5_erase_page(bank, chip, sector); - if (res != ERROR_OK) - return res; - - res = nrf5_nvmc_write_enable(chip); - if (res != ERROR_OK) - return res; - - memcpy(&uicr[offset], buffer, count); + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + if (chip == NULL) + return; - res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE); - if (res != ERROR_OK) { - nrf5_nvmc_read_only(chip); - return res; + chip->refcount--; + if (chip->refcount == 0) { + free(chip); + bank->driver_priv = NULL; } - - return nrf5_nvmc_read_only(chip); } - -static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) +static struct nrf5_info *nrf5_get_chip(struct target *target) { - int res; - struct nrf5_info *chip; + struct flash_bank *bank_iter; - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; + /* iterate over nrf5 banks of same target */ + for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { + if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash) + continue; - return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count); -} + if (bank_iter->target != target) + continue; -static void nrf5_free_driver_priv(struct flash_bank *bank) -{ - struct nrf5_info *chip = bank->driver_priv; - if (chip == NULL) - return; + struct nrf5_bank *nbank = bank_iter->driver_priv; + if (!nbank) + continue; - chip->refcount--; - if (chip->refcount == 0) { - free(chip); - bank->driver_priv = NULL; + if (nbank->chip) + return nbank->chip; } + return NULL; } FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { - static struct nrf5_info *chip; + struct nrf5_info *chip; + struct nrf5_bank *nbank = NULL; switch (bank->base) { case NRF5_FLASH_BASE: - bank->bank_number = 0; - break; case NRF5_UICR_BASE: - bank->bank_number = 1; break; default: LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } + chip = nrf5_get_chip(bank->target); if (!chip) { /* Create a new chip */ chip = calloc(1, sizeof(*chip)); @@ -921,16 +1105,19 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) switch (bank->base) { case NRF5_FLASH_BASE: - chip->bank[bank->bank_number].write = nrf5_code_flash_write; + nbank = &chip->bank[0]; break; case NRF5_UICR_BASE: - chip->bank[bank->bank_number].write = nrf5_uicr_flash_write; + nbank = &chip->bank[1]; break; } + assert(nbank != NULL); chip->refcount++; - chip->bank[bank->bank_number].probed = false; - bank->driver_priv = chip; + nbank->chip = chip; + nbank->probed = false; + bank->driver_priv = nbank; + bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; } @@ -953,19 +1140,20 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) if (res != ERROR_OK) return res; - uint32_t ppfc; - - res = target_read_u32(target, NRF5_FICR_PPFC, + if (chip->features & NRF5_FEATURE_SERIES_51) { + uint32_t ppfc; + res = target_read_u32(target, NRF51_FICR_PPFC, &ppfc); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read PPFC register"); - return res; - } + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read PPFC register"); + return res; + } - if ((ppfc & 0xFF) == 0x00) { - LOG_ERROR("Code region 0 size was pre-programmed at the factory, " - "mass erase command won't work."); - return ERROR_FAIL; + if ((ppfc & 0xFF) == 0x00) { + LOG_ERROR("Code region 0 size was pre-programmed at the factory, " + "mass erase command won't work."); + return ERROR_FAIL; + } } res = nrf5_erase_all(chip); @@ -988,9 +1176,17 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) return ERROR_OK; } -static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) +COMMAND_HANDLER(nrf5_handle_info_command) { int res; + struct flash_bank *bank = NULL; + struct target *target = get_current_target(CMD_CTX); + + res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); + if (res != ERROR_OK) + return res; + + assert(bank != NULL); struct nrf5_info *chip; @@ -1004,13 +1200,13 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) } ficr[] = { { .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 = 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 = NRF5_FICR_CONFIGID }, { .address = NRF5_FICR_DEVICEID0 }, { .address = NRF5_FICR_DEVICEID1 }, @@ -1025,22 +1221,22 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) { .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 }, + { .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 }, }, uicr[] = { - { .address = NRF5_UICR_CLENR0, }, - { .address = NRF5_UICR_RBPCONF }, - { .address = NRF5_UICR_XTALFREQ }, - { .address = NRF5_UICR_FWID }, + { .address = NRF51_UICR_CLENR0, }, + { .address = NRF51_UICR_RBPCONF }, + { .address = NRF51_UICR_XTALFREQ }, + { .address = NRF51_UICR_FWID }, }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { @@ -1061,7 +1257,7 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) } } - snprintf(buf, buf_size, + command_print(CMD, "\n[factory information control block]\n\n" "code page size: %"PRIu32"B\n" "code memory size: %"PRIu32"kB\n" @@ -1120,6 +1316,13 @@ static const struct command_registration nrf5_exec_command_handlers[] = { .help = "Erase all flash contents of the chip.", .usage = "", }, + { + .name = "info", + .handler = nrf5_handle_info_command, + .mode = COMMAND_EXEC, + .help = "Show FICR and UICR info.", + .usage = "", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index c62af04..a485282 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -1216,7 +1216,7 @@ static int numicro_init_isp(struct target *target) return ERROR_OK; } -static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t* rdata) +static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata) { uint32_t timeout, status; int retval = ERROR_OK; @@ -1548,7 +1548,6 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, { struct target *target = bank->target; uint32_t timeout, status; - uint8_t *new_buffer = NULL; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { @@ -1566,20 +1565,8 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; - if (count & 0x3) { - uint32_t old_count = count; - count = (old_count | 3) + 1; - new_buffer = malloc(count); - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory " - "for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write (%d), extending to %d " - "and padding with 0xff", old_count, count); - memset(new_buffer, 0xff, count); - buffer = memcpy(new_buffer, buffer, old_count); - } + assert(offset % 4 == 0); + assert(count % 4 == 0); uint32_t words_remaining = count / 4; @@ -1597,13 +1584,10 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, LOG_DEBUG("write longword @ %08X", offset + i); - uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff}; - memcpy(padding, buffer + i, MIN(4, count-i)); - retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, padding); + retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); @@ -1649,7 +1633,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_OK; } -static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type** cpu) +static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu) { uint32_t part_id; int retval = ERROR_OK; @@ -1663,7 +1647,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_ LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id); /* search part numbers */ - for (size_t i = 0; i < sizeof(NuMicroParts)/sizeof(NuMicroParts[0]); i++) { + for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) { if (part_id == NuMicroParts[i].partid) { *cpu = &NuMicroParts[i]; LOG_INFO("Device Name: %s", (*cpu)->partname); @@ -1754,6 +1738,7 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command) memset(bank_info, 0, sizeof(struct numicro_flash_bank)); bank->driver_priv = bank_info; + bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 386075e..a8f8d3f 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -108,7 +108,7 @@ static const struct row_region safe_sflash_regions[] = { {0x16007C00, 0x400}, /* SFLASH: TOC2 */ }; -#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0])) +#define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions) static struct working_area *g_stack_area; static struct armv7m_algorithm g_armv7m_info; @@ -481,20 +481,15 @@ static const char *protection_to_str(uint8_t protection) switch (protection) { case PROTECTION_VIRGIN: return "VIRGIN"; - break; case PROTECTION_NORMAL: return "NORMAL"; - break; case PROTECTION_SECURE: return "SECURE"; - break; case PROTECTION_DEAD: return "DEAD"; - break; case PROTECTION_UNKNOWN: default: return "UNKNOWN"; - break; } } diff --git a/src/flash/nor/renesas_rpchf.c b/src/flash/nor/renesas_rpchf.c new file mode 100644 index 0000000..3f03f92 --- /dev/null +++ b/src/flash/nor/renesas_rpchf.c @@ -0,0 +1,648 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Renesas RCar Gen3 RPC Hyperflash driver + * Based on U-Boot RPC Hyperflash driver + * + * Copyright (C) 2016 Renesas Electronics Corporation + * Copyright (C) 2016 Cogent Embedded, Inc. + * Copyright (C) 2017-2019 Marek Vasut <marek.vasut@gmail.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "cfi.h" +#include "non_cfi.h" +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/time_support.h> + +#define RPC_CMNCR 0x0000 /* R/W */ +#define RPC_CMNCR_MD BIT(31) +#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) +#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) +#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) +#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) +#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \ + RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3)) +#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8) +#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12) +#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14) +#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \ + RPC_CMNCR_IO3FV(3)) +#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0) + +#define RPC_SSLDR 0x0004 /* R/W */ +#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16) +#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8) +#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0) + +#define RPC_DRCR 0x000C /* R/W */ +#define RPC_DRCR_SSLN BIT(24) +#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16) +#define RPC_DRCR_RCF BIT(9) +#define RPC_DRCR_RBE BIT(8) +#define RPC_DRCR_SSLE BIT(0) + +#define RPC_DRCMR 0x0010 /* R/W */ +#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPC_DREAR 0x0014 /* R/W */ +#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16) +#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0) + +#define RPC_DROPR 0x0018 /* R/W */ +#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24) +#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0) + +#define RPC_DRENR 0x001C /* R/W */ +#define RPC_DRENR_CDB(o) (uint32_t)((((o) & 0x3) << 30)) +#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28) +#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24) +#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20) +#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16) +#define RPC_DRENR_DME BIT(15) +#define RPC_DRENR_CDE BIT(14) +#define RPC_DRENR_OCDE BIT(12) +#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8) +#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4) + +#define RPC_SMCR 0x0020 /* R/W */ +#define RPC_SMCR_SSLKP BIT(8) +#define RPC_SMCR_SPIRE BIT(2) +#define RPC_SMCR_SPIWE BIT(1) +#define RPC_SMCR_SPIE BIT(0) + +#define RPC_SMCMR 0x0024 /* R/W */ +#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPC_SMADR 0x0028 /* R/W */ +#define RPC_SMOPR 0x002C /* R/W */ +#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0) +#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24) + +#define RPC_SMENR 0x0030 /* R/W */ +#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30) +#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28) +#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24) +#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20) +#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16) +#define RPC_SMENR_DME BIT(15) +#define RPC_SMENR_CDE BIT(14) +#define RPC_SMENR_OCDE BIT(12) +#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8) +#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4) +#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0) + +#define RPC_SMRDR0 0x0038 /* R */ +#define RPC_SMRDR1 0x003C /* R */ +#define RPC_SMWDR0 0x0040 /* R/W */ +#define RPC_SMWDR1 0x0044 /* R/W */ +#define RPC_CMNSR 0x0048 /* R */ +#define RPC_CMNSR_SSLF BIT(1) +#define RPC_CMNSR_TEND BIT(0) + +#define RPC_DRDMCR 0x0058 /* R/W */ +#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0) + +#define RPC_DRDRENR 0x005C /* R/W */ +#define RPC_DRDRENR_HYPE (0x5 << 12) +#define RPC_DRDRENR_ADDRE BIT(8) +#define RPC_DRDRENR_OPDRE BIT(4) +#define RPC_DRDRENR_DRDRE BIT(0) + +#define RPC_SMDMCR 0x0060 /* R/W */ +#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0) + +#define RPC_SMDRENR 0x0064 /* R/W */ +#define RPC_SMDRENR_HYPE (0x5 << 12) +#define RPC_SMDRENR_ADDRE BIT(8) +#define RPC_SMDRENR_OPDRE BIT(4) +#define RPC_SMDRENR_SPIDRE BIT(0) + +#define RPC_PHYCNT 0x007C /* R/W */ +#define RPC_PHYCNT_CAL BIT(31) +#define PRC_PHYCNT_OCTA_AA BIT(22) +#define PRC_PHYCNT_OCTA_SA BIT(23) +#define PRC_PHYCNT_EXDS BIT(21) +#define RPC_PHYCNT_OCT BIT(20) +#define RPC_PHYCNT_WBUF2 BIT(4) +#define RPC_PHYCNT_WBUF BIT(2) +#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) + +#define RPC_PHYINT 0x0088 /* R/W */ +#define RPC_PHYINT_RSTEN BIT(18) +#define RPC_PHYINT_WPEN BIT(17) +#define RPC_PHYINT_INTEN BIT(16) +#define RPC_PHYINT_RST BIT(2) +#define RPC_PHYINT_WP BIT(1) +#define RPC_PHYINT_INT BIT(0) + +#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */ +#define RPC_WBUF_SIZE 0x100 + +static uint32_t rpc_base = 0xee200000; +static uint32_t mem_base = 0x08000000; + +enum rpc_hf_size { + RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8), + RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC), + RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF), +}; + +static int rpc_hf_wait_tend(struct target *target) +{ + uint32_t reg = rpc_base + RPC_CMNSR; + uint32_t val; + unsigned long timeout = 1000; + long long endtime; + int ret; + + endtime = timeval_ms() + timeout; + do { + ret = target_read_u32(target, reg, &val); + if (ret != ERROR_OK) + return ERROR_FAIL; + + if (val & RPC_CMNSR_TEND) + return ERROR_OK; + + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_TIMEOUT_REACHED; +} + +static int clrsetbits_u32(struct target *target, uint32_t reg, + uint32_t clr, uint32_t set) +{ + uint32_t val; + int ret; + + ret = target_read_u32(target, reg, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~clr; + val |= set; + + return target_write_u32(target, reg, val); +} + +static int rpc_hf_mode(struct target *target, bool manual) +{ + uint32_t val; + int ret; + + ret = rpc_hf_wait_tend(target); + if (ret != ERROR_OK) { + LOG_ERROR("Mode TEND timeout"); + return ret; + } + + ret = clrsetbits_u32(target, rpc_base + RPC_PHYCNT, + RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | + RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3), + RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); + if (ret != ERROR_OK) + return ret; + + ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR, + RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), + RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | + (manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1)); + if (ret != ERROR_OK) + return ret; + + if (manual) + return ERROR_OK; + + ret = target_write_u32(target, rpc_base + RPC_DRCR, + RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | + RPC_DRCR_RBE); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_DRCMR, + RPC_DRCMR_CMD(0xA0)); + if (ret != ERROR_OK) + return ret; + ret = target_write_u32(target, rpc_base + RPC_DRENR, + RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | + RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) | + RPC_DRENR_CDE | RPC_DRENR_OCDE | + RPC_DRENR_ADE(4)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_DRDMCR, + RPC_DRDMCR_DMCYC(0xE)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_DRDRENR, + RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | + RPC_DRDRENR_DRDRE); + if (ret != ERROR_OK) + return ret; + + /* Dummy read */ + return target_read_u32(target, rpc_base + RPC_DRCR, &val); +} + +static int rpc_hf_xfer(struct target *target, target_addr_t addr, + uint32_t wdata, uint32_t *rdata, enum rpc_hf_size size, + bool write, const uint8_t *wbuf, unsigned int wbuf_size) +{ + int ret; + uint32_t val; + + if (wbuf_size != 0) { + ret = rpc_hf_wait_tend(target); + if (ret != ERROR_OK) { + LOG_ERROR("Xfer TEND timeout"); + return ret; + } + + /* Write calibration magic */ + ret = target_write_u32(target, rpc_base + RPC_DRCR, 0x01FF0301); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_PHYCNT, 0x80030277); + if (ret != ERROR_OK) + return ret; + + ret = target_write_memory(target, rpc_base | RPC_WBUF, 4, + wbuf_size / 4, wbuf); + if (ret != ERROR_OK) + return ret; + + ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR, + RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), + RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | + RPC_CMNCR_MD | RPC_CMNCR_BSZ(1)); + if (ret != ERROR_OK) + return ret; + } else { + ret = rpc_hf_mode(target, 1); + if (ret != ERROR_OK) + return ret; + } + + /* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */ + ret = target_write_u32(target, rpc_base + RPC_SMCMR, + write ? 0 : RPC_SMCMR_CMD(0x80)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMADR, + addr >> 1); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMOPR, 0x0); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMDRENR, + RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | + RPC_SMDRENR_SPIDRE); + if (ret != ERROR_OK) + return ret; + + val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | + RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | + (wbuf_size ? RPC_SMENR_OPDB(2) : 0) | + RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size; + + if (write) { + ret = target_write_u32(target, rpc_base + RPC_SMENR, val); + if (ret != ERROR_OK) + return ret; + + if (wbuf_size == 0) { + buf_bswap32((uint8_t *)&wdata, (uint8_t *)&wdata, 4); + ret = target_write_u32(target, rpc_base + RPC_SMWDR0, + wdata); + if (ret != ERROR_OK) + return ret; + } + + ret = target_write_u32(target, rpc_base + RPC_SMCR, + RPC_SMCR_SPIWE | RPC_SMCR_SPIE); + if (ret != ERROR_OK) + return ret; + } else { + val |= RPC_SMENR_DME; + + ret = target_write_u32(target, rpc_base + RPC_SMDMCR, + RPC_SMDMCR_DMCYC(0xE)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMENR, val); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMCR, + RPC_SMCR_SPIRE | RPC_SMCR_SPIE); + if (ret != ERROR_OK) + return ret; + + ret = rpc_hf_wait_tend(target); + if (ret != ERROR_OK) + return ret; + + uint32_t val32; + ret = target_read_u32(target, rpc_base + RPC_SMRDR0, &val32); + if (ret != ERROR_OK) + return ret; + buf_bswap32((uint8_t *)&val32, (uint8_t *)&val32, 4); + *rdata = val32; + } + + ret = rpc_hf_mode(target, 0); + if (ret != ERROR_OK) + LOG_ERROR("Xfer done TEND timeout"); + return ret; +} + +static int rpchf_target_write_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, const uint8_t *buffer) +{ + struct target *target = bank->target; + uint32_t wdata; + + if (count != 2) + return ERROR_FAIL; + + wdata = buffer[0] | (buffer[1] << 8); + + return rpc_hf_xfer(target, addr, wdata, NULL, RPC_HF_SIZE_16BIT, + true, NULL, 0); +} + +static int rpchf_target_read_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer) +{ + struct target *target = bank->target; + uint32_t i, rdata; + int ret; + + for (i = 0; i < count; i++) { + ret = rpc_hf_xfer(target, addr + (2 * i), 0, &rdata, + RPC_HF_SIZE_16BIT, false, NULL, 0); + if (ret != ERROR_OK) + return ret; + buffer[(2 * i) + 0] = rdata & 0xff; + buffer[(2 * i) + 1] = (rdata >> 8) & 0xff; + } + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(rpchf_flash_bank_command) +{ + struct cfi_flash_bank *cfi_info; + int ret; + + ret = cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV); + if (ret != ERROR_OK) + return ret; + + cfi_info = bank->driver_priv; + cfi_info->read_mem = rpchf_target_read_memory; + cfi_info->write_mem = rpchf_target_write_memory; + + return ERROR_OK; +} + +static int rpchf_spansion_write_words(struct flash_bank *bank, const uint8_t *word, + uint32_t wordcount, uint32_t address) +{ + int retval; + struct cfi_flash_bank *cfi_info = bank->driver_priv; + struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; + + /* Calculate buffer size and boundary mask + * buffersize is (buffer size per chip) * (number of chips) + * bufferwsize is buffersize in words */ + uint32_t buffersize = RPC_WBUF_SIZE; + uint32_t buffermask = buffersize - 1; + uint32_t bufferwsize = buffersize / 2; + + /* Check for valid range */ + if (address & buffermask) { + LOG_ERROR("Write address at base " TARGET_ADDR_FMT + ", address 0x%" PRIx32 " not aligned to 2^%d boundary", + bank->base, address, cfi_info->max_buf_write_size); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Check for valid size */ + if (wordcount > bufferwsize) { + LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" + PRId32, wordcount, buffersize); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Unlock */ + retval = cfi_spansion_unlock_seq(bank); + if (retval != ERROR_OK) + return retval; + + retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1)); + if (retval != ERROR_OK) + return retval; + + retval = rpc_hf_xfer(bank->target, address, 0, NULL, RPC_HF_SIZE_64BIT, true, word, wordcount * 2); + if (retval != ERROR_OK) + return retval; + + if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); + if (retval != ERROR_OK) + return retval; + + LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT + ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address, + bufferwsize); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +static int rpchf_write_words(struct flash_bank *bank, const uint8_t *word, + uint32_t wordcount, uint32_t address) +{ + return rpchf_spansion_write_words(bank, word, wordcount, address); +} + +static int rpchf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + uint32_t address = bank->base + offset; /* address of first byte to be programmed */ + uint32_t write_p; + int align; /* number of unaligned bytes */ + uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being + *programmed */ + int i; + int retval; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) + return ERROR_FLASH_DST_OUT_OF_BANK; + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + /* start at the first byte of the first word (bus_width size) */ + write_p = address & ~(bank->bus_width - 1); + align = address - write_p; + if (align != 0) { + LOG_INFO("Fixup %d unaligned head bytes", align); + + /* read a complete word from flash */ + retval = cfi_target_read_memory(bank, write_p, 1, current_word); + if (retval != ERROR_OK) + return retval; + + /* replace only bytes that must be written */ + for (i = align; + (i < bank->bus_width) && (count > 0); + i++, count--) + if (cfi_info->data_swap) + /* data bytes are swapped (reverse endianness) */ + current_word[bank->bus_width - i] = *buffer++; + else + current_word[i] = *buffer++; + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + write_p += bank->bus_width; + } + + /* Calculate buffer size and boundary mask + * buffersize is (buffer size per chip) * (number of chips) + * bufferwsize is buffersize in words */ + uint32_t buffersize = RPC_WBUF_SIZE; + uint32_t buffermask = buffersize-1; + uint32_t bufferwsize = buffersize / bank->bus_width; + + /* fall back to memory writes */ + while (count >= (uint32_t)bank->bus_width) { + int fallback; + if ((write_p & 0xff) == 0) { + LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" + PRIx32 " bytes remaining", write_p, count); + } + fallback = 1; + if ((bufferwsize > 0) && (count >= buffersize) && + !(write_p & buffermask)) { + retval = rpchf_write_words(bank, buffer, bufferwsize, write_p); + if (retval == ERROR_OK) { + buffer += buffersize; + write_p += buffersize; + count -= buffersize; + fallback = 0; + } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) + return retval; + } + /* try the slow way? */ + if (fallback) { + for (i = 0; i < bank->bus_width; i++) + current_word[i] = *buffer++; + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + + write_p += bank->bus_width; + count -= bank->bus_width; + } + } + + /* return to read array mode, so we can read from flash again for padding */ + retval = cfi_reset(bank); + if (retval != ERROR_OK) + return retval; + + /* handle unaligned tail bytes */ + if (count > 0) { + LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count); + + /* read a complete word from flash */ + retval = cfi_target_read_memory(bank, write_p, 1, current_word); + if (retval != ERROR_OK) + return retval; + + /* replace only bytes that must be written */ + for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) + if (cfi_info->data_swap) + /* data bytes are swapped (reverse endianness) */ + current_word[bank->bus_width - i] = *buffer++; + else + current_word[i] = *buffer++; + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + } + + /* return to read array mode */ + return cfi_reset(bank); +} + +static int rpchf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + struct target *target = bank->target; + + LOG_DEBUG("reading buffer of %" PRIi32 " byte at 0x%8.8" PRIx32, + count, offset); + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) + return ERROR_FLASH_DST_OUT_OF_BANK; + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + return target_read_memory(target, offset | mem_base, + 4, count / 4, buffer); +} + +const struct flash_driver renesas_rpchf_flash = { + .name = "rpchf", + .flash_bank_command = rpchf_flash_bank_command, + .erase = cfi_erase, + .protect = cfi_protect, + .write = rpchf_write, + .read = rpchf_read, + .probe = cfi_probe, + .auto_probe = cfi_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = cfi_protect_check, + .info = cfi_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c new file mode 100644 index 0000000..862e43a --- /dev/null +++ b/src/flash/nor/sh_qspi.c @@ -0,0 +1,912 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * SH QSPI (Quad SPI) driver + * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com> + * + * Based on U-Boot SH QSPI driver + * Copyright (C) 2013 Renesas Electronics Corporation + * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "spi.h" +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/time_support.h> +#include <helper/types.h> +#include <jtag/jtag.h> +#include <target/algorithm.h> +#include <target/arm.h> +#include <target/arm_opcodes.h> +#include <target/target.h> + +/* SH QSPI register bit masks <REG>_<BIT> */ +#define SPCR_MSTR 0x08 +#define SPCR_SPE 0x40 +#define SPSR_SPRFF 0x80 +#define SPSR_SPTEF 0x20 +#define SPPCR_IO3FV 0x04 +#define SPPCR_IO2FV 0x02 +#define SPPCR_IO1FV 0x01 +#define SPBDCR_RXBC0 BIT(0) +#define SPCMD_SCKDEN BIT(15) +#define SPCMD_SLNDEN BIT(14) +#define SPCMD_SPNDEN BIT(13) +#define SPCMD_SSLKP BIT(7) +#define SPCMD_BRDV0 BIT(2) +#define SPCMD_INIT1 (SPCMD_SCKDEN | SPCMD_SLNDEN | \ + SPCMD_SPNDEN | SPCMD_SSLKP | \ + SPCMD_BRDV0) +#define SPCMD_INIT2 (SPCMD_SPNDEN | SPCMD_SSLKP | \ + SPCMD_BRDV0) +#define SPBFCR_TXRST BIT(7) +#define SPBFCR_RXRST BIT(6) +#define SPBFCR_TXTRG 0x30 +#define SPBFCR_RXTRG 0x07 + +/* SH QSPI register set */ +#define SH_QSPI_SPCR 0x00 +#define SH_QSPI_SSLP 0x01 +#define SH_QSPI_SPPCR 0x02 +#define SH_QSPI_SPSR 0x03 +#define SH_QSPI_SPDR 0x04 +#define SH_QSPI_SPSCR 0x08 +#define SH_QSPI_SPSSR 0x09 +#define SH_QSPI_SPBR 0x0a +#define SH_QSPI_SPDCR 0x0b +#define SH_QSPI_SPCKD 0x0c +#define SH_QSPI_SSLND 0x0d +#define SH_QSPI_SPND 0x0e +#define SH_QSPI_DUMMY0 0x0f +#define SH_QSPI_SPCMD0 0x10 +#define SH_QSPI_SPCMD1 0x12 +#define SH_QSPI_SPCMD2 0x14 +#define SH_QSPI_SPCMD3 0x16 +#define SH_QSPI_SPBFCR 0x18 +#define SH_QSPI_DUMMY1 0x19 +#define SH_QSPI_SPBDCR 0x1a +#define SH_QSPI_SPBMUL0 0x1c +#define SH_QSPI_SPBMUL1 0x20 +#define SH_QSPI_SPBMUL2 0x24 +#define SH_QSPI_SPBMUL3 0x28 + +struct sh_qspi_flash_bank { + const struct flash_device *dev; + uint32_t io_base; + int probed; + struct working_area *io_algorithm; + struct working_area *source; + unsigned int buffer_size; +}; + +struct sh_qspi_target { + char *name; + uint32_t tap_idcode; + uint32_t io_base; +}; + +static const struct sh_qspi_target target_devices[] = { + /* name, tap_idcode, io_base */ + { "SH QSPI", 0x4ba00477, 0xe6b10000 }, + { NULL, 0, 0 } +}; + +static int sh_qspi_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t val; + int ret; + + /* QSPI initialize */ + /* Set master mode only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR); + if (ret != ERROR_OK) + return ret; + + /* Set SSL signal level */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set MOSI signal value when transfer is in idle state */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR, + SPPCR_IO3FV | SPPCR_IO2FV); + if (ret != ERROR_OK) + return ret; + + /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01); + if (ret != ERROR_OK) + return ret; + + /* Disable Dummy Data Transmission */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set clock delay value */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set SSL negation delay value */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set next-access delay value */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set equence command */ + ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0, + SPCMD_INIT2); + if (ret != ERROR_OK) + return ret; + + /* Reset transfer and receive Buffer */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPBFCR_TXRST | SPBFCR_RXRST; + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Clear transfer and receive Buffer control bit */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~(SPBFCR_TXRST | SPBFCR_RXRST); + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Set equence control method. Use equence0 only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Enable SPI function */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPCR_SPE; + + return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); +} + +static int sh_qspi_cs_activate(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t val; + int ret; + + /* Set master mode only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR); + if (ret != ERROR_OK) + return ret; + + /* Set command */ + ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0, + SPCMD_INIT1); + if (ret != ERROR_OK) + return ret; + + /* Reset transfer and receive Buffer */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPBFCR_TXRST | SPBFCR_RXRST; + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Clear transfer and receive Buffer control bit */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~(SPBFCR_TXRST | SPBFCR_RXRST); + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Set equence control method. Use equence0 only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Enable SPI function */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPCR_SPE; + + return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); +} + +static int sh_qspi_cs_deactivate(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t val; + int ret; + + /* Disable SPI Function */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~SPCR_SPE; + + return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); +} + +static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg, + uint32_t mask, bool set, + unsigned long timeout) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + long long endtime; + uint8_t val; + int ret; + + endtime = timeval_ms() + timeout; + do { + ret = target_read_u8(target, info->io_base + reg, &val); + if (ret != ERROR_OK) + return ret; + + if (!set) + val = ~val; + + if ((val & mask) == mask) + return ERROR_OK; + + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_TIMEOUT_REACHED; +} + +static int sh_qspi_xfer_common(struct flash_bank *bank, + const uint8_t *dout, unsigned int outlen, + uint8_t *din, unsigned int inlen, + bool xfer_start, bool xfer_end) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t tdata, rdata; + uint8_t val; + unsigned int nbyte = outlen + inlen; + int ret = 0; + + if (xfer_start) { + ret = sh_qspi_cs_activate(bank); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0, + nbyte); + if (ret != ERROR_OK) + return ret; + + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, + &val); + if (ret != ERROR_OK) + return ret; + + val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG); + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, + val); + if (ret != ERROR_OK) + return ret; + } + + while (nbyte > 0) { + ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF, + true, 1000); + if (ret != ERROR_OK) + return ret; + + tdata = outlen ? *dout++ : 0; + ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR, + tdata); + if (ret != ERROR_OK) + return ret; + + ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF, + true, 1000); + if (ret != ERROR_OK) + return ret; + + ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR, + &rdata); + if (ret != ERROR_OK) + return ret; + if (!outlen && inlen) { + *din++ = rdata; + inlen--; + } + + if (outlen) + outlen--; + + nbyte--; + } + + if (xfer_end) + return sh_qspi_cs_deactivate(bank); + else + return ERROR_OK; +} + +/* Send "write enable" command to SPI flash chip. */ +static int sh_qspi_write_enable(struct flash_bank *bank) +{ + uint8_t dout = SPIFLASH_WRITE_ENABLE; + + return sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1); +} + +/* Read the status register of the external SPI flash chip. */ +static int read_status_reg(struct flash_bank *bank, uint32_t *status) +{ + uint8_t dout = SPIFLASH_READ_STATUS; + uint8_t din; + int ret; + + ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1); + if (ret != ERROR_OK) + return ret; + + *status = din & 0xff; + + return ERROR_OK; +} + +/* check for WIP (write in progress) bit in status register */ +/* timeout in ms */ +static int wait_till_ready(struct flash_bank *bank, int timeout) +{ + long long endtime; + uint32_t status; + int ret; + + endtime = timeval_ms() + timeout; + do { + /* read flash status register */ + ret = read_status_reg(bank, &status); + if (ret != ERROR_OK) + return ret; + + if ((status & SPIFLASH_BSY_BIT) == 0) + return ERROR_OK; + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_TIMEOUT_REACHED; +} + +static int sh_qspi_erase_sector(struct flash_bank *bank, int sector) +{ + struct sh_qspi_flash_bank *info = bank->driver_priv; + bool addr4b = info->dev->size_in_bytes > (1UL << 24); + uint32_t address = (sector * info->dev->sectorsize) << + (addr4b ? 0 : 8); + uint8_t dout[5] = { + info->dev->erase_cmd, + (address >> 24) & 0xff, (address >> 16) & 0xff, + (address >> 8) & 0xff, (address >> 0) & 0xff + }; + unsigned int doutlen = addr4b ? 5 : 4; + int ret; + + /* Write Enable */ + ret = sh_qspi_write_enable(bank); + if (ret != ERROR_OK) + return ret; + + /* Erase */ + ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1); + if (ret != ERROR_OK) + return ret; + + /* Poll status register */ + return wait_till_ready(bank, 3000); +} + +static int sh_qspi_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + int retval = ERROR_OK; + int sector; + + LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!info->probed) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (info->dev->erase_cmd == 0x00) + return ERROR_FLASH_OPER_UNSUPPORTED; + + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + for (sector = first; sector <= last; sector++) { + retval = sh_qspi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + keep_alive(); + } + + return retval; +} + +static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + struct reg_param reg_params[4]; + struct arm_algorithm arm_algo; + uint32_t io_base = (uint32_t)(info->io_base); + uint32_t src_base = (uint32_t)(info->source->address); + uint32_t chunk; + bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24)); + int ret = ERROR_OK; + int sector; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Write pasts end of flash. Extra data discarded."); + count = bank->size - offset; + } + + if (offset & 0xff) { + LOG_ERROR("sh_qspi_write_page: unaligned write address: %08x", + offset); + return ERROR_FAIL; + } + + /* Check sector protection */ + for (sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + struct flash_sector *bs = &bank->sectors[sector]; + + if ((offset < (bs->offset + bs->size)) && + ((offset + count - 1) >= bs->offset) && + bs->is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + arm_algo.common_magic = ARM_COMMON_MAGIC; + arm_algo.core_mode = ARM_MODE_SVC; + arm_algo.core_state = ARM_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + + while (count > 0) { + chunk = (count > info->buffer_size) ? + info->buffer_size : count; + + target_write_buffer(target, info->source->address, + chunk, buffer); + + buf_set_u32(reg_params[0].value, 0, 32, io_base); + buf_set_u32(reg_params[1].value, 0, 32, src_base); + buf_set_u32(reg_params[2].value, 0, 32, + (1 << 31) | (addr4b << 30) | + (info->dev->pprog_cmd << 20) | chunk); + buf_set_u32(reg_params[3].value, 0, 32, offset); + + ret = target_run_algorithm(target, 0, NULL, 4, reg_params, + info->io_algorithm->address, + 0, 10000, &arm_algo); + if (ret != ERROR_OK) { + LOG_ERROR("error executing SH QSPI flash IO algorithm"); + ret = ERROR_FLASH_OPERATION_FAILED; + break; + } + + buffer += chunk; + offset += chunk; + count -= chunk; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + return ret; +} + +static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + struct reg_param reg_params[4]; + struct arm_algorithm arm_algo; + uint32_t io_base = (uint32_t)(info->io_base); + uint32_t src_base = (uint32_t)(info->source->address); + uint32_t chunk; + bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24)); + int ret = ERROR_OK; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + arm_algo.common_magic = ARM_COMMON_MAGIC; + arm_algo.core_mode = ARM_MODE_SVC; + arm_algo.core_state = ARM_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + + while (count > 0) { + chunk = (count > info->buffer_size) ? + info->buffer_size : count; + + buf_set_u32(reg_params[0].value, 0, 32, io_base); + buf_set_u32(reg_params[1].value, 0, 32, src_base); + buf_set_u32(reg_params[2].value, 0, 32, + (addr4b << 30) | (info->dev->read_cmd << 20) | + chunk); + buf_set_u32(reg_params[3].value, 0, 32, offset); + + ret = target_run_algorithm(target, 0, NULL, 4, reg_params, + info->io_algorithm->address, + 0, 10000, &arm_algo); + if (ret != ERROR_OK) { + LOG_ERROR("error executing SH QSPI flash IO algorithm"); + ret = ERROR_FLASH_OPERATION_FAILED; + break; + } + + target_read_buffer(target, info->source->address, + chunk, buffer); + + buffer += chunk; + offset += chunk; + count -= chunk; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + return ret; +} + +/* Return ID of flash device */ +static int read_flash_id(struct flash_bank *bank, uint32_t *id) +{ + struct target *target = bank->target; + uint8_t dout = SPIFLASH_READ_ID; + uint8_t din[3] = { 0, 0, 0 }; + int ret; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1); + if (ret != ERROR_OK) + return ret; + + *id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16); + + if (*id == 0xffffff) { + LOG_ERROR("No SPI flash found"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int sh_qspi_protect(struct flash_bank *bank, int set, + int first, int last) +{ + int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + + return ERROR_OK; +} + +static int sh_qspi_upload_helper(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + + /* see contrib/loaders/flash/sh_qspi.s for src */ + static const uint8_t sh_qspi_io_code[] = { +#include "../../../contrib/loaders/flash/sh_qspi/sh_qspi.inc" + }; + int ret; + + if (info->source) + target_free_working_area(target, info->source); + if (info->io_algorithm) + target_free_working_area(target, info->io_algorithm); + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(sh_qspi_io_code), + &info->io_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + target_write_buffer(target, info->io_algorithm->address, + sizeof(sh_qspi_io_code), sh_qspi_io_code); + + /* + * Try to allocate as big work area buffer as possible, start + * with 32 kiB and count down. If there is less than 256 Bytes + * of work area available, abort. + */ + info->buffer_size = 32768; + while (true) { + ret = target_alloc_working_area_try(target, info->buffer_size, + &info->source); + if (ret == ERROR_OK) + return ret; + + info->buffer_size /= 2; + if (info->buffer_size <= 256) { + target_free_working_area(target, info->io_algorithm); + + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + return ERROR_OK; +} + +static int sh_qspi_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + struct flash_sector *sectors; + uint32_t id = 0; /* silence uninitialized warning */ + uint32_t sectorsize; + const struct sh_qspi_target *target_device; + int ret; + + if (info->probed) + free(bank->sectors); + + info->probed = 0; + + for (target_device = target_devices; target_device->name; + ++target_device) + if (target_device->tap_idcode == target->tap->idcode) + break; + if (!target_device->name) { + LOG_ERROR("Device ID 0x%" PRIx32 " is not known", + target->tap->idcode); + return ERROR_FAIL; + } + + info->io_base = target_device->io_base; + + LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT, + target_device->name, bank->base); + + ret = sh_qspi_upload_helper(bank); + if (ret != ERROR_OK) + return ret; + + ret = sh_qspi_init(bank); + if (ret != ERROR_OK) + return ret; + + ret = read_flash_id(bank, &id); + if (ret != ERROR_OK) + return ret; + + info->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name; p++) + if (p->device_id == id) { + info->dev = p; + break; + } + + if (!info->dev) { + LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); + return ERROR_FAIL; + } + + LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", + info->dev->name, info->dev->device_id); + + /* Set correct size value */ + bank->size = info->dev->size_in_bytes; + if (bank->size <= (1UL << 16)) + LOG_WARNING("device needs 2-byte addresses - not implemented"); + + /* if no sectors, treat whole bank as single sector */ + sectorsize = info->dev->sectorsize ? + info->dev->sectorsize : + info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = info->dev->size_in_bytes / sectorsize; + sectors = calloc(1, sizeof(*sectors) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * sectorsize; + sectors[sector].size = sectorsize; + sectors[sector].is_erased = 0; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + info->probed = 1; + return ERROR_OK; +} + +static int sh_qspi_auto_probe(struct flash_bank *bank) +{ + struct sh_qspi_flash_bank *info = bank->driver_priv; + + if (info->probed) + return ERROR_OK; + + return sh_qspi_probe(bank); +} + +static int sh_qspi_flash_blank_check(struct flash_bank *bank) +{ + /* Not implemented */ + return ERROR_OK; +} + +static int sh_qspi_protect_check(struct flash_bank *bank) +{ + /* Not implemented */ + return ERROR_OK; +} + +static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct sh_qspi_flash_bank *info = bank->driver_priv; + + if (!info->probed) { + snprintf(buf, buf_size, + "\nSH QSPI flash bank not probed yet\n"); + return ERROR_OK; + } + + snprintf(buf, buf_size, "\nSH QSPI flash information:\n" + " Device \'%s\' (ID 0x%08" PRIx32 ")\n", + info->dev->name, info->dev->device_id); + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command) +{ + struct sh_qspi_flash_bank *info; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 6 || CMD_ARGC > 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) { + LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + info = calloc(1, sizeof(struct sh_qspi_flash_bank)); + if (!info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = info; + + return ERROR_OK; +} + +const struct flash_driver sh_qspi_flash = { + .name = "sh_qspi", + .flash_bank_command = sh_qspi_flash_bank_command, + .erase = sh_qspi_erase, + .protect = sh_qspi_protect, + .write = sh_qspi_write, + .read = sh_qspi_read, + .probe = sh_qspi_probe, + .auto_probe = sh_qspi_auto_probe, + .erase_check = sh_qspi_flash_blank_check, + .protect_check = sh_qspi_protect_check, + .info = sh_qspi_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 7ccf56b..4e39705 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -471,7 +471,7 @@ static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf, return ret; } -static int sim3x_flash_write(struct flash_bank *bank, const uint8_t * buffer, uint32_t offset, uint32_t count) +static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int ret; struct target *target; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index cf10e37..990b48a 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -116,7 +116,7 @@ struct stm32x_options { struct stm32x_flash_bank { struct stm32x_options option_bytes; int ppage_size; - int probed; + bool probed; bool has_dual_banks; /* used to access dual flash bank stm32xl */ @@ -145,7 +145,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; - stm32x_info->probed = 0; + stm32x_info->probed = false; stm32x_info->has_dual_banks = false; stm32x_info->can_load_options = false; stm32x_info->register_base = FLASH_REG_BASE_B0; @@ -229,34 +229,20 @@ static int stm32x_read_options(struct flash_bank *bank) uint32_t option_bytes; int retval; - /* read user and read protection option bytes */ - retval = target_read_u32(target, STM32_OB_RDP, &option_bytes); + /* read user and read protection option bytes, user data option bytes */ + retval = target_read_u32(target, STM32_FLASH_OBR_B0, &option_bytes); if (retval != ERROR_OK) return retval; - stm32x_info->option_bytes.rdp = option_bytes & 0xFF; - stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF; - - /* read user data option bytes */ - retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes); - if (retval != ERROR_OK) - return retval; - - stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); + stm32x_info->option_bytes.rdp = (option_bytes & (1 << OPT_READOUT)) ? 0 : stm32x_info->default_rdp; + stm32x_info->option_bytes.user = (option_bytes >> stm32x_info->option_offset >> 2) & 0xff; + stm32x_info->option_bytes.data = (option_bytes >> stm32x_info->user_data_offset) & 0xffff; /* read write protection option bytes */ - retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes); + retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &stm32x_info->option_bytes.protection); if (retval != ERROR_OK) return retval; - stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); - - retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes); - if (retval != ERROR_OK) - return retval; - - stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16; - return ERROR_OK; } @@ -382,7 +368,6 @@ static int stm32x_protect_check(struct flash_bank *bank) static int stm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; - int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -400,7 +385,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) if (retval != ERROR_OK) return retval; - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) return retval; @@ -711,7 +696,7 @@ static int stm32x_probe(struct flash_bank *bank) int page_size; uint32_t base_address = 0x08000000; - stm32x_info->probed = 0; + stm32x_info->probed = false; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_data_offset = 10; stm32x_info->option_offset = 0; @@ -728,31 +713,79 @@ static int stm32x_probe(struct flash_bank *bank) /* set page size, protection granularity and max flash size depending on family */ switch (device_id & 0xfff) { - case 0x410: /* medium density */ + case 0x440: /* stm32f05x */ + page_size = 1024; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 64; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x444: /* stm32f03x */ + case 0x445: /* stm32f04x */ + page_size = 1024; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 32; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x448: /* stm32f07x */ + page_size = 2048; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 128; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x442: /* stm32f09x */ + page_size = 2048; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 256; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x410: /* stm32f1x medium-density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; - case 0x412: /* low density */ + case 0x412: /* stm32f1x low-density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 32; break; - case 0x414: /* high density */ + case 0x414: /* stm32f1x high-density */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 512; break; - case 0x418: /* connectivity line density */ + case 0x418: /* stm32f1x connectivity */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; break; - case 0x420: /* value line density */ + case 0x430: /* stm32f1 XL-density (dual flash banks) */ + page_size = 2048; + stm32x_info->ppage_size = 2; + max_flash_size_in_kb = 1024; + stm32x_info->has_dual_banks = true; + break; + case 0x420: /* stm32f100xx low- and medium-density value line */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; + case 0x428: /* stm32f100xx high-density value line */ + page_size = 2048; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 512; + break; case 0x422: /* stm32f302/3xb/c */ page_size = 2048; stm32x_info->ppage_size = 2; @@ -771,17 +804,6 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; - case 0x428: /* value line High density */ - page_size = 2048; - stm32x_info->ppage_size = 4; - max_flash_size_in_kb = 128; - break; - case 0x430: /* xl line density (dual flash banks) */ - page_size = 2048; - stm32x_info->ppage_size = 2; - max_flash_size_in_kb = 1024; - stm32x_info->has_dual_banks = true; - break; case 0x432: /* stm32f37x */ page_size = 2048; stm32x_info->ppage_size = 2; @@ -801,27 +823,6 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; - case 0x440: /* stm32f05x */ - case 0x444: /* stm32f03x */ - case 0x445: /* stm32f04x */ - page_size = 1024; - stm32x_info->ppage_size = 4; - max_flash_size_in_kb = 64; - stm32x_info->user_data_offset = 16; - stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0xAA; - stm32x_info->can_load_options = true; - break; - case 0x448: /* stm32f07x */ - case 0x442: /* stm32f09x */ - page_size = 2048; - stm32x_info->ppage_size = 4; - max_flash_size_in_kb = 256; - stm32x_info->user_data_offset = 16; - stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0xAA; - stm32x_info->can_load_options = true; - break; default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; @@ -900,7 +901,7 @@ static int stm32x_probe(struct flash_bank *bank) if (num_prot_blocks == 32) bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size; - stm32x_info->probed = 1; + stm32x_info->probed = true; return ERROR_OK; } @@ -1368,8 +1369,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt); CMD_ARGC--; CMD_ARGV++; - } - else if (stm32x_info->has_dual_banks) { + } else if (stm32x_info->has_dual_banks) { if (strcmp("BOOT0", CMD_ARGV[0]) == 0) optionbyte |= (1 << 3); else if (strcmp("BOOT1", CMD_ARGV[0]) == 0) @@ -1488,8 +1488,6 @@ static int stm32x_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(stm32x_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1501,7 +1499,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32x mass erase complete"); diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index b49e76e..c1283bb 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -634,7 +634,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ for (i = first; i <= last; i++) { - int snb; + unsigned int snb; if (stm32x_info->has_large_mem && i >= 12) snb = (i - 12) | 0x10; else @@ -894,31 +894,68 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); } -static int setup_sector(struct flash_bank *bank, int start, int num, int size) +static void setup_sector(struct flash_bank *bank, int i, int size) { + assert(i < bank->num_sectors); + bank->sectors[i].offset = bank->size; + bank->sectors[i].size = size; + bank->size += bank->sectors[i].size; + LOG_DEBUG("sector %d: %dkBytes", i, size >> 10); +} + +static uint16_t sector_size_in_kb(int i, uint16_t max_sector_size_in_kb) +{ + assert(i >= 0); + if (i < 4) + return max_sector_size_in_kb / 8; + if (i == 4) + return max_sector_size_in_kb / 2; + return max_sector_size_in_kb; +} + +static int calculate_number_of_sectors(struct flash_bank *bank, + uint16_t flash_size_in_kb, + uint16_t max_sector_size_in_kb) +{ + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; + uint16_t remaining_flash_size_in_kb = flash_size_in_kb; + int nr_sectors; - 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; - LOG_DEBUG("sector %d: %d kBytes", i, size >> 10); + /* Dual Bank Flash has two identically-arranged banks of sectors. */ + if (stm32x_info->has_large_mem) + remaining_flash_size_in_kb /= 2; + + for (nr_sectors = 0; remaining_flash_size_in_kb > 0; nr_sectors++) { + uint16_t size_in_kb = sector_size_in_kb(nr_sectors, max_sector_size_in_kb); + if (size_in_kb > remaining_flash_size_in_kb) { + LOG_INFO("%s Bank %" PRIu16 " kiB final sector clipped to %" PRIu16 " kiB", + stm32x_info->has_large_mem ? "Dual" : "Single", + flash_size_in_kb, remaining_flash_size_in_kb); + remaining_flash_size_in_kb = 0; + } else { + remaining_flash_size_in_kb -= size_in_kb; + } } - return start + num; + return stm32x_info->has_large_mem ? nr_sectors*2 : nr_sectors; } static void setup_bank(struct flash_bank *bank, int start, uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb) { - int remain; - - start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024); - start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024); - - /* remaining sectors all of size max_sector_size_in_kb */ - remain = (flash_size_in_kb / max_sector_size_in_kb) - 1; - start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024); + uint16_t remaining_flash_size_in_kb = flash_size_in_kb; + int sector_index = 0; + while (remaining_flash_size_in_kb > 0) { + uint16_t size_in_kb = sector_size_in_kb(sector_index, max_sector_size_in_kb); + if (size_in_kb > remaining_flash_size_in_kb) { + /* Clip last sector. Already warned in + * calculate_number_of_sectors. */ + size_in_kb = remaining_flash_size_in_kb; + } + setup_sector(bank, start + sector_index, size_in_kb * 1024); + remaining_flash_size_in_kb -= size_in_kb; + sector_index++; + } } static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) @@ -1150,12 +1187,12 @@ static int stm32x_probe(struct flash_bank *bank) } /* calculate numbers of pages */ - int num_pages = flash_size_in_kb / max_sector_size_in_kb - + (stm32x_info->has_large_mem ? 8 : 4); + int num_pages = calculate_number_of_sectors( + bank, flash_size_in_kb, max_sector_size_in_kb); bank->base = base_address; bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + bank->sectors = calloc(num_pages, sizeof(struct flash_sector)); for (i = 0; i < num_pages; i++) { bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index fd6bf9a..7b6fdb3 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -57,8 +57,6 @@ #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_QW (1 << 2) /* Operation queue in progress */ @@ -79,6 +77,15 @@ #define OPT_LOCK (1 << 0) #define OPT_START (1 << 1) +/* FLASH_OPTSR register bits */ +#define OPT_BSY (1 << 0) +#define OPT_RDP_POS 8 +#define OPT_RDP_MASK (0xff << OPT_RDP_POS) +#define OPT_OPTCHANGEERR (1 << 30) + +/* FLASH_OPTCCR register bits */ +#define OPT_CLR_OPTCHANGEERR (1 << 30) + /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB @@ -92,68 +99,103 @@ #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; -}; +/* stm32h7x_part_info permits the store each device information and specificities. + * the default unit is byte unless the suffix '_kb' is used. */ 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 page_size_kb; + unsigned int block_size; /* flash write word size in bytes */ 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 */ + bool has_dual_bank; + uint16_t max_bank_size_kb; /* Used when has_dual_bank is true */ + uint32_t fsize_addr; /* Location of FSIZE register */ + uint32_t wps_group_size; /* write protection group sectors' count */ + uint32_t wps_mask; + /* function to compute flash_cr register values */ + uint32_t (*compute_flash_cr)(uint32_t cmd, int snb); }; struct stm32h7x_flash_bank { - int probed; + bool probed; uint32_t idcode; uint32_t user_bank_size; - uint32_t flash_base; /* Address of flash reg controller */ - struct stm32x_options option_bytes; + uint32_t flash_regs_base; /* Address of flash reg controller */ const struct stm32h7x_part_info *part_info; }; +enum stm32h7x_opt_rdp { + OPT_RDP_L0 = 0xaa, + OPT_RDP_L1 = 0x00, + OPT_RDP_L2 = 0xcc +}; + static const struct stm32h7x_rev stm32_450_revs[] = { - { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" }, +}; + +static const struct stm32h7x_rev stm32_480_revs[] = { + { 0x1000, "A"}, }; +static uint32_t stm32x_compute_flash_cr_450(uint32_t cmd, int snb) +{ + return cmd | (snb << 8); +} + +static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb) +{ + /* save FW and START bits, to be right shifted by 2 bits later */ + const uint32_t tmp = cmd & (FLASH_FW | FLASH_START); + + /* mask parallelism (ignored), FW and START bits */ + cmd &= ~(FLASH_PSIZE_64 | FLASH_FW | FLASH_START); + + return cmd | (tmp >> 2) | (snb << 6); +} + static const struct stm32h7x_part_info stm32h7x_parts[] = { { .id = 0x450, .revs = stm32_450_revs, .num_revs = ARRAY_SIZE(stm32_450_revs), .device_str = "STM32H74x/75x", - .page_size = 128, /* 128 KB */ + .page_size_kb = 128, + .block_size = 32, + .max_flash_size_kb = 2048, + .max_bank_size_kb = 1024, + .has_dual_bank = true, + .fsize_addr = 0x1FF1E880, + .wps_group_size = 1, + .wps_mask = 0xFF, + .compute_flash_cr = stm32x_compute_flash_cr_450, + }, + { + .id = 0x480, + .revs = stm32_480_revs, + .num_revs = ARRAY_SIZE(stm32_480_revs), + .device_str = "STM32H7Ax/7Bx", + .page_size_kb = 8, + .block_size = 16, .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, + .max_bank_size_kb = 1024, + .has_dual_bank = true, + .fsize_addr = 0x08FFF80C, + .wps_group_size = 4, + .wps_mask = 0xFFFFFFFF, + .compute_flash_cr = stm32x_compute_flash_cr_480, }, }; -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) @@ -166,51 +208,68 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); bank->driver_priv = stm32x_info; - stm32x_info->probed = 0; + stm32x_info->probed = false; 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) +static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; - return reg + stm32x_info->flash_base; + return reg_offset + stm32x_info->flash_regs_base; +} + +static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) +{ + uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); + int retval = target_read_u32(bank->target, reg_addr, value); + + if (retval != ERROR_OK) + LOG_ERROR("error while reading from address 0x%" PRIx32, reg_addr); + + return retval; +} + +static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); + int retval = target_write_u32(bank->target, reg_addr, value); + + if (retval != ERROR_OK) + LOG_ERROR("error while writing to address 0x%" PRIx32, reg_addr); + + return retval; } 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); + return stm32x_read_flash_reg(bank, FLASH_SR, status); } static int stm32x_wait_flash_op_queue(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 flash operations completion */ for (;;) { retval = stm32x_get_flash_status(bank, &status); - if (retval != ERROR_OK) { - LOG_INFO("wait_flash_op_queue, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); + if (retval != ERROR_OK) return retval; - } if ((status & FLASH_QW) == 0) break; if (timeout-- <= 0) { - LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); + LOG_ERROR("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { - LOG_INFO("wait_flash_op_queue, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); + LOG_ERROR("wait_flash_op_queue, WRPERR detected"); retval = ERROR_FAIL; } @@ -219,7 +278,7 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) if (retval == ERROR_OK) retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original retval */ - target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status); + stm32x_write_flash_reg(bank, FLASH_CCR, status); } return retval; } @@ -227,12 +286,11 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) 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); + int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -240,15 +298,15 @@ static int stm32x_unlock_reg(struct flash_bank *bank) return ERROR_OK; /* unlock flash registers for bank */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1); + retval = stm32x_write_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); + retval = stm32x_write_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); + retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -262,9 +320,8 @@ static int stm32x_unlock_reg(struct flash_bank *bank) 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); + int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; @@ -272,15 +329,15 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; /* unlock option registers */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1); + retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2); + retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; @@ -292,159 +349,108 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; } -static int stm32x_lock_reg(struct flash_bank *bank) +static inline 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; + return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK); } -static int stm32x_read_options(struct flash_bank *bank) +static inline int stm32x_lock_option_reg(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_OPTSR_CUR, &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) & 0xa3; - - 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_WPSN_CUR, &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_WPSN_CUR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32x_info->option_bytes.protection2 = optiondata & 0xff; - - return ERROR_OK; + return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK); } -static int stm32x_write_options(struct flash_bank *bank) +static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { - 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 & 0xa3) << 24; + int retval, retval2; - /* program options */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_PRG, optiondata); + /* unlock option bytes for modification */ + retval = stm32x_unlock_option_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; - optiondata = stm32x_info->option_bytes.protection & 0xff; - /* Program protection WPSNPRG */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_PRG, optiondata); + /* write option bytes */ + retval = stm32x_write_flash_reg(bank, reg_offset, value); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; - optiondata = stm32x_info->option_bytes.protection2 & 0xff; - /* Program protection WPSNPRG2 */ - retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_PRG, 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); + retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; /* start programming cycle */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START); + retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; /* wait for completion */ int timeout = FLASH_ERASE_TIMEOUT; + uint32_t status; for (;;) { - uint32_t status; - retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status); + retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status); if (retval != ERROR_OK) { - LOG_INFO("stm32x_write_options: wait_flash_op_queue : error"); - return retval; + LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR"); + goto flash_options_lock; } - if ((status & FLASH_QW) == 0) + if ((status & OPT_BSY) == 0) break; if (timeout-- <= 0) { - LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); - return ERROR_FAIL; + LOG_ERROR("waiting for OBL launch, time out expired, OPTSR: 0x%" PRIx32 "", status); + retval = ERROR_FAIL; + goto flash_options_lock; } alive_sleep(1); } - /* relock option registers */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK); + /* check for failure */ + if (status & OPT_OPTCHANGEERR) { + LOG_ERROR("error changing option bytes (OPTCHANGEERR=1)"); + retval = ERROR_FLASH_OPERATION_FAILED; + } + +flash_options_lock: + retval2 = stm32x_lock_option_reg(bank); + if (retval2 != ERROR_OK) + LOG_ERROR("error during the lock of flash options"); + + return (retval == ERROR_OK) ? retval2 : retval; +} + +static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) +{ + uint32_t data; + + int retval = stm32x_read_flash_reg(bank, reg_offset, &data); if (retval != ERROR_OK) return retval; - return ERROR_OK; + data = (data & ~mask) | (value & mask); + + return stm32x_write_option(bank, reg_offset, data); } static int stm32x_protect_check(struct flash_bank *bank) { - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + uint32_t protection; /* read 'write protection' settings */ - int retval = stm32x_read_options(bank); + int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); if (retval != ERROR_OK) { - LOG_DEBUG("unable to read option bytes"); + LOG_DEBUG("unable to read WPSN_CUR register"); 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; - } - } + for (int i = 0; i < bank->num_prot_blocks; i++) + bank->prot_blocks[i].is_protected = protection & (1 << i) ? 0 : 1; + return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, int first, int last) { - struct target *target = bank->target; - int retval; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int retval, retval2; assert(first < bank->num_sectors); assert(last < bank->num_sectors); @@ -454,7 +460,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* Sector Erase @@ -468,92 +474,84 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ 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); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %d", i); - return retval; + goto flash_lock; } - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), - FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %d", i); - return retval; + goto flash_lock; } retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("erase time-out or operation error sector %d", i); - return retval; + goto flash_lock; } bank->sectors[i].is_erased = 1; } - retval = stm32x_lock_reg(bank); - if (retval != ERROR_OK) { +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); - return retval; - } - return ERROR_OK; + return (retval == ERROR_OK) ? retval2 : retval; } 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; + uint32_t protection; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - /* read protection settings */ - int retval = stm32x_read_options(bank); + + /* read 'write protection' settings */ + int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); if (retval != ERROR_OK) { - LOG_DEBUG("unable to read option bytes"); + LOG_DEBUG("unable to read WPSN_CUR register"); 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); - } + if (set) + protection &= ~(1 << i); + else + protection |= (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)); + /* apply WRPSN mask */ + protection &= 0xff; - retval = stm32x_write_options(bank); - if (retval != ERROR_OK) - return retval; + LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); - return ERROR_OK; + /* apply new option value */ + return stm32x_write_option(bank, FLASH_WPSN_PRG, protection); } static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; /* - * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get + * If the size of the data part of the buffer is not a multiple of .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 data_size = 512 * stm32x_info->part_info->block_size; 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 reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; int retval = ERROR_OK; static const uint8_t stm32x_flash_write_code[] = { @@ -588,7 +586,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, } } - LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size); + LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%" PRIx32, buffer_size); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; @@ -596,27 +594,29 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, 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 */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count of words (word size = .block_size (bytes) */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* word size in bytes */ + init_reg_param(®_params[5], "r5", 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); + buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->part_info->block_size); + buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base); retval = target_run_flash_async_algorithm(target, buffer, count, - FLASH_BLOCK_SIZE, + stm32x_info->part_info->block_size, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), 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"); + LOG_ERROR("error executing stm32h7x flash write algorithm"); uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); @@ -626,7 +626,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, 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); + stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr); retval = ERROR_FAIL; } } @@ -639,6 +639,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); return retval; } @@ -646,6 +647,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t address = bank->base + offset; int retval, retval2; @@ -654,19 +656,19 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, 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; - } + /* should be enforced via bank->write_start_alignment */ + assert(!(offset % stm32x_info->part_info->block_size)); + + /* should be enforced via bank->write_end_alignment */ + assert(!(count % stm32x_info->part_info->block_size)); retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_lock; - uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE; - uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE; + uint32_t blocks_remaining = count / stm32x_info->part_info->block_size; - /* multiple words (32-bytes) to be programmed in block */ + /* multiple words (n * .block_size) to be programmed in block */ if (blocks_remaining) { retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); if (retval != ERROR_OK) { @@ -676,8 +678,8 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, 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; + buffer += blocks_remaining * stm32x_info->part_info->block_size; + address += blocks_remaining * stm32x_info->part_info->block_size; blocks_remaining = 0; } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) @@ -694,11 +696,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, 4. Wait for flash operations completion */ while (blocks_remaining > 0) { - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) goto flash_lock; - retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer); + retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer); if (retval != ERROR_OK) goto flash_lock; @@ -706,49 +709,17 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto flash_lock; - buffer += FLASH_BLOCK_SIZE; - address += FLASH_BLOCK_SIZE; + buffer += stm32x_info->part_info->block_size; + address += stm32x_info->part_info->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_flash_op_queue(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; - } + return (retval == ERROR_OK) ? retval2 : retval; } static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) @@ -764,13 +735,10 @@ 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->probed = false; stm32x_info->part_info = NULL; int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); @@ -792,44 +760,77 @@ static int stm32x_probe(struct flash_bank *bank) 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; + /* update the address of controller */ + if (bank->base == FLASH_BANK0_ADDRESS) + stm32x_info->flash_regs_base = FLASH_REG_BASE_B0; + else if (bank->base == FLASH_BANK1_ADDRESS) + stm32x_info->flash_regs_base = FLASH_REG_BASE_B1; + else { + LOG_WARNING("Flash register base not defined for bank %d", bank->bank_number); + return ERROR_FAIL; + } + LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base); /* get flash size from target */ - retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb); + retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &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 + + + + /* setup bank size */ + const uint32_t bank1_base = FLASH_BANK0_ADDRESS; + const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024; + bool has_dual_bank = stm32x_info->part_info->has_dual_bank; + + switch (device_id) { + case 0x450: + case 0x480: + /* For STM32H74x/75x and STM32H7Ax/Bx + * - STM32H7xxxI devices contains dual bank, 1 Mbyte each + * - STM32H7xxxG devices contains dual bank, 512 Kbyte each + * - STM32H7xxxB devices contains single bank, 128 Kbyte + * - the second bank starts always from 0x08100000 */ - 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. " - TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, - bank->base, base_address, second_bank_base); + if (flash_size_in_kb == 128) + has_dual_bank = false; + else + /* flash size is 2M or 1M */ + flash_size_in_kb /= 2; + break; + default: + LOG_ERROR("unsupported device"); + return ERROR_FAIL; + } + + if (has_dual_bank) { + LOG_INFO("STM32H7 flash has dual banks"); + if (bank->base != bank1_base && bank->base != bank2_base) { + LOG_ERROR("STM32H7 flash bank base address config is incorrect. " + TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, + bank->base, bank1_base, bank2_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); + LOG_INFO("STM32H7 flash has a single bank"); + if (bank->base == bank2_base) { + LOG_ERROR("this device has a single bank only"); + return ERROR_FAIL; + } else if (bank->base != bank1_base) { + LOG_ERROR("STM32H7 flash bank base address config is incorrect. " + TARGET_ADDR_FMT " but should be 0x%" PRIx32, + bank->base, bank1_base); + return ERROR_FAIL; + } } + LOG_INFO("Bank (%d) size is %d kb, base address is 0x%" PRIx32, + bank->bank_number, flash_size_in_kb, (uint32_t) bank->base); + /* 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) { @@ -842,33 +843,41 @@ static int stm32x_probe(struct flash_bank *bank) /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); + bank->size = flash_size_in_kb * 1024; + bank->write_start_alignment = stm32x_info->part_info->block_size; + bank->write_end_alignment = stm32x_info->part_info->block_size; - /* 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); + /* setup sectors */ + bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb; + assert(bank->num_sectors > 0); - if (bank->sectors) { + 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); + bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024, + bank->num_sectors); + 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); + /* setup protection blocks */ + const uint32_t wpsn = stm32x_info->part_info->wps_group_size; + assert(bank->num_sectors % wpsn == 0); - for (i = 0; i < num_pages; i++) { - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 0; + bank->num_prot_blocks = bank->num_sectors / wpsn; + assert(bank->num_prot_blocks > 0); + + if (bank->prot_blocks) + free(bank->prot_blocks); + + bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024, + bank->num_prot_blocks); + + if (bank->prot_blocks == NULL) { + LOG_ERROR("failed to allocate bank prot_block"); + return ERROR_FAIL; } stm32x_info->probed = 1; @@ -922,57 +931,52 @@ static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -COMMAND_HANDLER(stm32x_handle_lock_command) +static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp) { - 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; - } + struct target *target = bank->target; + uint32_t optsr, cur_rdp; + int retval; 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, "%s failed to read options", - bank->driver->name); - return ERROR_OK; + retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr); + + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read FLASH_OPTSR_PRG register"); + return retval; } - /* set readout protection */ - stm32x_info->option_bytes.RDP = 0; - if (stm32x_write_options(bank) != ERROR_OK) { - command_print(CMD, "%s failed to lock device", - bank->driver->name); + /* get current RDP, and check if there is a change */ + cur_rdp = (optsr & OPT_RDP_MASK) >> OPT_RDP_POS; + if (new_rdp == cur_rdp) { + LOG_INFO("the requested RDP value is already programmed"); return ERROR_OK; } - command_print(CMD, "%s locked", bank->driver->name); - return ERROR_OK; + switch (new_rdp) { + case OPT_RDP_L0: + LOG_WARNING("unlocking the entire flash device"); + break; + case OPT_RDP_L1: + LOG_WARNING("locking the entire flash device"); + break; + case OPT_RDP_L2: + LOG_WARNING("locking the entire flash device, irreversible"); + break; + } + + /* apply new RDP */ + optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS); + + /* apply new option value */ + return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr); } -COMMAND_HANDLER(stm32x_handle_unlock_command) +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; @@ -981,43 +985,41 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) if (ERROR_OK != retval) return retval; - stm32x_info = bank->driver_priv; - target = bank->target; + retval = stm32x_set_rdp(bank, OPT_RDP_L1); - /* 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 (retval != ERROR_OK) + command_print(CMD, "%s failed to lock device", bank->driver->name); + else + command_print(CMD, "%s locked", bank->driver->name); - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + return retval; +} - if (stm32x_read_options(bank) != ERROR_OK) { - command_print(CMD, "%s failed to read options", bank->driver->name); - return ERROR_OK; - } +COMMAND_HANDLER(stm32x_handle_unlock_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; - /* clear readout protection option byte - * this will also force a device unlock if set */ - stm32x_info->option_bytes.RDP = 0xAA; + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; - if (stm32x_write_options(bank) != ERROR_OK) { + retval = stm32x_set_rdp(bank, OPT_RDP_L0); + + if (retval != ERROR_OK) command_print(CMD, "%s failed to unlock device", bank->driver->name); - return ERROR_OK; - } - command_print(CMD, "%s unlocked.\n", bank->driver->name); + else + command_print(CMD, "%s unlocked", bank->driver->name); - return ERROR_OK; + return retval; } static int stm32x_mass_erase(struct flash_bank *bank) { - int retval; + int retval, retval2; struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1026,34 +1028,33 @@ static int stm32x_mass_erase(struct flash_bank *bank) retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* mass erase flash memory bank */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER | FLASH_PSIZE_64); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) - return retval; + goto flash_lock; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), - FLASH_BER | FLASH_PSIZE_64 | FLASH_START); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0)); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_flash_op_queue(bank, 30000); if (retval != ERROR_OK) - return retval; + goto flash_lock; - retval = stm32x_lock_reg(bank); - if (retval != ERROR_OK) { +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); - return retval; - } - return ERROR_OK; + + return (retval == ERROR_OK) ? retval2 : retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) { command_print(CMD, "stm32h7x mass_erase <bank>"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -1067,7 +1068,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32h7x mass erase complete"); @@ -1078,6 +1079,53 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) return retval; } +COMMAND_HANDLER(stm32x_handle_option_read_command) +{ + if (CMD_ARGC < 2) { + command_print(CMD, "stm32h7x option_read <bank> <option_reg offset>"); + 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; + + uint32_t reg_offset, value; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); + retval = stm32x_read_flash_reg(bank, reg_offset, &value); + if (ERROR_OK != retval) + return retval; + + command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", + stm32x_get_flash_reg(bank, reg_offset), value); + + return retval; +} + +COMMAND_HANDLER(stm32x_handle_option_write_command) +{ + if (CMD_ARGC < 3) { + command_print(CMD, "stm32h7x option_write <bank> <option_reg offset> <value> [mask]"); + 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; + + uint32_t reg_offset, value, mask = 0xffffffff; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); + if (CMD_ARGC > 3) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask); + + return stm32x_modify_option(bank, reg_offset, value, mask); +} + static const struct command_registration stm32x_exec_command_handlers[] = { { .name = "lock", @@ -1100,6 +1148,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = { .usage = "bank_id", .help = "Erase entire flash device.", }, + { + .name = "option_read", + .handler = stm32x_handle_option_read_command, + .mode = COMMAND_EXEC, + .usage = "bank_id reg_offset", + .help = "Read and display device option bytes.", + }, + { + .name = "option_write", + .handler = stm32x_handle_option_write_command, + .mode = COMMAND_EXEC, + .usage = "bank_id reg_offset value [mask]", + .help = "Write device option bit fields with provided value.", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index f680542..94fcd32 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1,7 +1,10 @@ /*************************************************************************** * Copyright (C) 2015 by Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * - * + * * + * Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics * + * tarek.bouchkati@gmail.com * + * * * 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 * @@ -24,6 +27,8 @@ #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> +#include "bits.h" +#include "stm32l4x.h" /* STM32L4xxx series for reference. * @@ -47,91 +52,294 @@ * RM0394 devices have a single bank only. * * RM0432 devices have single and dual bank operating modes. - * The FLASH size is 1Mbyte or 2Mbyte. + * - for STM32L4R/Sxx the FLASH size is 2Mbyte or 1Mbyte. + * - for STM32L4P/Q5x the FLASH size is 1Mbyte or 512Kbyte. * Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode). * * Bank mode is controlled by two different bits in option bytes register. - * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode. - * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode. + * - for STM32L4R/Sxx + * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode. + * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode. + * - for STM32L4P5/Q5x + * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode. + * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode. + * + */ + +/* STM32WBxxx series for reference. + * + * RM0434 (STM32WB55) + * http://www.st.com/resource/en/reference_manual/dm00318631.pdf + * + * RM0471 (STM32WB50) + * http://www.st.com/resource/en/reference_manual/dm00622834.pdf + */ + +/* STM32WLxxx series for reference. + * + * RM0461 (STM32WLEx) + * http://www.st.com/resource/en/reference_manual/dm00530369.pdf + */ + +/* + * STM32G0xxx series for reference. + * + * RM0444 (STM32G0x1) + * http://www.st.com/resource/en/reference_manual/dm00371828.pdf + * + * RM0454 (STM32G0x0) + * http://www.st.com/resource/en/reference_manual/dm00463896.pdf + */ + +/* + * STM32G4xxx series for reference. + * + * RM0440 (STM32G43x/44x/47x/48x) + * http://www.st.com/resource/en/reference_manual/dm00355726.pdf + * + * Cat. 2 devices have single bank only, page size is 2kByte. + * + * Cat. 3 devices have single and dual bank operating modes, + * Page size is 2kByte (dual mode) or 4kByte (single mode). * + * Bank mode is controlled by bit 22 (DBANK) in option bytes register. + * Both banks are treated as a single OpenOCD bank. */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 -#define STM32_FLASH_BASE 0x40022000 -#define STM32_FLASH_ACR 0x40022000 -#define STM32_FLASH_KEYR 0x40022008 -#define STM32_FLASH_OPTKEYR 0x4002200c -#define STM32_FLASH_SR 0x40022010 -#define STM32_FLASH_CR 0x40022014 -#define STM32_FLASH_OPTR 0x40022020 -#define STM32_FLASH_WRP1AR 0x4002202c -#define STM32_FLASH_WRP1BR 0x40022030 -#define STM32_FLASH_WRP2AR 0x4002204c -#define STM32_FLASH_WRP2BR 0x40022050 - -/* FLASH_CR register bits */ - -#define FLASH_PG (1 << 0) -#define FLASH_PER (1 << 1) -#define FLASH_MER1 (1 << 2) -#define FLASH_PAGE_SHIFT 3 -#define FLASH_CR_BKER (1 << 11) -#define FLASH_MER2 (1 << 15) -#define FLASH_STRT (1 << 16) -#define FLASH_OPTSTRT (1 << 17) -#define FLASH_EOPIE (1 << 24) -#define FLASH_ERRIE (1 << 25) -#define FLASH_OBLLAUNCH (1 << 27) -#define FLASH_OPTLOCK (1 << 30) -#define FLASH_LOCK (1 << 31) - -/* FLASH_SR register bits */ - -#define FLASH_BSY (1 << 16) -/* Fast programming not used => related errors not used*/ -#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ -#define FLASH_SIZERR (1 << 6) /* Size error */ -#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ -#define FLASH_WRPERR (1 << 4) /* Write protection error */ -#define FLASH_PROGERR (1 << 3) /* Programming error */ -#define FLASH_OPERR (1 << 1) /* Operation error */ -#define FLASH_EOP (1 << 0) /* End of operation */ - -#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGSERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR) - -/* STM32_FLASH_OBR bit definitions (reading) */ - -#define OPT_DBANK_LE_1M (1 << 21) /* dual bank for devices up to 1M flash */ -#define OPT_DBANK_GE_2M (1 << 22) /* dual bank for devices with 2M flash */ - -/* register unlock keys */ - -#define KEY1 0x45670123 -#define KEY2 0xCDEF89AB - -/* option register unlock key */ -#define OPTKEY1 0x08192A3B -#define OPTKEY2 0x4C5D6E7F - -#define RDP_LEVEL_0 0xAA -#define RDP_LEVEL_1 0xBB -#define RDP_LEVEL_2 0xCC - - -/* other registers */ -#define DBGMCU_IDCODE 0xE0042000 -#define FLASH_SIZE_REG 0x1FFF75E0 +struct stm32l4_rev { + const uint16_t rev; + const char *str; +}; + +struct stm32l4_part_info { + uint16_t id; + const char *device_str; + const struct stm32l4_rev *revs; + const size_t num_revs; + const uint16_t max_flash_size_kb; + const bool has_dual_bank; + const uint32_t flash_regs_base; + const uint32_t fsize_addr; +}; struct stm32l4_flash_bank { - uint16_t bank2_start; - int probed; + bool probed; + uint32_t idcode; + int bank1_sectors; + bool dual_bank_mode; + int hole_sectors; + uint32_t user_bank_size; + uint32_t wrpxxr_mask; + const struct stm32l4_part_info *part_info; }; -/* flash bank stm32l4x <base> <size> 0 0 <target#> - */ +/* human readable list of families this drivers supports */ +static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0"; + +static const struct stm32l4_rev stm32_415_revs[] = { + { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } +}; + +static const struct stm32l4_rev stm32_435_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_460_revs[] = { + { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_461_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_462_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_464_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_466_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_468_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, +}; + +static const struct stm32l4_rev stm32_469_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, +}; + +static const struct stm32l4_rev stm32_470_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, +}; + +static const struct stm32l4_rev stm32_471_revs[] = { + { 0x1001, "Z" }, +}; + +static const struct stm32l4_rev stm32_495_revs[] = { + { 0x2001, "2.1" }, +}; + +static const struct stm32l4_rev stm32_496_revs[] = { + { 0x1000, "A" }, +}; + +static const struct stm32l4_rev stm32_497_revs[] = { + { 0x1000, "1.0" }, +}; + +static const struct stm32l4_part_info stm32l4_parts[] = { + { + .id = 0x415, + .revs = stm32_415_revs, + .num_revs = ARRAY_SIZE(stm32_415_revs), + .device_str = "STM32L47/L48xx", + .max_flash_size_kb = 1024, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x435, + .revs = stm32_435_revs, + .num_revs = ARRAY_SIZE(stm32_435_revs), + .device_str = "STM32L43/L44xx", + .max_flash_size_kb = 256, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x460, + .revs = stm32_460_revs, + .num_revs = ARRAY_SIZE(stm32_460_revs), + .device_str = "STM32G07/G08xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x461, + .revs = stm32_461_revs, + .num_revs = ARRAY_SIZE(stm32_461_revs), + .device_str = "STM32L49/L4Axx", + .max_flash_size_kb = 1024, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x462, + .revs = stm32_462_revs, + .num_revs = ARRAY_SIZE(stm32_462_revs), + .device_str = "STM32L45/L46xx", + .max_flash_size_kb = 512, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x464, + .revs = stm32_464_revs, + .num_revs = ARRAY_SIZE(stm32_464_revs), + .device_str = "STM32L41/L42xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x466, + .revs = stm32_466_revs, + .num_revs = ARRAY_SIZE(stm32_466_revs), + .device_str = "STM32G03/G04xx", + .max_flash_size_kb = 64, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x468, + .revs = stm32_468_revs, + .num_revs = ARRAY_SIZE(stm32_468_revs), + .device_str = "STM32G43/G44xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x469, + .revs = stm32_469_revs, + .num_revs = ARRAY_SIZE(stm32_469_revs), + .device_str = "STM32G47/G48xx", + .max_flash_size_kb = 512, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x470, + .revs = stm32_470_revs, + .num_revs = ARRAY_SIZE(stm32_470_revs), + .device_str = "STM32L4R/L4Sxx", + .max_flash_size_kb = 2048, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x471, + .revs = stm32_471_revs, + .num_revs = ARRAY_SIZE(stm32_471_revs), + .device_str = "STM32L4P5/L4Q5x", + .max_flash_size_kb = 1024, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x495, + .revs = stm32_495_revs, + .num_revs = ARRAY_SIZE(stm32_495_revs), + .device_str = "STM32WB5x", + .max_flash_size_kb = 1024, + .has_dual_bank = false, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x496, + .revs = stm32_496_revs, + .num_revs = ARRAY_SIZE(stm32_496_revs), + .device_str = "STM32WB3x", + .max_flash_size_kb = 512, + .has_dual_bank = false, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x497, + .revs = stm32_497_revs, + .num_revs = ARRAY_SIZE(stm32_497_revs), + .device_str = "STM32WLEx", + .max_flash_size_kb = 256, + .has_dual_bank = false, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + }, +}; + +/* flash bank stm32l4x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) { struct stm32l4_flash_bank *stm32l4_info; @@ -144,32 +352,40 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) return ERROR_FAIL; /* Checkme: What better error to use?*/ bank->driver_priv = stm32l4_info; - stm32l4_info->probed = 0; + /* The flash write must be aligned to a double word (8-bytes) boundary. + * Ask the flash infrastructure to ensure required alignment */ + bank->write_start_alignment = bank->write_end_alignment = 8; + + stm32l4_info->probed = false; + stm32l4_info->user_bank_size = bank->size; return ERROR_OK; } -static inline int stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg) +static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { - return reg; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_info->part_info->flash_regs_base + reg_offset; } -static inline int stm32l4_get_flash_status(struct flash_bank *bank, uint32_t *status) +static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { - struct target *target = bank->target; - return target_read_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR), status); + return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); +} + +static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) { - struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { - retval = stm32l4_get_flash_status(bank, &status); + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); @@ -195,20 +411,20 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) /* If this operation fails, we ignore it and report the original * retval */ - target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR), - status & FLASH_ERROR); + stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR); } + return retval; } -static int stm32l4_unlock_reg(struct target *target) +static int stm32l4_unlock_reg(struct flash_bank *bank) { uint32_t ctrl; /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ - int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -216,15 +432,15 @@ static int stm32l4_unlock_reg(struct target *target) return ERROR_OK; /* unlock flash registers */ - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -236,11 +452,11 @@ static int stm32l4_unlock_reg(struct target *target) return ERROR_OK; } -static int stm32l4_unlock_option_reg(struct target *target) +static int stm32l4_unlock_option_reg(struct flash_bank *bank) { uint32_t ctrl; - int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -248,15 +464,15 @@ static int stm32l4_unlock_option_reg(struct target *target) return ERROR_OK; /* unlock option registers */ - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -268,66 +484,72 @@ static int stm32l4_unlock_option_reg(struct target *target) return ERROR_OK; } -static int stm32l4_read_option(struct flash_bank *bank, uint32_t address, uint32_t* value) -{ - struct target *target = bank->target; - return target_read_u32(target, address, value); -} - -static int stm32l4_write_option(struct flash_bank *bank, uint32_t address, uint32_t value, uint32_t mask) +static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, + uint32_t value, uint32_t mask) { - struct target *target = bank->target; uint32_t optiondata; + int retval, retval2; - int retval = target_read_u32(target, address, &optiondata); + retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata); if (retval != ERROR_OK) return retval; - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; - retval = stm32l4_unlock_option_reg(target); + retval = stm32l4_unlock_option_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; optiondata = (optiondata & ~mask) | (value & mask); - retval = target_write_u32(target, address, optiondata); + retval = stm32l4_write_flash_reg(bank, reg_offset, optiondata); if (retval != ERROR_OK) - return retval; + goto err_lock; - retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OPTSTRT); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT); if (retval != ERROR_OK) - return retval; + goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK); + if (retval != ERROR_OK) return retval; - return retval; + return retval2; } static int stm32l4_protect_check(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; - stm32l4_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar); - stm32l4_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br); - stm32l4_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar); - stm32l4_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br); - - const uint8_t wrp1a_start = wrp1ar & 0xFF; - const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF; - const uint8_t wrp1b_start = wrp1br & 0xFF; - const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF; - const uint8_t wrp2a_start = wrp2ar & 0xFF; - const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF; - const uint8_t wrp2b_start = wrp2br & 0xFF; - const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF; + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar); + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br); + if (stm32l4_info->part_info->has_dual_bank) { + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar); + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br); + } else { + /* prevent unintialized errors */ + wrp2ar = 0; + wrp2br = 0; + } + + const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask; for (int i = 0; i < bank->num_sectors; i++) { - if (i < stm32l4_info->bank2_start) { + if (i < stm32l4_info->bank1_sectors) { if (((i >= wrp1a_start) && (i <= wrp1a_end)) || ((i >= wrp1b_start) && @@ -336,8 +558,9 @@ static int stm32l4_protect_check(struct flash_bank *bank) else bank->sectors[i].is_protected = 0; } else { + assert(stm32l4_info->part_info->has_dual_bank == true); uint8_t snb; - snb = i - stm32l4_info->bank2_start; + snb = i - stm32l4_info->bank1_sectors; if (((snb >= wrp2a_start) && (snb <= wrp2a_end)) || ((snb >= wrp2b_start) && @@ -352,62 +575,60 @@ static int stm32l4_protect_check(struct flash_bank *bank) static int stm32l4_erase(struct flash_bank *bank, int first, int last) { - struct target *target = bank->target; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int i; + int retval, retval2; - assert(first < bank->num_sectors); - assert(last < bank->num_sectors); + assert((0 <= first) && (first <= last) && (last < bank->num_sectors)); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - int retval; - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; /* 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 + checking the BSY bit in the FLASH_SR register 2. Set the PER bit and select the page and bank you wish to erase in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register 4. Wait for the BSY bit to be cleared */ - struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; for (i = first; i <= last; i++) { uint32_t erase_flags; erase_flags = FLASH_PER | FLASH_STRT; - if (i >= stm32l4_info->bank2_start) { + if (i >= stm32l4_info->bank1_sectors) { uint8_t snb; - snb = i - stm32l4_info->bank2_start; + snb = i - stm32l4_info->bank1_sectors; erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER; } else erase_flags |= i << FLASH_PAGE_SHIFT; - retval = target_write_u32(target, - stm32l4_get_flash_reg(bank, STM32_FLASH_CR), erase_flags); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags); if (retval != ERROR_OK) - return retval; + break; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + break; bank->sectors[i].is_erased = 1; } - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + if (retval != ERROR_OK) return retval; - return ERROR_OK; + return retval2; } static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last) @@ -423,9 +644,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last int ret = ERROR_OK; /* Bank 2 */ uint32_t reg_value = 0xFF; /* Default to bank un-protected */ - if (last >= stm32l4_info->bank2_start) { + if (last >= stm32l4_info->bank1_sectors) { if (set == 1) { - uint8_t begin = first > stm32l4_info->bank2_start ? first : 0x00; + uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00; reg_value = ((last & 0xFF) << 16) | begin; } @@ -433,9 +654,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last } /* Bank 1 */ reg_value = 0xFF; /* Default to bank un-protected */ - if (first < stm32l4_info->bank2_start) { + if (first < stm32l4_info->bank1_sectors) { if (set == 1) { - uint8_t end = last >= stm32l4_info->bank2_start ? 0xFF : last; + uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last; reg_value = (end << 16) | (first & 0xFF); } @@ -445,16 +666,16 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last return ret; } -/* Count is in halfwords */ +/* Count is in double-words */ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) + uint32_t offset, uint32_t count) { struct target *target = bank->target; - uint32_t buffer_size = 16384; + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -476,18 +697,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != - ERROR_OK) { - buffer_size /= 2; - if (buffer_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("large enough working area not available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */ + buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1); + if (buffer_size < 256) { + LOG_WARNING("large enough working area not available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } else if (buffer_size > 16384) { + /* probably won't benefit from more than 16k ... */ + buffer_size = 16384; + } + + if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; @@ -497,17 +719,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, 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 (double word-64bit) */ - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */ 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 / 4); - buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE); + buf_set_u32(reg_params[3].value, 0, 32, count); + buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR)); + buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR)); - retval = target_run_flash_async_algorithm(target, buffer, count, 2, + retval = target_run_flash_async_algorithm(target, buffer, count, 8, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -523,7 +747,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) { LOG_ERROR("flash write failed = %08" PRIx32, error); /* Clear but report errors */ - target_write_u32(target, STM32_FLASH_SR, error); + stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error); retval = ERROR_FAIL; } } @@ -536,195 +760,311 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); return retval; } static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) + uint32_t offset, uint32_t count) { - struct target *target = bank->target; - int retval; + int retval = ERROR_OK, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (offset & 0x7) { - LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", - offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + /* The flash write must be aligned to a double word (8-bytes) boundary. + * The flash infrastructure ensures it, do just a security check */ + assert(offset % 8 == 0); + assert(count % 8 == 0); + + /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether + * data to be written does not go into a gap: + * suppose buffer is fully contained in bank from sector 0 to sector + * num->sectors - 1 and sectors are ordered according to offset + */ + struct flash_sector *head = &bank->sectors[0]; + struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1]; + + while ((head < tail) && (offset >= (head + 1)->offset)) { + /* buffer does not intersect head nor gap behind head */ + head++; + } + + while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) { + /* buffer does not intersect tail nor gap before tail */ + --tail; } - if (count & 0x7) { - LOG_WARNING("Padding %d bytes to keep 8-byte write size", - count & 7); - count = (count + 7) & ~7; - /* This pads the write chunk with random bytes by overrunning the - * write buffer. Padding with the erased pattern 0xff is purely - * cosmetical, as 8-byte flash words are ECC secured and the first - * write will program the ECC bits. A second write would need - * to reprogramm these ECC bits. - * But this can only be done after erase! - */ + LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32, + offset, offset + count - 1, head->offset, tail->offset + tail->size - 1); + + /* Now check that there is no gap from head to tail, this should work + * even for multiple or non-symmetric gaps + */ + while (head < tail) { + if (head->offset + head->size != (head + 1)->offset) { + LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT, + bank->base + head->offset + head->size, + bank->base + (head + 1)->offset - 1); + retval = ERROR_FLASH_DST_OUT_OF_BANK; + } + head++; } - retval = stm32l4_unlock_reg(target); if (retval != ERROR_OK) return retval; - /* Only full double words (8-byte) can be programmed*/ - retval = stm32l4_write_block(bank, buffer, offset, count / 2); + retval = stm32l4_unlock_reg(bank); + if (retval != ERROR_OK) + goto err_lock; + + retval = stm32l4_write_block(bank, buffer, offset, count / 8); + +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + if (retval != ERROR_OK) { - LOG_WARNING("block write failed"); + LOG_ERROR("block write failed"); return retval; + } + return retval2; +} + +static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) +{ + int retval; + + /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */ + retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id); + if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { + retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id); + if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { + LOG_ERROR("can't get device id"); + return (retval == ERROR_OK) ? ERROR_FAIL : retval; } + } - LOG_WARNING("block write succeeded"); - return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); + return retval; } static int stm32l4_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - int i; - uint16_t flash_size_in_kb = 0xffff; - uint16_t max_flash_size_in_kb; + const struct stm32l4_part_info *part_info; + uint16_t flash_size_kb = 0xffff; uint32_t device_id; uint32_t options; - uint32_t base_address = 0x08000000; - stm32l4_info->probed = 0; + stm32l4_info->probed = false; - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id); + /* read stm32 device id registers */ + int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode); if (retval != ERROR_OK) return retval; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); - /* set max flash size depending on family */ - switch (device_id & 0xfff) { - case 0x470: - max_flash_size_in_kb = 2048; - break; - case 0x461: - case 0x415: - max_flash_size_in_kb = 1024; - break; - case 0x462: - max_flash_size_in_kb = 512; - break; - case 0x435: - max_flash_size_in_kb = 256; - break; - default: - LOG_WARNING("Cannot identify target as an STM32L4 family device."); + device_id = stm32l4_info->idcode & 0xFFF; + + for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) { + if (device_id == stm32l4_parts[n].id) + stm32l4_info->part_info = &stm32l4_parts[n]; + } + + if (!stm32l4_info->part_info) { + LOG_WARNING("Cannot identify target as an %s family device.", device_families); return ERROR_FAIL; } + part_info = stm32l4_info->part_info; + + char device_info[1024]; + retval = bank->driver->info(bank, device_info, sizeof(device_info)); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info); + /* get flash size from target. */ - retval = target_read_u16(target, FLASH_SIZE_REG, &flash_size_in_kb); + retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { + if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0 + || flash_size_kb > part_info->max_flash_size_kb) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", - max_flash_size_in_kb); - flash_size_in_kb = max_flash_size_in_kb; + part_info->max_flash_size_kb); + flash_size_kb = part_info->max_flash_size_kb; + } + + /* if the user sets the size manually then ignore the probed value + * this allows us to work around devices that have a invalid flash size register value */ + if (stm32l4_info->user_bank_size) { + LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE"); + flash_size_kb = stm32l4_info->user_bank_size / 1024; } - LOG_INFO("flash size = %dkbytes", flash_size_in_kb); + LOG_INFO("flash size = %dkbytes", flash_size_kb); /* did we assign a flash size? */ - assert((flash_size_in_kb != 0xffff) && flash_size_in_kb); - - /* get options for DUAL BANK. */ - retval = target_read_u32(target, STM32_FLASH_OPTR, &options); + assert((flash_size_kb != 0xffff) && flash_size_kb); + /* read flash option register */ + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options); if (retval != ERROR_OK) return retval; + stm32l4_info->bank1_sectors = 0; + stm32l4_info->hole_sectors = 0; + int num_pages = 0; - int page_size = 0; - - switch (device_id & 0xfff) { - case 0x470: - /* L4R/S have 1M or 2M FLASH and dual/single bank mode. - * Page size is 4K or 8K.*/ - if (flash_size_in_kb == 2048) { - stm32l4_info->bank2_start = 256; - if (options & OPT_DBANK_GE_2M) { - page_size = 4096; - num_pages = 512; - } else { - page_size = 8192; - num_pages = 256; - } - break; - } - if (flash_size_in_kb == 1024) { - stm32l4_info->bank2_start = 128; - if (options & OPT_DBANK_LE_1M) { - page_size = 4096; - num_pages = 256; - } else { - page_size = 8192; - num_pages = 128; - } - break; - } - /* Invalid FLASH size for this device. */ - LOG_WARNING("Invalid flash size for STM32L4+ family device."); - return ERROR_FAIL; - case 0x461: - case 0x415: - /* These are dual-bank devices, we need to check the OPT_DBANK_LE_1M bit here */ - page_size = 2048; - num_pages = flash_size_in_kb / 2; - /* check that calculation result makes sense */ - assert(num_pages > 0); - if ((flash_size_in_kb == 1024) || !(options & OPT_DBANK_LE_1M)) - stm32l4_info->bank2_start = 256; - else - stm32l4_info->bank2_start = num_pages / 2; - break; - case 0x462: - case 0x435: - default: - /* These are single-bank devices */ - page_size = 2048; - num_pages = flash_size_in_kb / 2; - /* check that calculation result makes sense */ - assert(num_pages > 0); - stm32l4_info->bank2_start = UINT16_MAX; - break; + int page_size_kb = 0; + + stm32l4_info->dual_bank_mode = false; + + switch (device_id) { + case 0x415: /* STM32L47/L48xx */ + case 0x461: /* STM32L49/L4Axx */ + /* if flash size is max (1M) the device is always dual bank + * 0x415: has variants with 512K + * 0x461: has variants with 512 and 256 + * for these variants: + * if DUAL_BANK = 0 -> single bank + * else -> dual bank without gap + * note: the page size is invariant + */ + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + + /* check DUAL_BANK bit[21] if the flash is less than 1M */ + if (flash_size_kb == 1024 || (options & BIT(21))) { + stm32l4_info->dual_bank_mode = true; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; + case 0x435: /* STM32L43/L44xx */ + case 0x460: /* STM32G07/G08xx */ + case 0x462: /* STM32L45/L46xx */ + case 0x464: /* STM32L41/L42xx */ + case 0x466: /* STM32G03/G04xx */ + case 0x468: /* STM32G43/G44xx */ + case 0x497: /* STM32WLEx */ + /* single bank flash */ + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + break; + case 0x469: /* STM32G47/G48xx */ + /* STM32G47/8 can be single/dual bank: + * if DUAL_BANK = 0 -> single bank + * else -> dual bank WITH gap + */ + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + if (options & BIT(22)) { + stm32l4_info->dual_bank_mode = true; + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages / 2; + + /* for devices with trimmed flash, there is a gap between both banks */ + stm32l4_info->hole_sectors = + (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb); + } + break; + case 0x470: /* STM32L4R/L4Sxx */ + case 0x471: /* STM32L4P5/L4Q5x */ + /* STM32L4R/S can be single/dual bank: + * if size = 2M check DBANK bit(22) + * if size = 1M check DB1M bit(21) + * STM32L4P/Q can be single/dual bank + * if size = 1M check DBANK bit(22) + * if size = 512K check DB512K bit(21) + */ + page_size_kb = 8; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; + if ((use_dbank_bit && (options & BIT(22))) || + (!use_dbank_bit && (options & BIT(21)))) { + stm32l4_info->dual_bank_mode = true; + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; + case 0x495: /* STM32WB5x */ + case 0x496: /* STM32WB3x */ + /* single bank flash */ + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + break; + default: + LOG_ERROR("unsupported device"); + return ERROR_FAIL; + } + + LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single"); + + const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb; + + if (gap_size_kb != 0) { + LOG_INFO("gap detected from 0x%08" PRIx32 " to 0x%08" PRIx32, + STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors + * page_size_kb * 1024, + STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors + * page_size_kb + gap_size_kb) * 1024 - 1); } - /* Release sector table if allocated. */ + /* number of significant bits in WRPxxR differs per device, + * always right adjusted, on some devices non-implemented + * bits read as '0', on others as '1' ... + * notably G4 Cat. 2 implement only 6 bits, contradicting the RM + */ + + /* use *max_flash_size* instead of actual size as the trimmed versions + * certainly use the same number of bits + * max_flash_size is always power of two, so max_pages too + */ + uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb; + assert((max_pages & (max_pages - 1)) == 0); + + /* in dual bank mode number of pages is doubled, but extra bit is bank selection */ + stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1); + assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0); + LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask); + if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } - /* Set bank configuration and construct sector table. */ - bank->base = base_address; - bank->size = num_pages * page_size; + bank->size = (flash_size_kb + gap_size_kb) * 1024; + bank->base = STM32_FLASH_BANK_BASE; bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - if (!bank->sectors) - return ERROR_FAIL; /* Checkme: What better error to use?*/ + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (bank->sectors == NULL) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } - for (i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * page_size; - bank->sectors[i].size = page_size; + for (int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * page_size_kb * 1024; + /* in dual bank configuration, if there is a gap between banks + * we fix up the sector offset to consider this gap */ + if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors) + bank->sectors[i].offset += gap_size_kb * 1024; + bank->sectors[i].size = page_size_kb * 1024; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - stm32l4_info->probed = 1; - + stm32l4_info->probed = true; return ERROR_OK; } @@ -733,107 +1073,89 @@ static int stm32l4_auto_probe(struct flash_bank *bank) struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_info->probed) return ERROR_OK; + return stm32l4_probe(bank); } static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) { - struct target *target = bank->target; - uint32_t dbgmcu_idcode; - - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, &dbgmcu_idcode); - if (retval != ERROR_OK) - return retval; - - uint16_t device_id = dbgmcu_idcode & 0xfff; - uint8_t rev_id = dbgmcu_idcode >> 28; - uint8_t rev_minor = 0; - int i; - - for (i = 16; i < 28; i++) { - if (dbgmcu_idcode & (1 << i)) - rev_minor++; - else - break; - } - - const char *device_str; - - switch (device_id) { - case 0x470: - device_str = "STM32L4R/4Sxx"; - break; - - case 0x461: - device_str = "STM32L496/4A6"; - break; - - case 0x415: - device_str = "STM32L475/476/486"; - break; - - case 0x462: - device_str = "STM32L45x/46x"; - break; - - case 0x435: - device_str = "STM32L43x/44x"; - break; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + const struct stm32l4_part_info *part_info = stm32l4_info->part_info; + + if (part_info) { + const char *rev_str = NULL; + uint16_t rev_id = stm32l4_info->idcode >> 16; + for (unsigned int i = 0; i < part_info->num_revs; i++) { + if (rev_id == part_info->revs[i].rev) { + rev_str = part_info->revs[i].str; + + if (rev_str != NULL) { + snprintf(buf, buf_size, "%s - Rev: %s%s", + part_info->device_str, rev_str, stm32l4_info->probed ? + (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); + return ERROR_OK; + } + } + } - default: - snprintf(buf, buf_size, "Cannot identify target as a STM32L4\n"); + snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s", + part_info->device_str, rev_id, stm32l4_info->probed ? + (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); + return ERROR_OK; + } else { + snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families); return ERROR_FAIL; } - snprintf(buf, buf_size, "%s - Rev: %1d.%02d", - device_str, rev_id, rev_minor); - return ERROR_OK; } -static int stm32l4_mass_erase(struct flash_bank *bank, uint32_t action) +static int stm32l4_mass_erase(struct flash_bank *bank) { - int retval; + int retval, retval2; struct target *target = bank->target; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + uint32_t action = FLASH_MER1; + + if (stm32l4_info->part_info->has_dual_bank) + action |= FLASH_MER2; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; /* mass erase flash memory */ - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), action); + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT / 10); if (retval != ERROR_OK) - return retval; - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), - action | FLASH_STRT); + goto err_lock; + + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action); if (retval != ERROR_OK) - return retval; + goto err_lock; - retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto err_lock; + + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; - return ERROR_OK; + return retval2; } COMMAND_HANDLER(stm32l4_handle_mass_erase_command) { - int i; - uint32_t action; - if (CMD_ARGC < 1) { command_print(CMD, "stm32l4x mass_erase <STM32L4 bank>"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -844,11 +1166,10 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command) if (ERROR_OK != retval) return retval; - action = FLASH_MER1 | FLASH_MER2; - retval = stm32l4_mass_erase(bank, action); + retval = stm32l4_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32l4x mass erase complete"); @@ -871,12 +1192,13 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command) if (ERROR_OK != retval) return retval; - uint32_t reg_addr = STM32_FLASH_BASE; + uint32_t reg_offset, reg_addr; uint32_t value = 0; - reg_addr += strtoul(CMD_ARGV[1], NULL, 16); + reg_offset = strtoul(CMD_ARGV[1], NULL, 16); + reg_addr = stm32l4_get_flash_reg(bank, reg_offset); - retval = stm32l4_read_option(bank, reg_addr, &value); + retval = stm32l4_read_flash_reg(bank, reg_offset, &value); if (ERROR_OK != retval) return retval; @@ -897,11 +1219,11 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command) if (ERROR_OK != retval) return retval; - uint32_t reg_addr = STM32_FLASH_BASE; + uint32_t reg_offset; uint32_t value = 0; uint32_t mask = 0xFFFFFFFF; - reg_addr += strtoul(CMD_ARGV[1], NULL, 16); + reg_offset = strtoul(CMD_ARGV[1], NULL, 16); value = strtoul(CMD_ARGV[2], NULL, 16); if (CMD_ARGC > 3) mask = strtoul(CMD_ARGV[3], NULL, 16); @@ -910,13 +1232,13 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command) "INFO: a reset or power cycle is required " "for the new settings to take effect.", bank->driver->name); - retval = stm32l4_write_option(bank, reg_addr, value, mask); + retval = stm32l4_write_option(bank, reg_offset, value, mask); return retval; } COMMAND_HANDLER(stm32l4_handle_option_load_command) { - if (CMD_ARGC < 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; @@ -924,20 +1246,27 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command) if (ERROR_OK != retval) return retval; - struct target *target = bank->target; - - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (ERROR_OK != retval) return retval; - retval = stm32l4_unlock_option_reg(target); + retval = stm32l4_unlock_option_reg(bank); if (ERROR_OK != retval) return retval; - /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */ - retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH); + /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload, + * but the RMs explicitly do *NOT* list this as power-on reset cause, and: + * "Note: If the read protection is set while the debugger is still + * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." + */ + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH); + + command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); + + /* Need to re-probe after change */ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + stm32l4_info->probed = false; - command_print(CMD, "stm32l4x option load (POR) completed."); return retval; } diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h new file mode 100644 index 0000000..abd8010 --- /dev/null +++ b/src/flash/nor/stm32l4x.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2015 by Uwe Bonnes * + * bon@elektron.ikp.physik.tu-darmstadt.de * + * + * 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/>. * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_STM32L4X +#define OPENOCD_FLASH_NOR_STM32L4X + +/* Flash registers offsets */ +#define STM32_FLASH_ACR 0x00 +#define STM32_FLASH_KEYR 0x08 +#define STM32_FLASH_OPTKEYR 0x0c +#define STM32_FLASH_SR 0x10 +#define STM32_FLASH_CR 0x14 +#define STM32_FLASH_OPTR 0x20 +#define STM32_FLASH_WRP1AR 0x2c +#define STM32_FLASH_WRP1BR 0x30 +#define STM32_FLASH_WRP2AR 0x4c +#define STM32_FLASH_WRP2BR 0x50 + +/* FLASH_CR register bits */ +#define FLASH_PG (1 << 0) +#define FLASH_PER (1 << 1) +#define FLASH_MER1 (1 << 2) +#define FLASH_PAGE_SHIFT 3 +#define FLASH_CR_BKER (1 << 11) +#define FLASH_MER2 (1 << 15) +#define FLASH_STRT (1 << 16) +#define FLASH_OPTSTRT (1 << 17) +#define FLASH_EOPIE (1 << 24) +#define FLASH_ERRIE (1 << 25) +#define FLASH_OBL_LAUNCH (1 << 27) +#define FLASH_OPTLOCK (1 << 30) +#define FLASH_LOCK (1 << 31) + +/* FLASH_SR register bits */ +#define FLASH_BSY (1 << 16) + +/* Fast programming not used => related errors not used*/ +#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ +#define FLASH_SIZERR (1 << 6) /* Size error */ +#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ +#define FLASH_WRPERR (1 << 4) /* Write protection error */ +#define FLASH_PROGERR (1 << 3) /* Programming error */ +#define FLASH_OPERR (1 << 1) /* Operation error */ +#define FLASH_EOP (1 << 0) /* End of operation */ +#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \ + FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR) + +/* register unlock keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* option register unlock key */ +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define RDP_LEVEL_0 0xAA +#define RDP_LEVEL_1 0xBB +#define RDP_LEVEL_2 0xCC + +/* other registers */ +#define DBGMCU_IDCODE_G0 0x40015800 +#define DBGMCU_IDCODE_L4_G4 0xE0042000 +#define DBGMCU_IDCODE_L5 0xE0044000 + +#define STM32_FLASH_BANK_BASE 0x08000000 + +#endif diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index e6473f8..c3f9c72 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -128,7 +128,7 @@ struct stm32lx_part_info { }; struct stm32lx_flash_bank { - int probed; + bool probed; uint32_t idcode; uint32_t user_bank_size; uint32_t flash_base; @@ -297,7 +297,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) bank->driver_priv = stm32lx_info; - stm32lx_info->probed = 0; + stm32lx_info->probed = false; stm32lx_info->user_bank_size = bank->size; /* the stm32l erased value is 0x00 */ @@ -308,8 +308,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) COMMAND_HANDLER(stm32lx_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -321,7 +319,7 @@ COMMAND_HANDLER(stm32lx_handle_mass_erase_command) retval = stm32lx_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32lx mass erase complete"); @@ -731,14 +729,13 @@ static int stm32lx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_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; unsigned int n; - stm32lx_info->probed = 0; + stm32lx_info->probed = false; int retval = stm32lx_read_id_code(bank->target, &device_id); if (retval != ERROR_OK) @@ -756,7 +753,7 @@ static int stm32lx_probe(struct flash_bank *bank) } if (n == ARRAY_SIZE(stm32lx_parts)) { - LOG_WARNING("Cannot identify target as a STM32L family."); + LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device."); return ERROR_FAIL; } else { LOG_INFO("Device: %s", stm32lx_info->part_info.device_str); @@ -852,14 +849,14 @@ static int stm32lx_probe(struct flash_bank *bank) return ERROR_FAIL; } - for (i = 0; i < num_sectors; i++) { + for (int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * FLASH_SECTOR_SIZE; bank->sectors[i].size = FLASH_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } - stm32lx_info->probed = 1; + stm32lx_info->probed = true; return ERROR_OK; } diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index bd313a0..fb2053b 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -109,7 +109,7 @@ COMMAND_HANDLER(handle_flash_info_command) return retval; } if (retval == ERROR_FLASH_OPER_UNSUPPORTED) - LOG_WARNING("Flash protection check is not implemented."); + LOG_INFO("Flash protection check is not implemented."); command_print(CMD, "#%d : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 @@ -476,7 +476,7 @@ COMMAND_HANDLER(handle_flash_write_image_command) COMMAND_HANDLER(handle_flash_fill_command) { target_addr_t address; - uint32_t pattern; + uint64_t pattern; uint32_t count; struct target *target = get_current_target(CMD_CTX); unsigned i; @@ -487,7 +487,7 @@ COMMAND_HANDLER(handle_flash_fill_command) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); struct flash_bank *bank; @@ -496,6 +496,9 @@ COMMAND_HANDLER(handle_flash_fill_command) return retval; switch (CMD_NAME[4]) { + case 'd': + wordsize = 8; + break; case 'w': wordsize = 4; break; @@ -509,6 +512,11 @@ COMMAND_HANDLER(handle_flash_fill_command) return ERROR_COMMAND_SYNTAX_ERROR; } + if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) { + command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize); + return ERROR_FAIL; + } + if (count == 0) return ERROR_OK; @@ -541,6 +549,10 @@ COMMAND_HANDLER(handle_flash_fill_command) uint8_t *ptr = buffer + padding_at_start; switch (wordsize) { + case 8: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u64(target, ptr, pattern); + break; case 4: for (i = 0; i < count; i++, ptr += wordsize) target_buffer_set_u32(target, ptr, pattern); @@ -577,9 +589,12 @@ COMMAND_HANDLER(handle_flash_fill_command) goto done; for (i = 0, ptr = buffer; i < count; i++) { - uint32_t readback = 0; + uint64_t readback = 0; switch (wordsize) { + case 8: + readback = target_buffer_get_u64(target, ptr); + break; case 4: readback = target_buffer_get_u32(target, ptr); break; @@ -593,7 +608,7 @@ COMMAND_HANDLER(handle_flash_fill_command) if (readback != pattern) { LOG_ERROR( "Verification error address " TARGET_ADDR_FMT - ", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32, + ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64, address + i * wordsize, readback, pattern); retval = ERROR_FAIL; goto done; @@ -613,6 +628,67 @@ done: return retval; } +COMMAND_HANDLER(handle_flash_md_command) +{ + int retval; + + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + + uint32_t count = 1; + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count); + + unsigned int wordsize; + switch (CMD_NAME[2]) { + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (count == 0) + return ERROR_OK; + + struct target *target = get_current_target(CMD_CTX); + struct flash_bank *bank; + retval = get_flash_bank_by_addr(target, address, true, &bank); + if (retval != ERROR_OK) + return retval; + + uint32_t offset = address - bank->base; + uint32_t sizebytes = count * wordsize; + if (offset + sizebytes > bank->size) { + command_print(CMD, "Cannot cross flash bank borders"); + return ERROR_FAIL; + } + + uint8_t *buffer = calloc(count, wordsize); + if (buffer == NULL) { + command_print(CMD, "No memory for flash read buffer"); + return ERROR_FAIL; + } + + retval = flash_driver_read(bank, buffer, offset, sizebytes); + if (retval == ERROR_OK) + target_handle_md_output(CMD, target, address, wordsize, count, buffer); + + free(buffer); + + return retval; +} + + COMMAND_HANDLER(handle_flash_write_bank_command) { uint32_t offset; @@ -952,7 +1028,7 @@ COMMAND_HANDLER(handle_flash_padded_value_command) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value); - command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", \ + command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", p->default_padded_value, p->bank_number); return retval; @@ -1003,6 +1079,14 @@ static const struct command_registration flash_exec_command_handlers[] = { }, { + .name = "filld", + .handler = handle_flash_fill_command, + .mode = COMMAND_EXEC, + .usage = "address value n", + .help = "Fill n double-words with 64-bit value, starting at " + "word address. (No autoerase.)", + }, + { .name = "fillw", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, @@ -1027,6 +1111,27 @@ static const struct command_registration flash_exec_command_handlers[] = { "word address. (No autoerase.)", }, { + .name = "mdb", + .handler = handle_flash_md_command, + .mode = COMMAND_EXEC, + .usage = "address [count]", + .help = "Display bytes from flash.", + }, + { + .name = "mdh", + .handler = handle_flash_md_command, + .mode = COMMAND_EXEC, + .usage = "address [count]", + .help = "Display half-words from flash.", + }, + { + .name = "mdw", + .handler = handle_flash_md_command, + .mode = COMMAND_EXEC, + .usage = "address [count]", + .help = "Display words from flash.", + }, + { .name = "write_bank", .handler = handle_flash_write_bank_command, .mode = COMMAND_EXEC, diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index 90557b8..bc16aca 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -709,6 +709,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) * Select one or more bits in FMBSEA or FMBSEB to disable Level 1 * protection for the particular sector to be erased/written. */ + assert(sector >= 0); if (sector < 16) { target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector)); diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index a0c35c5..ba35c2c 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -625,7 +625,6 @@ static int xcf_probe(struct flash_bank *bank) default: LOG_ERROR("Unknown flash device ID 0x%X", id); return ERROR_FAIL; - break; } bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector)); diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index ff053ae..aafb939 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -17,9 +17,12 @@ proc program_error {description exit} { proc program {filename args} { set exit 0 + set needsflash 1 foreach arg $args { - if {[string equal $arg "verify"]} { + if {[string equal $arg "preverify"]} { + set preverify 1 + } elseif {[string equal $arg "verify"]} { set verify 1 } elseif {[string equal $arg "reset"]} { set reset 1 @@ -30,6 +33,15 @@ proc program {filename args} { } } + # Set variables + set filename \{$filename\} + if {[info exists address]} { + set flash_args "$filename $address" + } else { + set flash_args "$filename" + } + + # make sure init is called if {[catch {init}] != 0} { program_error "** OpenOCD init failed **" 1 @@ -40,40 +52,46 @@ proc program {filename args} { program_error "** Unable to reset target **" $exit } - # start programming phase - echo "** Programming Started **" - set filename \{$filename\} - if {[info exists address]} { - set flash_args "$filename $address" - } else { - set flash_args "$filename" + # Check whether programming is needed + if {[info exists preverify]} { + echo "**pre-verifying**" + if {[catch {eval verify_image $flash_args}] == 0} { + echo "**Verified OK - No flashing**" + set needsflash 0 + } } - if {[catch {eval flash write_image erase $flash_args}] == 0} { - echo "** Programming Finished **" - if {[info exists verify]} { - # verify phase - echo "** Verify Started **" - if {[catch {eval verify_image $flash_args}] == 0} { - echo "** Verified OK **" - } else { - program_error "** Verify Failed **" $exit + # start programming phase + if {$needsflash == 1} { + echo "** Programming Started **" + + if {[catch {eval flash write_image erase $flash_args}] == 0} { + echo "** Programming Finished **" + if {[info exists verify]} { + # verify phase + echo "** Verify Started **" + if {[catch {eval verify_image $flash_args}] == 0} { + echo "** Verified OK **" + } else { + program_error "** Verify Failed **" $exit + } } + } else { + program_error "** Programming Failed **" $exit } + } - if {[info exists reset]} { - # reset target if requested - if {$exit == 1} { - # also disable target polling, we are shutting down anyway - poll off - } - echo "** Resetting Target **" - reset run + if {[info exists reset]} { + # reset target if requested + if {$exit == 1} { + # also disable target polling, we are shutting down anyway + poll off } - } else { - program_error "** Programming Failed **" $exit + echo "** Resetting Target **" + reset run } + if {$exit == 1} { shutdown } @@ -81,25 +99,25 @@ proc program {filename args} { } add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional" -add_usage_text program "<filename> \[address\] \[verify\] \[reset\] \[exit\]" +add_usage_text program "<filename> \[address\] \[pre-verify\] \[verify\] \[reset\] \[exit\]" -# stm32f0x uses the same flash driver as the stm32f1x -# this alias enables the use of either name. -proc stm32f0x args { - eval stm32f1x $args -} +# stm32[f0x|f3x] uses the same flash driver as the stm32f1x +proc stm32f0x args { eval stm32f1x $args } +proc stm32f3x args { eval stm32f1x $args } -# stm32f3x uses the same flash driver as the stm32f1x -# this alias enables the use of either name. -proc stm32f3x args { - eval stm32f1x $args -} +# stm32[f4x|f7x] uses the same flash driver as the stm32f2x +proc stm32f4x args { eval stm32f2x $args } +proc stm32f7x args { eval stm32f2x $args } -# stm32f4x uses the same flash driver as the stm32f2x -# this alias enables the use of either name. -proc stm32f4x args { - eval stm32f2x $args -} +# stm32lx driver supports both STM32 L0 and L1 devices +proc stm32l0x args { eval stm32lx $args } +proc stm32l1x args { eval stm32lx $args } + +# stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x +proc stm32g0x args { eval stm32l4x $args } +proc stm32g4x args { eval stm32l4x $args } +proc stm32wbx args { eval stm32l4x $args } +proc stm32wlx args { eval stm32l4x $args } # ease migration to updated flash driver proc stm32x args { |