diff options
Diffstat (limited to 'src/flash')
58 files changed, 3370 insertions, 348 deletions
diff --git a/src/flash/common.c b/src/flash/common.c index ebd9396..9f40a3a 100644 --- a/src/flash/common.c +++ b/src/flash/common.c @@ -11,14 +11,14 @@ #include "common.h" #include <helper/log.h> -unsigned get_flash_name_index(const char *name) +unsigned int get_flash_name_index(const char *name) { const char *name_index = strrchr(name, '.'); if (!name_index) return 0; if (name_index[1] < '0' || name_index[1] > '9') return ~0U; - unsigned requested; + unsigned int requested; int retval = parse_uint(name_index + 1, &requested); /* detect parsing error by forcing past end of bank list */ return (retval == ERROR_OK) ? requested : ~0U; @@ -26,7 +26,7 @@ unsigned get_flash_name_index(const char *name) bool flash_driver_name_matches(const char *name, const char *expected) { - unsigned blen = strlen(name); + unsigned int blen = strlen(name); /* only match up to the length of the driver name... */ if (strncmp(name, expected, blen) != 0) return false; diff --git a/src/flash/common.h b/src/flash/common.h index 15aea5b..6ceaa8d 100644 --- a/src/flash/common.h +++ b/src/flash/common.h @@ -17,7 +17,7 @@ * name provides a suffix but it does not parse as an unsigned integer, * the routine returns ~0U. This will prevent further matching. */ -unsigned get_flash_name_index(const char *name); +unsigned int get_flash_name_index(const char *name); /** * Attempt to match the @c expected name with the @c name of a driver. * @param name The name of the driver (from the bank's device structure). diff --git a/src/flash/nand/arm_io.c b/src/flash/nand/arm_io.c index 80bd0cf..dd012e1 100644 --- a/src/flash/nand/arm_io.c +++ b/src/flash/nand/arm_io.c @@ -31,12 +31,12 @@ * @return Success or failure of the operation */ static int arm_code_to_working_area(struct target *target, - const uint32_t *code, unsigned code_size, - unsigned additional, struct working_area **area) + const uint32_t *code, unsigned int code_size, + unsigned int additional, struct working_area **area) { uint8_t code_buf[code_size]; int retval; - unsigned size = code_size + additional; + unsigned int size = code_size + additional; /* REVISIT this assumes size doesn't ever change. * That's usually correct; but there are boards with diff --git a/src/flash/nand/arm_io.h b/src/flash/nand/arm_io.h index 10f0e66..760dc7e 100644 --- a/src/flash/nand/arm_io.h +++ b/src/flash/nand/arm_io.h @@ -27,7 +27,7 @@ struct arm_nand_data { struct working_area *copy_area; /** The chunk size is the page size or ECC chunk. */ - unsigned chunk_size; + unsigned int chunk_size; /** Where data is read from or written to. */ uint32_t data; diff --git a/src/flash/nand/at91sam9.c b/src/flash/nand/at91sam9.c index bfbba67..41cb07b 100644 --- a/src/flash/nand/at91sam9.c +++ b/src/flash/nand/at91sam9.c @@ -389,9 +389,8 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, uint32_t bit = parity & 0x0F; data[word] ^= (0x1) << bit; - LOG_INFO("Data word %d, bit %d corrected.", - (unsigned) word, - (unsigned) bit); + LOG_INFO("Data word %" PRIu32 ", bit %" PRIu32 " corrected.", + word, bit); } } @@ -533,7 +532,7 @@ COMMAND_HANDLER(handle_at91sam9_cle_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; - unsigned num, address_line; + unsigned int num, address_line; if (CMD_ARGC != 2) { command_print(CMD, "incorrect number of arguments for 'at91sam9 cle' command"); @@ -563,7 +562,7 @@ COMMAND_HANDLER(handle_at91sam9_ale_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; - unsigned num, address_line; + unsigned int num, address_line; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -591,7 +590,7 @@ COMMAND_HANDLER(handle_at91sam9_rdy_busy_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; - unsigned num, base_pioc, pin_num; + unsigned int num, base_pioc, pin_num; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; @@ -622,7 +621,7 @@ COMMAND_HANDLER(handle_at91sam9_ce_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; - unsigned num, base_pioc, pin_num; + unsigned int num, base_pioc, pin_num; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index 37e1d12..c5430ae 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -165,8 +165,8 @@ static struct nand_ecclayout nand_oob_8 = { */ static struct nand_device *get_nand_device_by_name(const char *name) { - unsigned requested = get_flash_name_index(name); - unsigned found = 0; + unsigned int requested = get_flash_name_index(name); + unsigned int found = 0; struct nand_device *nand; for (nand = nand_devices; nand; nand = nand->next) { @@ -194,7 +194,7 @@ struct nand_device *get_nand_device_by_num(int num) return NULL; } -COMMAND_HELPER(nand_command_get_device, unsigned name_index, +COMMAND_HELPER(nand_command_get_device, unsigned int name_index, struct nand_device **nand) { const char *str = CMD_ARGV[name_index]; @@ -202,7 +202,7 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index, if (*nand) return ERROR_OK; - unsigned num; + unsigned int num; COMMAND_PARSE_NUMBER(uint, str, num); *nand = get_nand_device_by_num(num); if (!*nand) { diff --git a/src/flash/nand/core.h b/src/flash/nand/core.h index 137298c..4286e11 100644 --- a/src/flash/nand/core.h +++ b/src/flash/nand/core.h @@ -209,7 +209,7 @@ int nand_correct_data(struct nand_device *nand, u_char *dat, int nand_register_commands(struct command_context *cmd_ctx); /** helper for parsing a nand device command argument string */ -COMMAND_HELPER(nand_command_get_device, unsigned name_index, +COMMAND_HELPER(nand_command_get_device, unsigned int name_index, struct nand_device **nand); diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index b7169fe..17040fe 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -379,7 +379,7 @@ static int davinci_writepage_tail(struct nand_device *nand, static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { - unsigned oob_offset; + unsigned int oob_offset; struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index ce79e13..5d99102 100644 --- a/src/flash/nand/driver.c +++ b/src/flash/nand/driver.c @@ -33,7 +33,7 @@ static struct nand_flash_controller *nand_flash_controllers[] = { struct nand_flash_controller *nand_driver_find_by_name(const char *name) { - for (unsigned i = 0; nand_flash_controllers[i]; i++) { + for (unsigned int i = 0; nand_flash_controllers[i]; i++) { struct nand_flash_controller *controller = nand_flash_controllers[i]; if (strcmp(name, controller->name) == 0) return controller; @@ -42,7 +42,7 @@ struct nand_flash_controller *nand_driver_find_by_name(const char *name) } int nand_driver_walk(nand_driver_walker_t f, void *x) { - for (unsigned i = 0; nand_flash_controllers[i]; i++) { + for (unsigned int i = 0; nand_flash_controllers[i]; i++) { int retval = (*f)(nand_flash_controllers[i], x); if (retval != ERROR_OK) return retval; diff --git a/src/flash/nand/fileio.c b/src/flash/nand/fileio.c index ca618b3..613ae3c 100644 --- a/src/flash/nand/fileio.c +++ b/src/flash/nand/fileio.c @@ -107,7 +107,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, { nand_fileio_init(state); - unsigned minargs = need_size ? 4 : 3; + unsigned int minargs = need_size ? 4 : 3; if (minargs > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; @@ -131,7 +131,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, } if (minargs < CMD_ARGC) { - for (unsigned i = minargs; i < CMD_ARGC; i++) { + for (unsigned int i = minargs; i < CMD_ARGC; i++) { if (!strcmp(CMD_ARGV[i], "oob_raw")) state->oob_format |= NAND_OOB_RAW; else if (!strcmp(CMD_ARGV[i], "oob_only")) diff --git a/src/flash/nand/lpc3180.c b/src/flash/nand/lpc3180.c index c1af1d7..d221c34 100644 --- a/src/flash/nand/lpc3180.c +++ b/src/flash/nand/lpc3180.c @@ -890,8 +890,7 @@ static int lpc3180_read_page(struct nand_device *nand, if (mlc_isr & 0x8) { if (mlc_isr & 0x40) { - LOG_ERROR("uncorrectable error detected: 0x%2.2x", - (unsigned)mlc_isr); + LOG_ERROR("uncorrectable error detected: 0x%2.2" PRIx32, mlc_isr); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; @@ -1275,7 +1274,7 @@ COMMAND_HANDLER(handle_lpc3180_select_command) if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned num; + unsigned int num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct nand_device *nand = get_nand_device_by_num(num); if (!nand) { diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c index 1fdae9f..c67f2aa 100644 --- a/src/flash/nand/lpc32xx.c +++ b/src/flash/nand/lpc32xx.c @@ -1386,8 +1386,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, if (mlc_isr & 0x8) { if (mlc_isr & 0x40) { - LOG_ERROR("uncorrectable error detected: " - "0x%2.2x", (unsigned)mlc_isr); + LOG_ERROR("uncorrectable error detected: 0x%2.2" PRIx32, mlc_isr); return ERROR_NAND_OPERATION_FAILED; } @@ -1743,7 +1742,7 @@ COMMAND_HANDLER(handle_lpc32xx_select_command) if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned num; + unsigned int num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct nand_device *nand = get_nand_device_by_num(num); if (!nand) { diff --git a/src/flash/nand/mx3.h b/src/flash/nand/mx3.h index b272962..648cd86 100644 --- a/src/flash/nand/mx3.h +++ b/src/flash/nand/mx3.h @@ -86,10 +86,10 @@ enum mx_nf_finalize_action { }; struct mx3_nf_flags { - unsigned target_little_endian:1; - unsigned nand_readonly:1; - unsigned one_kb_sram:1; - unsigned hw_ecc_enabled:1; + unsigned int target_little_endian:1; + unsigned int nand_readonly:1; + unsigned int one_kb_sram:1; + unsigned int hw_ecc_enabled:1; }; struct mx3_nf_controller { diff --git a/src/flash/nand/mxc.h b/src/flash/nand/mxc.h index ae2c03a..e9dc0a2 100644 --- a/src/flash/nand/mxc.h +++ b/src/flash/nand/mxc.h @@ -138,11 +138,11 @@ enum mxc_nf_finalize_action { }; struct mxc_nf_flags { - unsigned target_little_endian:1; - unsigned nand_readonly:1; - unsigned one_kb_sram:1; - unsigned hw_ecc_enabled:1; - unsigned biswap_enabled:1; + unsigned int target_little_endian:1; + unsigned int nand_readonly:1; + unsigned int one_kb_sram:1; + unsigned int hw_ecc_enabled:1; + unsigned int biswap_enabled:1; }; struct mxc_nf_controller { diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index afa11e7..147807f 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -26,6 +26,7 @@ NOR_DRIVERS = \ %D%/cc26xx.c \ %D%/cfi.c \ %D%/dsp5680xx_flash.c \ + %D%/dw-spi.c \ %D%/efm32.c \ %D%/em357.c \ %D%/eneispif.c \ @@ -44,6 +45,7 @@ NOR_DRIVERS = \ %D%/max32xxx.c \ %D%/mdr.c \ %D%/msp432.c \ + %D%/mspm0.c \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ @@ -89,6 +91,7 @@ NORHEADERS = \ %D%/cc26xx.h \ %D%/cfi.h \ %D%/driver.h \ + %D%/dw-spi-helper.h \ %D%/imp.h \ %D%/non_cfi.h \ %D%/ocl.h \ diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c index ce9bf24..aa573ac 100644 --- a/src/flash/nor/aducm360.c +++ b/src/flash/nor/aducm360.c @@ -79,7 +79,7 @@ static int aducm360_build_sector_list(struct flash_bank *bank) /* sector size is 512 */ bank->num_sectors = bank->size / FLASH_SECTOR_SIZE; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - for (unsigned i = 0; i < bank->num_sectors; ++i) { + for (unsigned int i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = offset; bank->sectors[i].size = FLASH_SECTOR_SIZE; offset += bank->sectors[i].size; diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index b1cb8f1..b86a18d 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -154,15 +154,15 @@ struct sam3_bank_private { struct sam3_chip *chip; /* so we can find the original bank pointer */ struct flash_bank *bank; - unsigned bank_number; + unsigned int bank_number; uint32_t controller_address; uint32_t base_address; uint32_t flash_wait_states; bool present; - unsigned size_bytes; - unsigned nsectors; - unsigned sector_size; - unsigned page_size; + unsigned int size_bytes; + unsigned int nsectors; + unsigned int sector_size; + unsigned int page_size; }; struct sam3_chip_details { @@ -176,12 +176,12 @@ struct sam3_chip_details { uint32_t chipid_cidr; const char *name; - unsigned n_gpnvms; + unsigned int n_gpnvms; #define SAM3_N_NVM_BITS 3 - unsigned gpnvm[SAM3_N_NVM_BITS]; - unsigned total_flash_size; - unsigned total_sram_size; - unsigned n_banks; + unsigned int gpnvm[SAM3_N_NVM_BITS]; + unsigned int total_flash_size; + unsigned int total_sram_size; + unsigned int n_banks; #define SAM3_MAX_FLASH_BANKS 2 /* these are "initialized" from the global const data */ struct sam3_bank_private bank[SAM3_MAX_FLASH_BANKS]; @@ -2029,7 +2029,7 @@ static int efc_get_result(struct sam3_bank_private *private, uint32_t *v) } static int efc_start_command(struct sam3_bank_private *private, - unsigned command, unsigned argument) + unsigned int command, unsigned int argument) { uint32_t n, v; int r; @@ -2051,7 +2051,7 @@ do_retry: case AT91C_EFC_FCMD_CLB: n = (private->size_bytes / private->page_size); if (argument >= n) - LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); + LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); break; case AT91C_EFC_FCMD_SFB: @@ -2124,8 +2124,8 @@ do_retry: * @param status - put command status bits here */ static int efc_perform_command(struct sam3_bank_private *private, - unsigned command, - unsigned argument, + unsigned int command, + unsigned int argument, uint32_t *status) { @@ -2220,7 +2220,7 @@ static int flashd_erase_entire_bank(struct sam3_bank_private *private) * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ -static int flashd_get_gpnvm(struct sam3_bank_private *private, unsigned gpnvm, unsigned *puthere) +static int flashd_get_gpnvm(struct sam3_bank_private *private, unsigned int gpnvm, unsigned int *puthere) { uint32_t v; int r; @@ -2261,10 +2261,10 @@ static int flashd_get_gpnvm(struct sam3_bank_private *private, unsigned gpnvm, u * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ -static int flashd_clr_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) +static int flashd_clr_gpnvm(struct sam3_bank_private *private, unsigned int gpnvm) { int r; - unsigned v; + unsigned int v; LOG_DEBUG("Here"); if (private->bank_number != 0) { @@ -2293,10 +2293,10 @@ static int flashd_clr_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) * @param private info about the bank * @param gpnvm GPNVM index. */ -static int flashd_set_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) +static int flashd_set_gpnvm(struct sam3_bank_private *private, unsigned int gpnvm) { int r; - unsigned v; + unsigned int v; if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); @@ -2346,8 +2346,8 @@ static int flashd_get_lock_bits(struct sam3_bank_private *private, uint32_t *v) */ static int flashd_unlock(struct sam3_bank_private *private, - unsigned start_sector, - unsigned end_sector) + unsigned int start_sector, + unsigned int end_sector) { int r; uint32_t status; @@ -2376,8 +2376,8 @@ static int flashd_unlock(struct sam3_bank_private *private, * @param end_sector - last sector (inclusive) to lock */ static int flashd_lock(struct sam3_bank_private *private, - unsigned start_sector, - unsigned end_sector) + unsigned int start_sector, + unsigned int end_sector) { uint32_t status; uint32_t pg; @@ -2405,8 +2405,8 @@ static int flashd_lock(struct sam3_bank_private *private, static uint32_t sam3_reg_fieldname(struct sam3_chip *chip, const char *regname, uint32_t value, - unsigned shift, - unsigned width) + unsigned int shift, + unsigned int width) { uint32_t v; int hwidth, dwidth; @@ -2491,7 +2491,7 @@ static const char *const sramsize[] = { }; -static const struct archnames { unsigned value; const char *name; } archnames[] = { +static const struct archnames { unsigned int value; const char *name; } archnames[] = { { 0x19, "AT91SAM9xx Series" }, { 0x29, "AT91SAM9XExx Series" }, { 0x34, "AT91x34 Series" }, @@ -2867,8 +2867,8 @@ static int sam3_read_this_reg(struct sam3_chip *chip, uint32_t *goes_here) r = target_read_u32(chip->target, reg->address, goes_here); if (r != ERROR_OK) { - LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d", - reg->name, (unsigned)(reg->address), r); + LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08" PRIx32 ", Err: %d", + reg->name, reg->address, r); } return r; } @@ -2883,8 +2883,8 @@ static int sam3_read_all_regs(struct sam3_chip *chip) r = sam3_read_this_reg(chip, sam3_get_reg_ptr(&(chip->cfg), reg)); if (r != ERROR_OK) { - LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Error: %d", - reg->name, ((unsigned)(reg->address)), r); + LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08" PRIx32 ", Error: %d", + reg->name, reg->address, r); return r; } reg++; @@ -2951,7 +2951,7 @@ static int sam3_protect_check(struct flash_bank *bank) { int r; uint32_t v = 0; - unsigned x; + unsigned int x; struct sam3_bank_private *private; LOG_DEBUG("Begin"); @@ -3071,7 +3071,7 @@ static int sam3_get_details(struct sam3_bank_private *private) const struct sam3_chip_details *details; struct sam3_chip *chip; struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS]; - unsigned x; + unsigned int x; LOG_DEBUG("Begin"); details = all_sam3_details; @@ -3264,7 +3264,7 @@ static int sam3_protect(struct flash_bank *bank, int set, unsigned int first, } -static int sam3_page_read(struct sam3_bank_private *private, unsigned pagenum, uint8_t *buf) +static int sam3_page_read(struct sam3_bank_private *private, unsigned int pagenum, uint8_t *buf) { uint32_t adr; int r; @@ -3283,7 +3283,7 @@ static int sam3_page_read(struct sam3_bank_private *private, unsigned pagenum, u return r; } -static int sam3_page_write(struct sam3_bank_private *private, unsigned pagenum, const uint8_t *buf) +static int sam3_page_write(struct sam3_bank_private *private, unsigned int pagenum, const uint8_t *buf) { uint32_t adr; uint32_t status; @@ -3347,10 +3347,10 @@ static int sam3_write(struct flash_bank *bank, uint32_t count) { int n; - unsigned page_cur; - unsigned page_end; + unsigned int page_cur; + unsigned int page_end; int r; - unsigned page_offset; + unsigned int page_offset; struct sam3_bank_private *private; uint8_t *pagebuffer; @@ -3497,7 +3497,7 @@ COMMAND_HANDLER(sam3_handle_info_command) if (!chip) return ERROR_OK; - unsigned x; + unsigned int x; int r; /* bank0 must exist before we can do anything */ @@ -3549,7 +3549,7 @@ need_define: COMMAND_HANDLER(sam3_handle_gpnvm_command) { - unsigned x, v; + unsigned int x, v; int r, who; struct sam3_chip *chip; diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 6212753..26a8037 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -134,15 +134,15 @@ struct sam4_bank_private { struct sam4_chip *chip; /* so we can find the original bank pointer */ struct flash_bank *bank; - unsigned bank_number; + unsigned int bank_number; uint32_t controller_address; uint32_t base_address; uint32_t flash_wait_states; bool present; - unsigned size_bytes; - unsigned nsectors; - unsigned sector_size; - unsigned page_size; + unsigned int size_bytes; + unsigned int nsectors; + unsigned int sector_size; + unsigned int page_size; }; struct sam4_chip_details { @@ -156,12 +156,12 @@ struct sam4_chip_details { uint32_t chipid_cidr; const char *name; - unsigned n_gpnvms; + unsigned int n_gpnvms; #define SAM4_N_NVM_BITS 3 - unsigned gpnvm[SAM4_N_NVM_BITS]; - unsigned total_flash_size; - unsigned total_sram_size; - unsigned n_banks; + unsigned int gpnvm[SAM4_N_NVM_BITS]; + unsigned int total_flash_size; + unsigned int total_sram_size; + unsigned int n_banks; #define SAM4_MAX_FLASH_BANKS 2 /* these are "initialized" from the global const data */ struct sam4_bank_private bank[SAM4_MAX_FLASH_BANKS]; @@ -1479,7 +1479,7 @@ static int efc_get_result(struct sam4_bank_private *private, uint32_t *v) } static int efc_start_command(struct sam4_bank_private *private, - unsigned command, unsigned argument) + unsigned int command, unsigned int argument) { uint32_t n, v; int r; @@ -1501,7 +1501,7 @@ do_retry: case AT91C_EFC_FCMD_CLB: n = (private->size_bytes / private->page_size); if (argument >= n) - LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); + LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); break; case AT91C_EFC_FCMD_SFB: @@ -1574,8 +1574,8 @@ do_retry: * @param status - put command status bits here */ static int efc_perform_command(struct sam4_bank_private *private, - unsigned command, - unsigned argument, + unsigned int command, + unsigned int argument, uint32_t *status) { @@ -1716,7 +1716,7 @@ static int flashd_erase_pages(struct sam4_bank_private *private, * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ -static int flashd_get_gpnvm(struct sam4_bank_private *private, unsigned gpnvm, unsigned *puthere) +static int flashd_get_gpnvm(struct sam4_bank_private *private, unsigned int gpnvm, unsigned int *puthere) { uint32_t v; int r; @@ -1757,10 +1757,10 @@ static int flashd_get_gpnvm(struct sam4_bank_private *private, unsigned gpnvm, u * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ -static int flashd_clr_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) +static int flashd_clr_gpnvm(struct sam4_bank_private *private, unsigned int gpnvm) { int r; - unsigned v; + unsigned int v; LOG_DEBUG("Here"); if (private->bank_number != 0) { @@ -1789,10 +1789,10 @@ static int flashd_clr_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) * @param private info about the bank * @param gpnvm GPNVM index. */ -static int flashd_set_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) +static int flashd_set_gpnvm(struct sam4_bank_private *private, unsigned int gpnvm) { int r; - unsigned v; + unsigned int v; if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); @@ -1846,8 +1846,8 @@ static int flashd_get_lock_bits(struct sam4_bank_private *private, uint32_t *v) */ static int flashd_unlock(struct sam4_bank_private *private, - unsigned start_sector, - unsigned end_sector) + unsigned int start_sector, + unsigned int end_sector) { int r; uint32_t status; @@ -1876,8 +1876,8 @@ static int flashd_unlock(struct sam4_bank_private *private, * @param end_sector - last sector (inclusive) to lock */ static int flashd_lock(struct sam4_bank_private *private, - unsigned start_sector, - unsigned end_sector) + unsigned int start_sector, + unsigned int end_sector) { uint32_t status; uint32_t pg; @@ -1905,8 +1905,8 @@ static int flashd_lock(struct sam4_bank_private *private, static uint32_t sam4_reg_fieldname(struct sam4_chip *chip, const char *regname, uint32_t value, - unsigned shift, - unsigned width) + unsigned int shift, + unsigned int width) { uint32_t v; int hwidth, dwidth; @@ -1991,7 +1991,7 @@ static const char *const sramsize[] = { }; -static const struct archnames { unsigned value; const char *name; } archnames[] = { +static const struct archnames { unsigned int value; const char *name; } archnames[] = { { 0x19, "AT91SAM9xx Series" }, { 0x29, "AT91SAM9XExx Series" }, { 0x34, "AT91x34 Series" }, @@ -2374,8 +2374,8 @@ static int sam4_read_this_reg(struct sam4_chip *chip, uint32_t *goes_here) r = target_read_u32(chip->target, reg->address, goes_here); if (r != ERROR_OK) { - LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Err: %d", - reg->name, (unsigned)(reg->address), r); + LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08" PRIx32 ", Err: %d", + reg->name, reg->address, r); } return r; } @@ -2390,8 +2390,8 @@ static int sam4_read_all_regs(struct sam4_chip *chip) r = sam4_read_this_reg(chip, sam4_get_reg_ptr(&(chip->cfg), reg)); if (r != ERROR_OK) { - LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Error: %d", - reg->name, ((unsigned)(reg->address)), r); + LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08" PRIx32 ", Error: %d", + reg->name, reg->address, r); return r; } reg++; @@ -2444,7 +2444,7 @@ static int sam4_protect_check(struct flash_bank *bank) { int r; uint32_t v[4] = {0}; - unsigned x; + unsigned int x; struct sam4_bank_private *private; LOG_DEBUG("Begin"); @@ -2557,7 +2557,7 @@ static int sam4_get_details(struct sam4_bank_private *private) const struct sam4_chip_details *details; struct sam4_chip *chip; struct flash_bank *saved_banks[SAM4_MAX_FLASH_BANKS]; - unsigned x; + unsigned int x; LOG_DEBUG("Begin"); details = all_sam4_details; @@ -2796,7 +2796,7 @@ static int sam4_protect(struct flash_bank *bank, int set, unsigned int first, } -static int sam4_page_read(struct sam4_bank_private *private, unsigned pagenum, uint8_t *buf) +static int sam4_page_read(struct sam4_bank_private *private, unsigned int pagenum, uint8_t *buf) { uint32_t adr; int r; @@ -2841,7 +2841,7 @@ static int sam4_set_wait(struct sam4_bank_private *private) return r; } -static int sam4_page_write(struct sam4_bank_private *private, unsigned pagenum, const uint8_t *buf) +static int sam4_page_write(struct sam4_bank_private *private, unsigned int pagenum, const uint8_t *buf) { uint32_t adr; uint32_t status; @@ -2891,10 +2891,10 @@ static int sam4_write(struct flash_bank *bank, uint32_t count) { int n; - unsigned page_cur; - unsigned page_end; + unsigned int page_cur; + unsigned int page_end; int r; - unsigned page_offset; + unsigned int page_offset; struct sam4_bank_private *private; uint8_t *pagebuffer; @@ -3045,7 +3045,7 @@ COMMAND_HANDLER(sam4_handle_info_command) if (!chip) return ERROR_OK; - unsigned x; + unsigned int x; int r; /* bank0 must exist before we can do anything */ @@ -3097,7 +3097,7 @@ need_define: COMMAND_HANDLER(sam4_handle_gpnvm_command) { - unsigned x, v; + unsigned int x, v; int r, who; struct sam4_chip *chip; diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 36298f1..0f7b0bb 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -365,7 +365,7 @@ static const struct samd_family *samd_find_family(uint32_t id) uint8_t family = SAMD_GET_FAMILY(id); uint8_t series = SAMD_GET_SERIES(id); - for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && samd_families[i].series == series && samd_families[i].family == family) @@ -387,7 +387,7 @@ static const struct samd_part *samd_find_part(uint32_t id) if (!family) return NULL; - for (unsigned i = 0; i < family->num_parts; i++) { + for (unsigned int i = 0; i < family->num_parts; i++) { if (family->parts[i].id == devsel) return &family->parts[i]; } diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c index 1d1ec02..7ce42b2 100644 --- a/src/flash/nor/ath79.c +++ b/src/flash/nor/ath79.c @@ -513,7 +513,7 @@ static int ath79_erase(struct flash_bank *bank, unsigned int first, if (ath79_info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; - for (unsigned sector = first; sector <= last; sector++) { + for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index c590081..f34958f 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -85,6 +85,9 @@ #define SAME_SERIES_51 0x01 #define SAME_SERIES_53 0x03 #define SAME_SERIES_54 0x04 +#define PIC32CXSG_SERIES_41 0x07 +#define PIC32CXSG_SERIES_60 0x00 +#define PIC32CXSG_SERIES_61 0x02 /* Device ID macros */ #define SAMD_GET_PROCESSOR(id) (id >> 28) @@ -148,6 +151,27 @@ static const struct samd_part same54_parts[] = { { 0x03, "SAME54N19A", 512, 192 }, }; +/* See PIC32CX SG41/SG60/SG61 Family Silicon Errata and Datasheet Clarifications + * DS80000985G */ +/* Known PIC32CX-SG41 parts. */ +static const struct samd_part pic32cxsg41_parts[] = { + { 0x00, "PIC32CX1025SG41128", 1024, 256 }, + { 0x01, "PIC32CX1025SG41100", 1024, 256 }, + { 0x02, "PIC32CX1025SG41064", 1024, 256 }, +}; + +/* Known PIC32CX-SG60 parts. */ +static const struct samd_part pic32cxsg60_parts[] = { + { 0x00, "PIC32CX1025SG60128", 1024, 256 }, + { 0x01, "PIC32CX1025SG60100", 1024, 256 }, +}; + +/* Known PIC32CX-SG61 parts. */ +static const struct samd_part pic32cxsg61_parts[] = { + { 0x00, "PIC32CX1025SG61128", 1024, 256 }, + { 0x01, "PIC32CX1025SG61100", 1024, 256 }, +}; + /* Each family of parts contains a parts table in the DEVSEL field of DID. The * processor ID, family ID, and series ID are used to determine which exact * family this is and then we can use the corresponding table. */ @@ -169,6 +193,12 @@ static const struct samd_family samd_families[] = { same53_parts, ARRAY_SIZE(same53_parts) }, { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54, same54_parts, ARRAY_SIZE(same54_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_41, + pic32cxsg41_parts, ARRAY_SIZE(pic32cxsg41_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_60, + pic32cxsg60_parts, ARRAY_SIZE(pic32cxsg60_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_61, + pic32cxsg61_parts, ARRAY_SIZE(pic32cxsg61_parts) }, }; struct samd_info { @@ -194,7 +224,7 @@ static const struct samd_family *samd_find_family(uint32_t id) uint8_t family = SAMD_GET_FAMILY(id); uint8_t series = SAMD_GET_SERIES(id); - for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && samd_families[i].series == series && samd_families[i].family == family) @@ -216,7 +246,7 @@ static const struct samd_part *samd_find_part(uint32_t id) if (!family) return NULL; - for (unsigned i = 0; i < family->num_parts; i++) { + for (unsigned int i = 0; i < family->num_parts; i++) { if (family->parts[i].id == devsel) return &family->parts[i]; } diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index 24c432c..d6d8938 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -55,8 +55,8 @@ struct samv_flash_bank { bool probed; - unsigned size_bytes; - unsigned gpnvm[SAMV_NUM_GPNVM_BITS]; + unsigned int size_bytes; + unsigned int gpnvm[SAMV_NUM_GPNVM_BITS]; }; /* The actual sector size of the SAMV7 flash memory is 128K bytes. @@ -82,7 +82,7 @@ static int samv_efc_get_result(struct target *target, uint32_t *v) } static int samv_efc_start_command(struct target *target, - unsigned command, unsigned argument) + unsigned int command, unsigned int argument) { uint32_t v; samv_efc_get_status(target, &v); @@ -100,7 +100,7 @@ static int samv_efc_start_command(struct target *target, } static int samv_efc_perform_command(struct target *target, - unsigned command, unsigned argument, uint32_t *status) + unsigned int command, unsigned int argument, uint32_t *status) { int r; uint32_t v; @@ -166,7 +166,7 @@ static int samv_erase_pages(struct target *target, first_page | erase_pages, status); } -static int samv_get_gpnvm(struct target *target, unsigned gpnvm, unsigned *out) +static int samv_get_gpnvm(struct target *target, unsigned int gpnvm, unsigned int *out) { uint32_t v; int r; @@ -190,10 +190,10 @@ static int samv_get_gpnvm(struct target *target, unsigned gpnvm, unsigned *out) return r; } -static int samv_clear_gpnvm(struct target *target, unsigned gpnvm) +static int samv_clear_gpnvm(struct target *target, unsigned int gpnvm) { int r; - unsigned v; + unsigned int v; if (gpnvm >= SAMV_NUM_GPNVM_BITS) { LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS); @@ -209,10 +209,10 @@ static int samv_clear_gpnvm(struct target *target, unsigned gpnvm) return r; } -static int samv_set_gpnvm(struct target *target, unsigned gpnvm) +static int samv_set_gpnvm(struct target *target, unsigned int gpnvm) { int r; - unsigned v; + unsigned int v; if (gpnvm >= SAMV_NUM_GPNVM_BITS) { LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS); return ERROR_FAIL; @@ -231,7 +231,7 @@ static int samv_set_gpnvm(struct target *target, unsigned gpnvm) } static int samv_flash_unlock(struct target *target, - unsigned start_sector, unsigned end_sector) + unsigned int start_sector, unsigned int end_sector) { int r; uint32_t status; @@ -251,7 +251,7 @@ static int samv_flash_unlock(struct target *target, } static int samv_flash_lock(struct target *target, - unsigned start_sector, unsigned end_sector) + unsigned int start_sector, unsigned int end_sector) { uint32_t status; uint32_t pg; @@ -419,7 +419,7 @@ static int samv_protect(struct flash_bank *bank, int set, unsigned int first, } static int samv_page_read(struct target *target, - unsigned page_num, uint8_t *buf) + unsigned int page_num, uint8_t *buf) { uint32_t addr = SAMV_FLASH_BASE + page_num * SAMV_PAGE_SIZE; int r = target_read_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); @@ -430,7 +430,7 @@ static int samv_page_read(struct target *target, } static int samv_page_write(struct target *target, - unsigned pagenum, const uint8_t *buf) + unsigned int pagenum, const uint8_t *buf) { uint32_t status; const uint32_t addr = SAMV_FLASH_BASE + pagenum * SAMV_PAGE_SIZE; @@ -618,7 +618,7 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) return ERROR_COMMAND_SYNTAX_ERROR; } - unsigned v = 0; + unsigned int v = 0; if (!strcmp("show", CMD_ARGV[0])) { if (who == -1) { showall: diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 78bc91e..2a15e49 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -806,7 +806,7 @@ int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char ** } bank->driver_priv = cfi_info; - for (unsigned i = 6; i < argc; i++) { + for (unsigned int i = 6; i < argc; i++) { if (strcmp(argv[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = true; else if (strcmp(argv[i], "data_swap") == 0) @@ -2219,8 +2219,7 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u uint8_t current_word[CFI_MAX_BUS_WIDTH]; int retval; - LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", - (int)count, (unsigned)offset); + 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"); diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index ec7f474..3a76d98 100644 --- a/src/flash/nor/cfi.h +++ b/src/flash/nor/cfi.h @@ -58,10 +58,10 @@ struct cfi_flash_bank { void *alt_ext; /* calculated timeouts */ - unsigned word_write_timeout; - unsigned buf_write_timeout; - unsigned block_erase_timeout; - unsigned chip_erase_timeout; + unsigned int word_write_timeout; + unsigned int buf_write_timeout; + unsigned int block_erase_timeout; + unsigned int chip_erase_timeout; /* memory accessors */ int (*write_mem)(struct flash_bank *bank, target_addr_t addr, diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 5e6c971..5c4f2ac 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -164,7 +164,7 @@ int default_flash_verify(struct flash_bank *bank, void flash_bank_add(struct flash_bank *bank) { /* put flash bank in linked list */ - unsigned bank_num = 0; + unsigned int bank_num = 0; if (flash_banks) { /* find last flash bank */ struct flash_bank *p = flash_banks; @@ -242,8 +242,8 @@ void flash_free_all_banks(void) struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) { - unsigned requested = get_flash_name_index(name); - unsigned found = 0; + unsigned int requested = get_flash_name_index(name); + unsigned int found = 0; struct flash_bank *bank; for (bank = flash_banks; bank; bank = bank->next) { diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index ff175a1..f8cf5e2 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -250,7 +250,7 @@ int get_flash_bank_by_num(unsigned int num, struct flash_bank **bank); * @param bank On output, contains a pointer to the bank or NULL. * @returns ERROR_OK on success, or an error indicating the problem. */ -COMMAND_HELPER(flash_command_get_bank, unsigned name_index, +COMMAND_HELPER(flash_command_get_bank, unsigned int name_index, struct flash_bank **bank); /** * Retrieves @a bank from a command argument, reporting errors parsing diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 211661e..794566f 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -254,6 +254,7 @@ extern const struct flash_driver cc26xx_flash; extern const struct flash_driver cc3220sf_flash; extern const struct flash_driver cfi_flash; extern const struct flash_driver dsp5680xx_flash; +extern const struct flash_driver dw_spi_flash; extern const struct flash_driver efm32_flash; extern const struct flash_driver em357_flash; extern const struct flash_driver eneispif_flash; @@ -273,6 +274,7 @@ extern const struct flash_driver max32xxx_flash; extern const struct flash_driver mdr_flash; extern const struct flash_driver mrvlqspi_flash; extern const struct flash_driver msp432_flash; +extern const struct flash_driver mspm0_flash; extern const struct flash_driver niietcm4_flash; extern const struct flash_driver npcx_flash; extern const struct flash_driver nrf51_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3435988..67d8624 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -31,6 +31,7 @@ static const struct flash_driver * const flash_drivers[] = { &cc26xx_flash, &cfi_flash, &dsp5680xx_flash, + &dw_spi_flash, &efm32_flash, &em357_flash, &eneispif_flash, @@ -50,6 +51,7 @@ static const struct flash_driver * const flash_drivers[] = { &mdr_flash, &mrvlqspi_flash, &msp432_flash, + &mspm0_flash, &niietcm4_flash, &npcx_flash, &nrf5_flash, @@ -91,7 +93,7 @@ static const struct flash_driver * const flash_drivers[] = { const struct flash_driver *flash_driver_find_by_name(const char *name) { - for (unsigned i = 0; flash_drivers[i]; i++) { + for (unsigned int i = 0; flash_drivers[i]; i++) { if (strcmp(name, flash_drivers[i]->name) == 0) return flash_drivers[i]; } diff --git a/src/flash/nor/dw-spi-helper.h b/src/flash/nor/dw-spi-helper.h new file mode 100644 index 0000000..d353755 --- /dev/null +++ b/src/flash/nor/dw-spi-helper.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/** + * @file + * Driver for SPI NOR flash chips connected via DesignWare SPI Core. + * + * In order to avoid using stack, all helper function arguments are packed + * into a single struct, passed by pointer. + * + * Pointers are represented by 64 bit integers to make structs compatible + * with 64 bit targets. + * + * This file contains helper function argument structures. + */ + +#ifndef OPENOCD_FLASH_NOR_DW_SPI_HELPER_H +#define OPENOCD_FLASH_NOR_DW_SPI_HELPER_H + +#include <stdint.h> + +/** + * @brief Arguments for transaction helper function. + */ +struct dw_spi_transaction { + uint64_t buffer; + ///< Pointer to data buffer to send over SPI. + ///< Return values are stored in place of output data when + ///< dw_spi_transaction::read_flag is 1. + uint32_t size; ///< Size of dw_spi_transaction::buffer. + uint64_t status_reg; ///< Pointer to SR register. + uint64_t data_reg; ///< Pointer to DR register. + uint8_t read_flag; + ///< When 1, store RX FIFO data to dw_spi_transaction::buffer. +} __attribute__((packed)); + +/** + * @brief Arguments for check_fill helper function. + */ +struct dw_spi_check_fill { + uint32_t address; ///< Starting address. Sector aligned. + uint32_t sector_size; ///< Sector size. + uint32_t sector_count; ///< Number of sectors to check. + uint64_t status_reg; ///< Pointer to SR register. + uint64_t data_reg; ///< Pointer to DR register. + uint64_t fill_status_array; + ///< Pointer to array describing sectors fill status. + ///< 1 if filled, 0 if not filled. + uint8_t pattern; ///< Fill pattern. + uint8_t read_cmd; ///< Read data command. + uint8_t four_byte_mode; ///< Four byte addressing mode flag. +} __attribute__((packed)); + +/** + * @brief Arguments for erase helper function. + */ +struct dw_spi_erase { + uint32_t address; ///< First sector address. Sector aligned. + uint32_t sector_size; ///< Sector size. + uint32_t sector_count; ///< Number of sectors to erase. + uint64_t status_reg; ///< Pointer to SR register. + uint64_t data_reg; ///< Pointer to DR register. + uint8_t read_status_cmd; ///< Read status command. + uint8_t write_enable_cmd; ///< Write enable command. + uint8_t erase_sector_cmd; ///< Erase sector command. + uint8_t write_enable_mask; ///< Write enable mask. + uint8_t busy_mask; ///< Busy mask. + uint8_t four_byte_mode; ///< Four byte addressing mode flag. +} __attribute__((packed)); + +/** + * @brief Arguments for program helper function. + */ +struct dw_spi_program { + uint32_t address; + ///< First page address. Page aligned when write is crossing + ///< the page boundary. + uint32_t page_size; ///< Page size. + uint64_t buffer; ///< Data buffer pointer. + uint32_t buffer_size; ///< Size of dw_spi_program::buffer. + uint64_t status_reg; ///< Pointer to SR register. + uint64_t data_reg; ///< Pointer to DR register. + uint8_t read_status_cmd; ///< Read status command. + uint8_t write_enable_cmd; ///< Write enable command. + uint8_t program_cmd; ///< Program command. + uint8_t write_enable_mask; ///< Write enable mask. + uint8_t busy_mask; ///< Busy mask. + uint8_t four_byte_mode; ///< Four byte addressing mode flag. +} __attribute__((packed)); + +/** + * @brief Arguments for read helper function. + */ +struct dw_spi_read { + uint32_t address; ///< First sector address. + uint64_t buffer; ///< Data buffer pointer. + uint32_t buffer_size; ///< Size of dw_spi_read::buffer. + uint64_t status_reg; ///< Pointer to SR register. + uint64_t data_reg; ///< Pointer to DR register. + uint8_t read_cmd; ///< Read data command. + uint8_t four_byte_mode; ///< Four byte addressing mode flag. +} __attribute__((packed)); + +#endif /* OPENOCD_FLASH_NOR_DW_SPI_HELPER_H */ diff --git a/src/flash/nor/dw-spi.c b/src/flash/nor/dw-spi.c new file mode 100644 index 0000000..e196547 --- /dev/null +++ b/src/flash/nor/dw-spi.c @@ -0,0 +1,1608 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Driver for SPI NOR flash chips connected via DesignWare SPI Core. + * Controller's Linux driver is located at drivers/spi/spi-dw-mmio.c. + * DW-SPI is used in a number of processors, including Microsemi Jaguar2 and + * Ocelot switch chips. + * + * Serial interface (SI) nCS0 pin, which is usually connected to the external + * flash, cannot be controlled via GPIO controller: it is asserted only when + * TX FIFO is not empty. Since JTAG is not fast enough to fill TX FIFO and + * collect data from RX FIFO at the same time even on the slowest SPI clock + * speeds, driver can only operate using functions, loaded in target's memory. + * Therefore, it requires the user to set up DRAM controller and provide + * work-area. + * + * In Microsemi devices, serial interface pins may be governed either + * by Boot or Master controller. For these devices, additional configuration of + * spi_mst address is required to switch between the two. + * + * Currently supported devices typically have much more RAM then NOR Flash + * (Jaguar2 reference design has 256MB RAM and 32MB NOR Flash), so supporting + * work-area sizes smaller then transfer buffer seems like the unnecessary + * complication. + * + * This code was tested on Jaguar2 VSC7448 connected to Macronix MX25L25635F. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dw-spi-helper.h" +#include "imp.h" +#include "spi.h" + +#include <helper/bits.h> +#include <helper/time_support.h> +#include <target/algorithm.h> +#include <target/breakpoints.h> +#include <target/mips32.h> +#include <target/target_type.h> + +/** + * @brief IP block placement map. + * + * Used for dynamic definition of the register map. + * + * IP block is used on different chips and placed in different locations. + * This structure defines some implementation specific variables. + */ +struct dw_spi_regmap { + uint32_t freq; ///< Clock frequency. + target_addr_t simc; ///< Absolute offset of SIMC register block. + target_addr_t spi_mst; + ///< Absolute offset of ICPU_CFG:SPI_MST register. 0 if not available. + uint8_t si_if_owner_offset; + ///< Offset of \ref si_mode bits in ICPU_CFG:SPI_MST. +}; + +/** + * @brief Register map for Jaguar2 switch devices. + */ +static const struct dw_spi_regmap jaguar2_regmap = { + .freq = 250000000UL, + .simc = 0x70101000UL, + .spi_mst = 0x70000024UL, + .si_if_owner_offset = 6, +}; + +/** + * @brief Register map for Ocelot switch devices. + */ +static const struct dw_spi_regmap ocelot_regmap = { + .freq = 250000000UL, + .simc = 0x70101000UL, + .spi_mst = 0x70000024UL, + .si_if_owner_offset = 4, +}; + +#define DW_SPI_IF_OWNER_WIDTH 2 ///< IF owner register field width. + +/** + * @brief Owner of the SI interface. + */ +enum dw_spi_si_mode { + DW_SPI_SI_MODE_BOOT = 1, + ///< Boot controller maps contents of SPI Flash to memory in read-only mode. + DW_SPI_SI_MODE_MASTER = 2, + ///< SPI controller mode for reading/writing SPI Flash. +}; + +#define DW_SPI_REG_CTRLR0 0x00 ///< General configuration register. +#define DW_SPI_REG_SIMCEN 0x08 ///< Master controller enable register. +#define DW_SPI_REG_SER 0x10 ///< Slave select register. +#define DW_SPI_REG_BAUDR 0x14 ///< Baud rate configuration register. +#define DW_SPI_REG_SR 0x28 ///< Status register. +#define DW_SPI_REG_IMR 0x2c ///< Interrupt configuration register. +#define DW_SPI_REG_DR 0x60 ///< Data register. + +#define DW_SPI_REG_CTRLR0_DFS(x) ((x) & GENMASK(3, 0)) ///< Data frame size. +#define DW_SPI_REG_CTRLR0_FRF(x) (((x) << 4) & GENMASK(5, 4)) ///< SI protocol. +#define DW_SPI_REG_CTRLR0_SCPH(x) ((!!(x)) << 6) ///< Probe position. +#define DW_SPI_REG_CTRLR0_SCPOL(x) ((!!(x)) << 7) ///< Probe polarity. +#define DW_SPI_REG_CTRLR0_TMOD(x) (((x) << 8) & GENMASK(9, 8)) ///< SI mode. +#define DW_SPI_REG_SIMCEN_SIMCEN(x) (!!(x)) ///< Controller enable. +#define DW_SPI_REG_SER_SER(x) ((x) & GENMASK(15, 0)) ///< Slave select bitmask. +#define DW_SPI_REG_BAUDR_SCKDV(x) ((x) & GENMASK(15, 0)) ///< Clock divisor. + +/** + * @brief Driver private state. + */ +struct dw_spi_driver { + bool probed; ///< Bank is probed. + uint32_t id; ///< Chip ID. + unsigned int speed; ///< Flash speed. + unsigned int timeout; ///< Flash timeout in milliseconds. + uint8_t chip_select_bitmask; ///< Chip select bitmask. + bool four_byte_mode; ///< Flash chip is in 32bit address mode. + enum dw_spi_si_mode saved_ctrl_mode; + ///< Previously selected controller mode. + struct dw_spi_regmap regmap; ///< SI controller regmap. + const struct flash_device *spi_flash; ///< SPI flash device info. +}; + +/** + * @brief Register used to pass argument struct to helper functions. + */ +#define DW_SPI_ARG_REG "r4" + +/** + * @brief Default timeout value in ms for flash transaction jobs. + */ +#define DW_SPI_TIMEOUT_DEFAULT (600 * 1000) + +/** + * @brief Timeout value in ms for short flash transactions, + * e.g. reading flash ID and status register. + */ +#define DW_SPI_TIMEOUT_TRANSACTION 1000 + +/** + * @brief Select SI interface owner. + * + * Mode selection is skipped if Boot controller not available on target + * (i.e. spi_mst command argument is not configured). + * + * @param[in] bank: Flash bank. + * @param[in] mode: New controller mode. + * @return Command execution status. + */ +static int +dw_spi_ctrl_mode(const struct flash_bank *const bank, enum dw_spi_si_mode mode) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + if (!regmap->spi_mst) + return ERROR_OK; + + uint32_t ctrl; + int ret = target_read_u32(target, regmap->spi_mst, &ctrl); + if (ret) { + LOG_ERROR("DW SPI SPI:MST register read error"); + return ret; + } + ctrl &= ~GENMASK(DW_SPI_IF_OWNER_WIDTH + driver->regmap.si_if_owner_offset, + driver->regmap.si_if_owner_offset); + ctrl |= mode << driver->regmap.si_if_owner_offset; + + ret = target_write_u32(target, regmap->spi_mst, ctrl); + if (ret) + LOG_ERROR("DW SPI controller mode configuration error"); + + return ret; +} + +/** + * @brief Select master controller as SI interface owner. + * + * Previous interface owner is restored via dw_spi_ctrl_mode_restore() function. + * Mode selection is skipped if Boot controller not available on target + * (i.e. spi_mst command argument is not configured). + * + * @param[in] bank: Flash bank. + * @param[in] mode: New controller mode. + * @return Command execution status. + */ +static int +dw_spi_ctrl_mode_configure(const struct flash_bank *const bank, + enum dw_spi_si_mode mode) +{ + struct target *const target = bank->target; + struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + if (!regmap->spi_mst) + return ERROR_OK; + + uint32_t ctrl; + int ret = target_read_u32(target, regmap->spi_mst, &ctrl); + if (ret) { + LOG_ERROR("DW SPI controller mode query error"); + return ret; + } + driver->saved_ctrl_mode = + (enum dw_spi_si_mode)((ctrl >> driver->regmap.si_if_owner_offset) & + GENMASK(DW_SPI_IF_OWNER_WIDTH, 0)); + + return dw_spi_ctrl_mode(bank, mode); +} + +/** + * @brief Restore SI controller mode. + * + * Restore initially configured SI controller mode. Undo configuration done by + * dw_spi_ctrl_mode_configure() function. + * Mode selection is skipped if Boot controller not available on target + * (i.e. spi_mst command argument is not configured). + * + * @param[in] bank: Flash bank. + * @return Command execution status. + */ +static int +dw_spi_ctrl_mode_restore(const struct flash_bank *const bank) +{ + const struct dw_spi_driver *const driver = bank->driver_priv; + + return dw_spi_ctrl_mode(bank, driver->saved_ctrl_mode); +} + +/** + * @brief Enable master controller. + * + * Configuration of the master controller must be done when it is disabled. + * + * @param[in] bank: Flash bank. + * @param[in] value: New enable state. + * @return Command execution status. + */ +static int +dw_spi_master_ctrl_enable(const struct flash_bank *const bank, bool value) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + int ret = target_write_u32(target, regmap->simc + DW_SPI_REG_SIMCEN, + DW_SPI_REG_SIMCEN_SIMCEN(value)); + if (ret) + LOG_ERROR("DW SPI master controller enable flag configuration error"); + + return ret; +} + +/** + * @brief Configure SI transfer mode. + * + * @param[in] bank: Flash bank. + * @return Command execution status. + */ +static int +dw_spi_ctrl_configure_si(const struct flash_bank *const bank) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + // 8 bit frame; Motorola protocol; middle lo probe; TX RX mode + const uint32_t mode = DW_SPI_REG_CTRLR0_DFS(0x7) | + DW_SPI_REG_CTRLR0_FRF(0) | + DW_SPI_REG_CTRLR0_SCPH(0) | + DW_SPI_REG_CTRLR0_SCPOL(0) | + DW_SPI_REG_CTRLR0_TMOD(0); + + int ret = target_write_u32(target, regmap->simc + DW_SPI_REG_CTRLR0, mode); + if (ret) { + LOG_ERROR("DW SPI master controller configuration query error"); + return ret; + } + + ret = target_write_u32(target, regmap->simc + DW_SPI_REG_SER, + DW_SPI_REG_SER_SER(driver->chip_select_bitmask)); + if (ret) + LOG_ERROR("DW SPI slave select configuration error"); + + return ret; +} + +/** + * @brief Configure SI transfer speed. + * + * @param[in] bank: Flash bank. + * @return Command execution status. + */ +static int +dw_spi_ctrl_configure_speed(const struct flash_bank *const bank) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + // divisor LSB must be zero + const uint16_t div = MIN((regmap->freq / driver->speed), 0xfffe) & 0xfffe; + + int ret = target_write_u32(target, regmap->simc + DW_SPI_REG_BAUDR, + DW_SPI_REG_BAUDR_SCKDV(div)); + if (ret) { + LOG_ERROR("DW SPI speed configuration error"); + return ret; + } + + unsigned int speed = regmap->freq / div; + LOG_DEBUG("DW SPI setting NOR controller speed to %u kHz", speed / 1000); + + return ret; +} + +/** + * @brief Disable SI master controller interrupts. + * + * @param[in] bank: Flash bank. + * @return Command execution status. + */ +static int +dw_spi_ctrl_disable_interrupts(const struct flash_bank *const bank) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + int ret = target_write_u32(target, regmap->simc + DW_SPI_REG_IMR, 0); + if (ret) + LOG_ERROR("DW SPI disable interrupts error"); + + return ret; +} + +/** + * @brief Do data transaction. + * + * Buffer data are sent and replaced with received data. Total buffer size + * is a sum of TX and RX messages. RX portion of the buffer is initially + * filled with dummy values, which get replaced by the message. + * + * @param[in] bank: Flash bank. + * @param[in,out] buffer: Data buffer. If \p read flag is set, buffer is + * filled with received data. + * @param[in] size: \p buffer size. + * @param[in] read: The read flag. If set to true, read values will override + * \p buffer. + * @return Command execution status. + */ +static int +dw_spi_ctrl_transaction(const struct flash_bank *const bank, + uint8_t *const buffer, size_t size, bool read) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + static const uint8_t target_code[] = { +#include "../../../contrib/loaders/flash/dw-spi/mipsel-linux-gnu-transaction.inc" + }; + const size_t target_code_size = sizeof(target_code); + const size_t total_working_area_size = + target_code_size + sizeof(struct dw_spi_transaction) + size; + + // allocate working area, memory args and data buffer + struct working_area *helper; + int ret = target_alloc_working_area(target, target_code_size, &helper); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper; + } + + struct working_area *helper_args; + ret = target_alloc_working_area(target, sizeof(struct dw_spi_transaction), + &helper_args); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper_args; + } + + struct working_area *target_buffer; + ret = target_alloc_working_area(target, size, &target_buffer); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_target_buffer; + } + + // write algorithm code and buffer to working areas + ret = target_write_buffer(target, helper->address, target_code_size, + target_code); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + ret = target_write_buffer(target, target_buffer->address, size, buffer); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + // prepare helper execution + struct mips32_algorithm mips32_algo = { .common_magic = MIPS32_COMMON_MAGIC, + .isa_mode = MIPS32_ISA_MIPS32 }; + + struct reg_param reg_param; + init_reg_param(®_param, DW_SPI_ARG_REG, 32, PARAM_OUT); + struct mem_param mem_param; + init_mem_param(&mem_param, helper_args->address, helper_args->size, + PARAM_OUT); + + // Set the arguments for the helper + buf_set_u32(reg_param.value, 0, 32, helper_args->address); + + struct dw_spi_transaction *helper_args_val = + (struct dw_spi_transaction *)mem_param.value; + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->buffer, + target_buffer->address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->size, size); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->status_reg, + regmap->simc + DW_SPI_REG_SR); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->data_reg, + regmap->simc + DW_SPI_REG_DR); + helper_args_val->read_flag = read; + + ret = target_run_algorithm(target, 1, &mem_param, 1, ®_param, + helper->address, 0, DW_SPI_TIMEOUT_TRANSACTION, + &mips32_algo); + + if (ret) { + LOG_ERROR("DW SPI flash algorithm error"); + goto cleanup; + } + + if (read) { + ret = target_read_buffer(target, target_buffer->address, size, buffer); + if (ret) + LOG_ERROR("DW SPI target buffer read error"); + } + +cleanup: + destroy_reg_param(®_param); + destroy_mem_param(&mem_param); + +err_write_buffer: + target_free_working_area(target, target_buffer); +err_target_buffer: + target_free_working_area(target, helper_args); +err_helper_args: + target_free_working_area(target, helper); +err_helper: + + return ret; +} + +/** + * @brief Check that selected region is filled with pattern. + * + * This function is used for Flash erase checking. + * + * @param[in] bank: Flash bank. + * @param[in] address: Starting address. Sector aligned. + * @param[in] sector_size: Size of sector. + * @param[in] sector_count: Number of sectors. + * @param[in] pattern: Fill pattern. + * @param[in] read_cmd: Flash read command. + * @param[out] buffer: Filled flag array. Must hold \p sector_count number + * of entries. + * @return Command execution status. + */ +static int +dw_spi_ctrl_check_sectors_fill(const struct flash_bank *const bank, + uint32_t address, size_t sector_size, + size_t sector_count, uint8_t pattern, + uint8_t read_cmd, uint8_t *buffer) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + static const uint8_t target_code[] = { +#include "../../../contrib/loaders/flash/dw-spi/mipsel-linux-gnu-check_fill.inc" + }; + const size_t target_code_size = sizeof(target_code); + const size_t total_working_area_size = + target_code_size + sizeof(struct dw_spi_check_fill) + sector_count; + + // allocate working area, memory args and data buffer + struct working_area *helper; + int ret = target_alloc_working_area(target, target_code_size, &helper); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper; + } + + struct working_area *helper_args; + ret = target_alloc_working_area(target, sizeof(struct dw_spi_check_fill), + &helper_args); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper_args; + } + + struct working_area *target_buffer; + ret = target_alloc_working_area(target, sector_count, &target_buffer); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_target_buffer; + } + + // write algorithm code and buffer to working areas + ret = target_write_buffer(target, helper->address, target_code_size, + target_code); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + // prepare helper execution + struct mips32_algorithm mips32_algo = { .common_magic = MIPS32_COMMON_MAGIC, + .isa_mode = MIPS32_ISA_MIPS32 }; + + struct reg_param reg_param; + init_reg_param(®_param, DW_SPI_ARG_REG, 32, PARAM_OUT); + struct mem_param mem_param; + init_mem_param(&mem_param, helper_args->address, helper_args->size, + PARAM_OUT); + + // Set the arguments for the helper + buf_set_u32(reg_param.value, 0, 32, helper_args->address); + + struct dw_spi_check_fill *helper_args_val = + (struct dw_spi_check_fill *)mem_param.value; + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->address, + address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->sector_size, + sector_size); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->sector_count, + sector_count); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->status_reg, + regmap->simc + DW_SPI_REG_SR); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->data_reg, + regmap->simc + DW_SPI_REG_DR); + target_buffer_set_u32(target, + (uint8_t *)&helper_args_val->fill_status_array, + target_buffer->address); + helper_args_val->pattern = pattern; + helper_args_val->read_cmd = read_cmd; + helper_args_val->four_byte_mode = driver->four_byte_mode; + + ret = target_run_algorithm(target, 1, &mem_param, 1, ®_param, + helper->address, 0, driver->timeout, + &mips32_algo); + + if (ret) { + LOG_ERROR("DW SPI flash algorithm error"); + goto cleanup; + } + + ret = target_read_buffer(target, target_buffer->address, sector_count, + buffer); + if (ret) + LOG_ERROR("DW SPI target buffer read error"); + +cleanup: + destroy_reg_param(®_param); + destroy_mem_param(&mem_param); + +err_write_buffer: + target_free_working_area(target, target_buffer); +err_target_buffer: + target_free_working_area(target, helper_args); +err_helper_args: + target_free_working_area(target, helper); +err_helper: + + return ret; +} + +/** + * @brief Write flash region. + * + * @param[in] bank: Flash bank. + * @param[in] address: First page address. Page aligned when write is crossing + * the page boundary. + * @param[in] buffer: Data buffer. + * @param[in] buffer_size: \p buffer size. + * @param[in] page_size: Size of flash page. + * @param[in] stat_cmd: Flash command to read chip status. + * @param[in] we_cmd: Flash command to enable write. + * @param[in] program_cmd: Flash command to program chip. + * @param[in] we_mask: Status byte write enable mask. + * @param[in] busy_mask: Status byte write busy mask. + * @return Command execution status. + */ +static int +dw_spi_ctrl_program(const struct flash_bank *const bank, uint32_t address, + const uint8_t *const buffer, size_t buffer_size, + uint32_t page_size, uint8_t stat_cmd, uint8_t we_cmd, + uint8_t program_cmd, uint8_t we_mask, uint8_t busy_mask) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + static const uint8_t target_code[] = { +#include "../../../contrib/loaders/flash/dw-spi/mipsel-linux-gnu-program.inc" + }; + const size_t target_code_size = sizeof(target_code); + const size_t total_working_area_size = + target_code_size + sizeof(struct dw_spi_program) + buffer_size; + + // allocate working area, memory args and data buffer + struct working_area *helper; + int ret = target_alloc_working_area(target, target_code_size, &helper); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper; + } + + struct working_area *helper_args; + ret = target_alloc_working_area(target, sizeof(struct dw_spi_program), + &helper_args); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper_args; + } + + struct working_area *target_buffer; + ret = target_alloc_working_area(target, buffer_size, &target_buffer); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_target_buffer; + } + + // write algorithm code and buffer to working areas + ret = target_write_buffer(target, helper->address, target_code_size, + target_code); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + ret = target_write_buffer(target, target_buffer->address, buffer_size, + buffer); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + // prepare helper execution + struct mips32_algorithm mips32_algo = { .common_magic = MIPS32_COMMON_MAGIC, + .isa_mode = MIPS32_ISA_MIPS32 }; + + struct reg_param reg_param; + init_reg_param(®_param, DW_SPI_ARG_REG, 32, PARAM_OUT); + struct mem_param mem_param; + init_mem_param(&mem_param, helper_args->address, helper_args->size, + PARAM_OUT); + + // Set the arguments for the helper + buf_set_u32(reg_param.value, 0, 32, helper_args->address); + struct dw_spi_program *helper_args_val = + (struct dw_spi_program *)mem_param.value; + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->address, + address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->page_size, + page_size); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->buffer, + target_buffer->address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->buffer_size, + buffer_size); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->status_reg, + regmap->simc + DW_SPI_REG_SR); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->data_reg, + regmap->simc + DW_SPI_REG_DR); + helper_args_val->read_status_cmd = stat_cmd; + helper_args_val->write_enable_cmd = we_cmd; + helper_args_val->program_cmd = program_cmd; + helper_args_val->write_enable_mask = we_mask; + helper_args_val->busy_mask = busy_mask; + helper_args_val->four_byte_mode = driver->four_byte_mode; + + ret = target_run_algorithm(target, 1, &mem_param, 1, ®_param, + helper->address, 0, driver->timeout, + &mips32_algo); + if (ret) + LOG_ERROR("DW SPI flash algorithm error"); + + destroy_reg_param(®_param); + destroy_mem_param(&mem_param); + +err_write_buffer: + target_free_working_area(target, target_buffer); +err_target_buffer: + target_free_working_area(target, helper_args); +err_helper_args: + target_free_working_area(target, helper); +err_helper: + + return ret; +} + +/** + * @brief Erase sectors. + * + * @param[in] bank: Flash bank. + * @param[in] address: Flash address. Must be sector aligned. + * @param[in] sector_size: Size of flash sector. + * @param[in] sector_count: Number of sectors to erase. + * @param[in] stat_cmd: Flash command to read chip status. + * @param[in] we_cmd: Flash command to set enable write. + * @param[in] erase_sector_cmd: Flash command to set erase sector. + * @param[in] we_mask: Status byte write enable mask. + * @param[in] busy_mask: Status byte write busy mask. + * @return Command execution status. + */ +static int +dw_spi_ctrl_erase_sectors(const struct flash_bank *const bank, uint32_t address, + uint32_t sector_size, size_t sector_count, + uint8_t stat_cmd, uint8_t we_cmd, + uint8_t erase_sector_cmd, uint8_t we_mask, + uint8_t busy_mask) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + static const uint8_t target_code[] = { +#include "../../../contrib/loaders/flash/dw-spi/mipsel-linux-gnu-erase.inc" + }; + const size_t target_code_size = sizeof(target_code); + const size_t total_working_area_size = + target_code_size + sizeof(struct dw_spi_erase); + + // allocate working area and memory args + struct working_area *helper; + int ret = target_alloc_working_area(target, target_code_size, &helper); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper; + } + + struct working_area *helper_args; + ret = target_alloc_working_area(target, sizeof(struct dw_spi_erase), + &helper_args); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper_args; + } + + // write algorithm code to working area + ret = target_write_buffer(target, helper->address, target_code_size, + target_code); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + // prepare helper execution + struct mips32_algorithm mips32_algo = { .common_magic = MIPS32_COMMON_MAGIC, + .isa_mode = MIPS32_ISA_MIPS32 }; + + struct reg_param reg_param; + init_reg_param(®_param, DW_SPI_ARG_REG, 32, PARAM_OUT); + struct mem_param mem_param; + init_mem_param(&mem_param, helper_args->address, helper_args->size, + PARAM_OUT); + + // Set the arguments for the helper + buf_set_u32(reg_param.value, 0, 32, helper_args->address); + struct dw_spi_erase *helper_args_val = + (struct dw_spi_erase *)mem_param.value; + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->address, + address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->sector_size, + sector_size); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->sector_count, + sector_count); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->status_reg, + regmap->simc + DW_SPI_REG_SR); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->data_reg, + regmap->simc + DW_SPI_REG_DR); + helper_args_val->read_status_cmd = stat_cmd; + helper_args_val->write_enable_cmd = we_cmd; + helper_args_val->erase_sector_cmd = erase_sector_cmd; + helper_args_val->write_enable_mask = we_mask; + helper_args_val->busy_mask = busy_mask; + helper_args_val->four_byte_mode = driver->four_byte_mode; + + ret = target_run_algorithm(target, 1, &mem_param, 1, ®_param, + helper->address, 0, driver->timeout, + &mips32_algo); + if (ret) + LOG_ERROR("DW SPI flash algorithm error"); + + destroy_reg_param(®_param); + destroy_mem_param(&mem_param); + +err_write_buffer: + target_free_working_area(target, helper_args); +err_helper_args: + target_free_working_area(target, helper); +err_helper: + + return ret; +} + +/** + * @brief Read flash data. + * + * @param[in] bank: Flash bank. + * @param[in] address: Flash address. + * @param[out] buffer: Data buffer. + * @param[in] buffer_size: \p buffer size. + * @param[in] read_cmd: Flash command to read data from flash. + * @return Command execution status. + */ +static int +dw_spi_ctrl_read(const struct flash_bank *const bank, uint32_t address, + uint8_t *buffer, size_t buffer_size, uint8_t read_cmd) +{ + struct target *const target = bank->target; + const struct dw_spi_driver *const driver = bank->driver_priv; + const struct dw_spi_regmap *const regmap = &driver->regmap; + + static const uint8_t target_code[] = { +#include "../../../contrib/loaders/flash/dw-spi/mipsel-linux-gnu-read.inc" + }; + const size_t target_code_size = sizeof(target_code); + const size_t total_working_area_size = + target_code_size + sizeof(struct dw_spi_read) + buffer_size; + + // allocate working area and memory args + struct working_area *helper; + int ret = target_alloc_working_area(target, target_code_size, &helper); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper; + } + + struct working_area *helper_args; + ret = target_alloc_working_area(target, sizeof(struct dw_spi_read), + &helper_args); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_helper_args; + } + + struct working_area *target_buffer; + ret = target_alloc_working_area(target, buffer_size, &target_buffer); + if (ret) { + LOG_ERROR("DW SPI could not allocate working area. Need %zx", + total_working_area_size); + goto err_target_buffer; + } + + // write algorithm code to working area + ret = target_write_buffer(target, helper->address, target_code_size, + target_code); + if (ret) { + LOG_ERROR("DW SPI writing to working area error"); + goto err_write_buffer; + } + + // prepare helper execution + struct mips32_algorithm mips32_algo = { .common_magic = MIPS32_COMMON_MAGIC, + .isa_mode = MIPS32_ISA_MIPS32 }; + + struct reg_param reg_param; + init_reg_param(®_param, DW_SPI_ARG_REG, 32, PARAM_OUT); + struct mem_param mem_param; + init_mem_param(&mem_param, helper_args->address, helper_args->size, + PARAM_OUT); + + // Set the arguments for the helper + buf_set_u32(reg_param.value, 0, 32, helper_args->address); + struct dw_spi_read *helper_args_val = (struct dw_spi_read *)mem_param.value; + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->address, + address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->buffer, + target_buffer->address); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->buffer_size, + buffer_size); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->status_reg, + regmap->simc + DW_SPI_REG_SR); + target_buffer_set_u32(target, (uint8_t *)&helper_args_val->data_reg, + regmap->simc + DW_SPI_REG_DR); + helper_args_val->read_cmd = read_cmd; + helper_args_val->four_byte_mode = driver->four_byte_mode; + + ret = target_run_algorithm(target, 1, &mem_param, 1, ®_param, + helper->address, 0, driver->timeout, + &mips32_algo); + if (ret) { + LOG_ERROR("DW SPI flash algorithm error"); + goto cleanup; + } + + ret = + target_read_buffer(target, target_buffer->address, buffer_size, buffer); + if (ret) + LOG_ERROR("DW SPI target buffer read error"); + +cleanup: + destroy_reg_param(®_param); + destroy_mem_param(&mem_param); + +err_write_buffer: + target_free_working_area(target, target_buffer); +err_target_buffer: + target_free_working_area(target, helper_args); +err_helper_args: + target_free_working_area(target, helper); +err_helper: + + return ret; +} + +/** + * @brief Read Flash device ID. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_read_id(const struct flash_bank *const bank) +{ + struct dw_spi_driver *const driver = bank->driver_priv; + + const size_t buffer_size = 1 + 3 + 1; + uint8_t buffer[buffer_size]; + + memset(buffer, 0, buffer_size); + buffer[0] = SPIFLASH_READ_ID; + + int ret = dw_spi_ctrl_transaction(bank, buffer, buffer_size, true); + if (ret) { + LOG_ERROR("DW SPI flash ID read error"); + return ret; + } + + buffer[buffer_size - 1] = 0; + // use le_to_h_u32 to decode flash ID as per JEDEC SFDP + driver->id = le_to_h_u32(buffer + 1); + LOG_DEBUG("DW SPI read flash ID %" PRIx32, driver->id); + + return ERROR_OK; +} + +/** + * @brief Read Flash device status. + * + * @param[in] bank: Flash bank handle. + * @param[out] status: The status byte. + * @return Command execution status. + */ +static int +dw_spi_read_status(const struct flash_bank *const bank, uint8_t *const status) +{ + const int buffer_size = 2; + uint8_t buffer[buffer_size]; + + memset(buffer, 0, buffer_size); + buffer[0] = SPIFLASH_READ_STATUS; + + int ret = dw_spi_ctrl_transaction(bank, buffer, buffer_size, true); + if (ret) { + LOG_ERROR("DW SPI flash status read error"); + return ret; + } + + *status = buffer[1]; + + return ERROR_OK; +} + +/** + * @brief Wait for Flash command to finish. + * + * @param[in] bank: Flash bank handle. + * @param[in] timeout: The timeout in ms. + * @return Command execution status. + */ +static int +dw_spi_wait_finish(const struct flash_bank *const bank, unsigned int timeout) +{ + const int64_t end_time = timeval_ms() + timeout; + while (timeval_ms() <= end_time) { + uint8_t status; + int ret = dw_spi_read_status(bank, &status); + if (ret) { + LOG_ERROR("DW SPI status query error"); + return ret; + } + if (!(status & SPIFLASH_BSY_BIT)) + return ERROR_OK; + + alive_sleep(1); + } + + LOG_ERROR("DW SPI process timeout"); + return ERROR_TIMEOUT_REACHED; +} + +/** + * @brief Flash device write enable. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_write_enable(const struct flash_bank *const bank) +{ + const int buffer_size = 1; + uint8_t buffer[buffer_size]; + + memset(buffer, 0, buffer_size); + buffer[0] = SPIFLASH_WRITE_ENABLE; + + int ret = dw_spi_ctrl_transaction(bank, buffer, buffer_size, false); + if (ret) { + LOG_ERROR("DW SPI flash write enable error"); + return ret; + } + + uint8_t status; + ret = dw_spi_read_status(bank, &status); + if (ret) + return ret; + + return status & SPIFLASH_WE_BIT ? ERROR_OK : ERROR_FAIL; +} + +/** + * @brief Erase Flash chip. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_erase_chip(const struct flash_bank *const bank) +{ + const struct dw_spi_driver *const driver = bank->driver_priv; + + const int buffer_size = 1; + uint8_t buffer[buffer_size]; + + int ret = dw_spi_write_enable(bank); + if (ret) + return ret; + + memset(buffer, 0, buffer_size); + buffer[0] = driver->spi_flash->chip_erase_cmd; + + ret = dw_spi_ctrl_transaction(bank, buffer, buffer_size, false); + if (ret) { + LOG_ERROR("DW SPI erase flash error"); + return ret; + } + + ret = dw_spi_wait_finish(bank, driver->timeout); + if (ret) { + LOG_ERROR("DW SPI erase flash timeout"); + return ret; + } + + return ERROR_OK; +} + +/** + * @brief Flash device erase sectors. + * + * @param[in] bank: Flash bank handle. + * @param[in] first: The first sector to erase. + * @param[in] last: The last sector to erase. + * @return Command execution status. + */ +static int +dw_spi_erase_sectors(const struct flash_bank *const bank, unsigned int first, + unsigned int last) +{ + const struct dw_spi_driver *const driver = bank->driver_priv; + + if (first == 0 && last >= (bank->num_sectors - 1)) { + // full erase + int ret = dw_spi_erase_chip(bank); + if (ret) + return ret; + } else { + // partial erase + int ret = dw_spi_ctrl_erase_sectors(bank, bank->sectors[first].offset, + driver->spi_flash->sectorsize, + last - first + 1, + SPIFLASH_READ_STATUS, + SPIFLASH_WRITE_ENABLE, + driver->spi_flash->erase_cmd, + SPIFLASH_WE_BIT, SPIFLASH_BSY_BIT); + if (ret) { + LOG_ERROR("DW SPI flash erase sectors error"); + return ret; + } + } + + return ERROR_OK; +} + +/** + * @brief Flash bank blank check. + */ +static int +dw_spi_blank_check(struct flash_bank *bank, size_t sector_count, + uint8_t pattern) +{ + const struct dw_spi_driver *const driver = bank->driver_priv; + + uint8_t *erased = malloc(sector_count); + if (!erased) { + LOG_ERROR("could not allocate memory"); + return ERROR_FAIL; + } + + // set initial erased value to unknown + memset(erased, 2, sector_count); + for (unsigned int sector_idx = 0; sector_idx < sector_count; sector_idx++) + bank->sectors[sector_idx].is_erased = 2; + + int ret = dw_spi_ctrl_check_sectors_fill(bank, 0, bank->sectors[0].size, + sector_count, pattern, + driver->spi_flash->read_cmd, + erased); + if (!ret) { + for (unsigned int sector_idx = 0; sector_idx < sector_count; + sector_idx++) + bank->sectors[sector_idx].is_erased = erased[sector_idx]; + } else { + LOG_ERROR("DW SPI flash erase check error"); + } + + free(erased); + + return ret; +} + +/** + * @brief Write buffer to Flash. + * + * @param[in] bank: Flash bank handle. + * @param[in] buffer: Data buffer. + * @param[in] offset: Flash address offset. + * @param[in] count: \p buffer size. + * @return Command execution status. + */ +static int +dw_spi_write_buffer(const struct flash_bank *const bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + const struct dw_spi_driver *const driver = bank->driver_priv; + const size_t page_size = driver->spi_flash->pagesize; + + // Write unaligned first sector separately as helper function does + // not handle this case well. + struct { + uint32_t address; + const uint8_t *buffer; + size_t count; + } chunks[2] = { + { .address = offset, .buffer = buffer, .count = 0 }, + { .address = offset, .buffer = buffer, .count = count }, + }; + + if (offset % page_size) { + // start is not aligned + chunks[0].count = MIN(page_size - (offset % page_size), count); + chunks[1].count -= chunks[0].count; + chunks[1].address += chunks[0].count; + chunks[1].buffer += chunks[0].count; + } + + for (unsigned int chunk_idx = 0; chunk_idx < ARRAY_SIZE(chunks); + chunk_idx++) { + if (chunks[chunk_idx].count > 0) { + int ret = dw_spi_ctrl_program(bank, chunks[chunk_idx].address, + chunks[chunk_idx].buffer, + chunks[chunk_idx].count, page_size, + SPIFLASH_READ_STATUS, + SPIFLASH_WRITE_ENABLE, + driver->spi_flash->pprog_cmd, + SPIFLASH_WE_BIT, SPIFLASH_BSY_BIT); + if (ret) { + LOG_ERROR("DW SPI flash write error"); + return ret; + } + } + } + + return ERROR_OK; +} + +/** + * @brief Search for Flash chip info. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_spiflash_search(const struct flash_bank *const bank) +{ + struct dw_spi_driver *const driver = bank->driver_priv; + + int ret = dw_spi_read_id(bank); + if (ret) + return ret; + + unsigned int idx = 0; + while (flash_devices[idx].name) { + if (flash_devices[idx].device_id == driver->id) { + driver->spi_flash = &flash_devices[idx]; + return ERROR_OK; + } + idx++; + } + + LOG_ERROR("DW SPI could not find Flash with ID %" PRIx32 + " in SPI Flash table: either Flash device is not supported " + "or communication speed is too high", + driver->id); + return ERROR_FAIL; +} + +/** + * @brief Handle flash bank command. + * + * @param[in] CMD_ARGC: Number of arguments. + * @param[in] CMD_ARGV: Command arguments. + * @return Command execution status. + */ +FLASH_BANK_COMMAND_HANDLER(dw_spi_flash_bank_command) +{ + unsigned int speed = 1000000; + unsigned int timeout = DW_SPI_TIMEOUT_DEFAULT; + uint8_t chip_select_bitmask = BIT(0); + struct dw_spi_regmap regmap = { 0 }; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int idx = 6; idx < CMD_ARGC; idx++) { + if (strcmp(CMD_ARGV[idx], "-jaguar2") == 0) { + // Fast config for Jaguar2 chips. + memcpy(®map, &jaguar2_regmap, sizeof(jaguar2_regmap)); + } else if (strcmp(CMD_ARGV[idx], "-ocelot") == 0) { + // Fast config for Ocelot chips. + memcpy(®map, &ocelot_regmap, sizeof(ocelot_regmap)); + } else if (strcmp(CMD_ARGV[idx], "-freq") == 0) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[++idx], regmap.freq); + } else if (strcmp(CMD_ARGV[idx], "-simc") == 0) { + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[++idx], regmap.simc); + } else if (strcmp(CMD_ARGV[idx], "-spi_mst") == 0) { + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[++idx], regmap.spi_mst); + } else if (strcmp(CMD_ARGV[idx], "-if_owner_offset") == 0) { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[++idx], + regmap.si_if_owner_offset); + } else if (strcmp(CMD_ARGV[idx], "-speed") == 0) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[++idx], speed); + } else if (strcmp(CMD_ARGV[idx], "-timeout") == 0) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[++idx], timeout); + timeout *= 1000; // convert to ms + } else if (strcmp(CMD_ARGV[idx], "-chip_select") == 0) { + unsigned int cs_bit; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[++idx], cs_bit); + chip_select_bitmask = BIT(cs_bit); + } else { + LOG_WARNING("DW SPI unknown argument %s", CMD_ARGV[idx]); + } + } + + if (!regmap.simc) { + LOG_ERROR("DW SPI cannot use boot controller with unconfigured simc"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bank->driver_priv = malloc(sizeof(struct dw_spi_driver)); + if (!bank->driver_priv) { + LOG_ERROR("could not allocate memory"); + return ERROR_FAIL; + } + + struct dw_spi_driver *driver = bank->driver_priv; + memset(driver, 0, sizeof(struct dw_spi_driver)); + driver->speed = speed; + driver->timeout = timeout; + driver->chip_select_bitmask = chip_select_bitmask; + driver->four_byte_mode = true; // 24bit commands not provided by spi.h + memcpy(&driver->regmap, ®map, sizeof(regmap)); + + return ERROR_OK; +} + +/** + * @brief Assert target is halted. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_assert_halted(const struct flash_bank *const bank) +{ + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + return ERROR_OK; +} + +/** + * @brief Prepare master controller for transaction. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_master_ctrl_configure(struct flash_bank *bank) +{ + int ret = dw_spi_assert_halted(bank); + if (ret) + return ret; + ret = dw_spi_ctrl_mode_configure(bank, DW_SPI_SI_MODE_MASTER); + if (ret) { + LOG_ERROR("DW SPI switch to master controller mode error"); + return ret; + } + ret = dw_spi_master_ctrl_enable(bank, false); + if (ret) { + LOG_ERROR("DW SPI disable master controller error"); + return ret; + } + ret = dw_spi_ctrl_configure_speed(bank); + if (ret) { + LOG_ERROR("DW SPI speed configuration error"); + return ret; + } + ret = dw_spi_ctrl_disable_interrupts(bank); + if (ret) { + LOG_ERROR("DW SPI disable SPI interrupts error"); + return ret; + } + ret = dw_spi_ctrl_configure_si(bank); + if (ret) { + LOG_ERROR("DW SPI controller configuration error"); + return ret; + } + ret = dw_spi_master_ctrl_enable(bank, true); + if (ret) { + LOG_ERROR("DW SPI enable master controller error"); + return ret; + } + + return ERROR_OK; +} + +/** + * @brief Restore SI controller selection. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_master_ctrl_restore(struct flash_bank *bank) +{ + int ret = dw_spi_master_ctrl_enable(bank, false); + if (ret) { + LOG_ERROR("DW SPI disable master controller error"); + return ret; + } + ret = dw_spi_ctrl_mode_restore(bank); + if (ret) { + LOG_ERROR("DW SPI controller restore error"); + return ret; + } + + return ret; +} + +/** + * @brief Flash bank probe. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_probe(struct flash_bank *bank) +{ + struct dw_spi_driver *const driver = bank->driver_priv; + + if (!driver) + return ERROR_FAIL; + + if (strcmp(bank->target->type->name, mips_m4k_target.name) != 0 || + bank->target->endianness != TARGET_LITTLE_ENDIAN) { + LOG_ERROR("DW SPI currently only supports " + "little endian mips_m4k target"); + return ERROR_TARGET_INVALID; + } + + int ret = dw_spi_master_ctrl_configure(bank); + if (ret) + return ret; + + ret = dw_spi_spiflash_search(bank); + if (ret) + goto err; + + bank->write_start_alignment = 0; + bank->write_end_alignment = 0; + + uint32_t flash_size = driver->spi_flash->size_in_bytes; + if (!bank->size) { + bank->size = flash_size; + LOG_INFO("DW SPI probed flash size 0x%" PRIx32, flash_size); + } else { + if (flash_size > bank->size) + LOG_WARNING("DW SPI probed flash size 0x%" PRIx32 + " is greater then declared 0x%" PRIx32, + flash_size, bank->size); + if (flash_size < bank->size) { + LOG_ERROR("DW SPI probed flash size 0x%" PRIx32 + " is smaller then declared 0x%" PRIx32, + flash_size, bank->size); + ret = ERROR_FLASH_BANK_INVALID; + goto err; + } + } + bank->num_sectors = bank->size / driver->spi_flash->sectorsize; + + // free previously allocated in case of reprobing + free(bank->sectors); + + bank->sectors = + alloc_block_array(0, driver->spi_flash->sectorsize, bank->num_sectors); + + if (!bank->sectors) { + LOG_ERROR("could not allocate memory"); + ret = ERROR_FAIL; + goto err; + } + + driver->probed = true; + +err: + dw_spi_master_ctrl_restore(bank); + return ret; +} + +/** + * @brief Flash bank erase sectors. + * + * @param[in] bank: Flash bank handle. + * @param[in] first: The first sector to erase. + * @param[in] last: The last sector to erase. + * @return Command execution status. + */ +static int +dw_spi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + int ret = dw_spi_master_ctrl_configure(bank); + if (ret) + return ret; + + ret = dw_spi_erase_sectors(bank, first, last); + dw_spi_master_ctrl_restore(bank); + return ret; +} + +/** + * @brief Flash bank write data. + * + * @param[in] bank: Flash bank handle. + * @param[in] buffer: Data buffer. + * @param[in] offset: Flash address offset. + * @param[in] count: \p buffer size. + * @return Command execution status. + */ +static int +dw_spi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, + uint32_t count) +{ + int ret = dw_spi_master_ctrl_configure(bank); + if (ret) + return ret; + + ret = dw_spi_write_buffer(bank, buffer, offset, count); + dw_spi_master_ctrl_restore(bank); + return ret; +} + +/** + * @brief Flash bank read data using master controller. + * + * @param[in] bank: Flash bank handle. + * @param[out] buffer: Data buffer. + * @param[in] offset: Flash address offset. + * @param[in] count: \p buffer size. + * @return Command execution status. + */ +static int +dw_spi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, + uint32_t count) +{ + struct dw_spi_driver *const driver = bank->driver_priv; + + int ret = dw_spi_master_ctrl_configure(bank); + if (ret) + return ret; + + ret = dw_spi_ctrl_read(bank, offset, buffer, count, + driver->spi_flash->read_cmd); + dw_spi_master_ctrl_restore(bank); + return ret; +} + +/** + * @brief Flash bank erase check. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_erase_check(struct flash_bank *bank) +{ + int ret = dw_spi_master_ctrl_configure(bank); + if (ret) + return ret; + + ret = dw_spi_blank_check(bank, bank->num_sectors, bank->erased_value); + + dw_spi_master_ctrl_restore(bank); + return ret; +} + +/** + * @brief Flash bank info. + * + * @param[in] bank: Flash bank handle. + * @param[in,out] cmd Command invocation. + * @return Command execution status. + */ +static int +dw_spi_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + const struct dw_spi_driver *const driver = bank->driver_priv; + command_print(cmd, "model %s", driver->spi_flash->name); + command_print(cmd, "ID 0x%" PRIx32, driver->id); + command_print_sameline(cmd, "size 0x%" PRIx32, bank->size); + return ERROR_OK; +} + +/** + * @brief Autoprobe driver. + * + * @param[in] bank: Flash bank handle. + * @return Command execution status. + */ +static int +dw_spi_auto_probe(struct flash_bank *bank) +{ + struct dw_spi_driver *driver = bank->driver_priv; + if (!driver) + return ERROR_FAIL; + if (!driver->probed) + return dw_spi_probe(bank); + return ERROR_OK; +} + +/** + * @brief DW-SPI NOR flash functions. + */ +const struct flash_driver dw_spi_flash = { + .name = "dw-spi", + .flash_bank_command = dw_spi_flash_bank_command, + .erase = dw_spi_erase, + .write = dw_spi_write, + .read = dw_spi_read, + .probe = dw_spi_probe, + .auto_probe = dw_spi_auto_probe, + .erase_check = dw_spi_erase_check, + .info = dw_spi_info, + .verify = default_flash_verify, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 043494c..207346f 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -709,7 +709,7 @@ static int em357_probe(struct flash_bank *bank) em357_info->ppage_size = 4; - LOG_INFO("flash size = %d KiB", num_pages*page_size/1024); + LOG_INFO("flash size = %d KiB", num_pages * page_size / 1024); free(bank->sectors); diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 9191764..395722c 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -531,7 +531,7 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, bin_size = sizeof(riscv64_bin); } - unsigned data_wa_size = 0; + unsigned int data_wa_size = 0; if (target_alloc_working_area(target, bin_size, &algorithm_wa) == ERROR_OK) { retval = target_write_buffer(target, algorithm_wa->address, bin_size, bin); @@ -751,9 +751,9 @@ static int fespi_probe(struct flash_bank *bank) target_device->name, bank->base); } else { - LOG_DEBUG("Assuming FESPI as specified at address " TARGET_ADDR_FMT - " with ctrl at " TARGET_ADDR_FMT, fespi_info->ctrl_base, - bank->base); + LOG_DEBUG("Assuming FESPI as specified at address " TARGET_ADDR_FMT + " with ctrl at " TARGET_ADDR_FMT, fespi_info->ctrl_base, + bank->base); } /* read and decode flash ID; returns in SW mode */ diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index 979ae84..2db79ef 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -107,7 +107,7 @@ static int fm4_flash_erase(struct flash_bank *bank, unsigned int first, struct working_area *workarea; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_algo; - unsigned i; + unsigned int i; int retval; const uint8_t erase_sector_code[] = { #include "../../../contrib/loaders/flash/fm4/erase.inc" @@ -207,7 +207,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, struct armv7m_algorithm armv7m_algo; uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2); uint32_t result; - unsigned i; + unsigned int i; int retval, retval2 = ERROR_OK; const uint8_t write_block_code[] = { #include "../../../contrib/loaders/flash/fm4/write.inc" diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index fee3644..85c306b 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -256,7 +256,7 @@ struct kinetis_flash_bank { struct kinetis_chip *k_chip; bool probed; - unsigned bank_number; /* bank number in particular chip */ + unsigned int bank_number; /* bank number in particular chip */ struct flash_bank *bank; uint32_t sector_size; @@ -285,9 +285,9 @@ struct kinetis_chip { uint32_t fcfg2_maxaddr0_shifted; uint32_t fcfg2_maxaddr1_shifted; - unsigned num_pflash_blocks, num_nvm_blocks; - unsigned pflash_sector_size, nvm_sector_size; - unsigned max_flash_prog_size; + unsigned int num_pflash_blocks, num_nvm_blocks; + unsigned int pflash_sector_size, nvm_sector_size; + unsigned int max_flash_prog_size; uint32_t pflash_base; uint32_t pflash_size; @@ -337,7 +337,7 @@ struct kinetis_chip { char name[40]; - unsigned num_banks; + unsigned int num_banks; struct kinetis_flash_bank banks[KINETIS_MAX_BANKS]; }; @@ -425,7 +425,7 @@ static int kinetis_probe_chip_s32k(struct kinetis_chip *k_chip); static int kinetis_auto_probe(struct flash_bank *bank); -static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) +static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned int reg, uint32_t value) { LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); @@ -453,7 +453,7 @@ static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint3 return ERROR_OK; } -static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) +static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned int reg, uint32_t *result) { struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); if (!ap) { @@ -479,7 +479,7 @@ static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32 return ERROR_OK; } -static int kinetis_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, +static int kinetis_mdm_poll_register(struct adiv5_dap *dap, unsigned int reg, uint32_t mask, uint32_t value, uint32_t timeout_ms) { uint32_t val; @@ -977,7 +977,7 @@ static void kinetis_free_driver_priv(struct flash_bank *bank) static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) { - unsigned num_blocks; + unsigned int num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; char base_name[69], name[87], num[11]; @@ -1038,6 +1038,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) bank->target = k_chip->target; bank->driver = &kinetis_flash; bank->default_padded_value = bank->erased_value = 0xff; + bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR; snprintf(name, sizeof(name), "%s.%s%s", base_name, class, num); @@ -1462,7 +1463,7 @@ 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; - unsigned num_blocks; + unsigned int num_blocks; uint32_t pflash_bit; uint8_t dflash_bit; struct flash_bank *bank_iter; @@ -1488,7 +1489,22 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) kinetis_auto_probe(bank_iter); - assert(bank_iter->prot_blocks); + if (bank_iter->num_prot_blocks == 0) { + if (k_bank->flash_class == FC_PFLASH) { + LOG_ERROR("BUG: PFLASH bank %u has no protection blocks", + bank_idx); + } else { + LOG_DEBUG("skipping FLEX_NVM bank %u with no prot blocks (EE bkp only)", + bank_idx); + } + continue; + } + + if (!bank_iter->prot_blocks) { + LOG_ERROR("BUG: bank %u has NULL protection blocks array", + bank_idx); + continue; + } if (k_bank->flash_class == FC_PFLASH) { for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) { @@ -2268,12 +2284,12 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) uint32_t ee_size = 0; uint32_t pflash_size_k, nvm_size_k, dflash_size_k; uint32_t pflash_size_m; - unsigned num_blocks = 0; - unsigned maxaddr_shift = 13; + unsigned int num_blocks = 0; + unsigned int maxaddr_shift = 13; struct target *target = k_chip->target; - unsigned familyid = 0, subfamid = 0; - unsigned cpu_mhz = 120; + unsigned int familyid = 0, subfamid = 0; + unsigned int cpu_mhz = 120; bool use_nvm_marking = false; char flash_marking[12], nvm_marking[2]; char name[40]; @@ -2894,7 +2910,7 @@ static int kinetis_probe(struct flash_bank *bank) { int result; uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; - unsigned num_blocks, first_nvm_bank; + unsigned int num_blocks, first_nvm_bank; uint32_t size_k; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip; @@ -2939,7 +2955,7 @@ static int kinetis_probe(struct flash_bank *bank) } else if (k_bank->bank_number < num_blocks) { /* nvm, banks start at address 0x10000000 */ - unsigned nvm_ord = k_bank->bank_number - first_nvm_bank; + unsigned int nvm_ord = k_bank->bank_number - first_nvm_bank; uint32_t limit; k_bank->flash_class = FC_FLEX_NVM; @@ -3138,8 +3154,8 @@ static int kinetis_blank_check(struct flash_bank *bank) COMMAND_HANDLER(kinetis_nvm_partition) { int result; - unsigned bank_idx; - unsigned num_blocks, first_nvm_bank; + unsigned int bank_idx; + unsigned int num_blocks, first_nvm_bank; unsigned long par, log2 = 0, ee1 = 0, ee2 = 0; enum { SHOW_INFO, DF_SIZE, EEBKP_SIZE } sz_type = SHOW_INFO; bool enable; diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index c069f3a..8207504 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -134,7 +134,7 @@ struct kinetis_ke_flash_bank { #define MDM_ACCESS_TIMEOUT 3000 /* iterations */ -static int kinetis_ke_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) +static int kinetis_ke_mdm_write_register(struct adiv5_dap *dap, unsigned int reg, uint32_t value) { LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); @@ -161,7 +161,7 @@ static int kinetis_ke_mdm_write_register(struct adiv5_dap *dap, unsigned reg, ui return ERROR_OK; } -static int kinetis_ke_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) +static int kinetis_ke_mdm_read_register(struct adiv5_dap *dap, unsigned int reg, uint32_t *result) { struct adiv5_ap *ap = dap_get_ap(dap, 1); if (!ap) { @@ -187,7 +187,7 @@ static int kinetis_ke_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uin return ERROR_OK; } -static int kinetis_ke_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value) +static int kinetis_ke_mdm_poll_register(struct adiv5_dap *dap, unsigned int reg, uint32_t mask, uint32_t value) { uint32_t val; int retval; @@ -1005,7 +1005,7 @@ static int kinetis_ke_write(struct flash_bank *bank, const uint8_t *buffer, result = kinetis_ke_stop_watchdog(bank->target); if (result != ERROR_OK) - return result; + return result; result = kinetis_ke_prepare_flash(bank); if (result != ERROR_OK) diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index f12eef7..09d35f6 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -272,7 +272,7 @@ #define LPC11XX_REG_SECTORS 24 -typedef enum { +enum lpc2000_variant { LPC2000_V1, LPC2000_V2, LPC1700, @@ -282,10 +282,10 @@ typedef enum { LPC1500, LPC54100, LPC_AUTO, -} lpc2000_variant; +}; struct lpc2000_flash_bank { - lpc2000_variant variant; + enum lpc2000_variant variant; uint32_t cclk; int cmd51_dst_boundary; int calc_checksum; diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c index 59a14af..267fd43 100644 --- a/src/flash/nor/max32xxx.c +++ b/src/flash/nor/max32xxx.c @@ -202,14 +202,14 @@ static int max32xxx_protect_check(struct flash_bank *bank) return ERROR_FLASH_BANK_NOT_PROBED; if (!info->max326xx) { - for (unsigned i = 0; i < bank->num_sectors; i++) + for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = -1; return ERROR_FLASH_OPER_UNSUPPORTED; } /* Check the protection */ - for (unsigned i = 0; i < bank->num_sectors; i++) { + for (unsigned int i = 0; i < bank->num_sectors; i++) { if (i%32 == 0) target_read_u32(target, info->flc_base + FLSH_PROT + ((i/32)*4), &temp_reg); @@ -360,7 +360,7 @@ static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* power of two, and multiple of word size */ - static const unsigned buf_min = 128; + static const unsigned int buf_min = 128; /* for small buffers it's faster not to download an algorithm */ if (wcount * 4 < buf_min) @@ -388,8 +388,8 @@ static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", - target_name(target), (unsigned) buffer_size); + LOG_DEBUG("retry target_alloc_working_area(%s, size=%" PRIu32 ")", + target_name(target), buffer_size); } target_write_buffer(target, write_algorithm->address, sizeof(write_code), @@ -903,7 +903,7 @@ COMMAND_HANDLER(max32xxx_handle_protection_check_command) } LOG_WARNING("s:<sector number> a:<address> p:<protection bit>"); - for (unsigned i = 0; i < bank->num_sectors; i += 4) { + for (unsigned int i = 0; i < bank->num_sectors; i += 4) { LOG_WARNING("s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d", (i+0), (i+0)*info->sector_size, bank->sectors[(i+0)].is_protected, (i+1), (i+1)*info->sector_size, bank->sectors[(i+1)].is_protected, diff --git a/src/flash/nor/mspm0.c b/src/flash/nor/mspm0.c new file mode 100644 index 0000000..4731c89 --- /dev/null +++ b/src/flash/nor/mspm0.c @@ -0,0 +1,1131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2023-2025 Texas Instruments Incorporated - https://www.ti.com/ + * + * NOR flash driver for MSPM0L and MSPM0G class of uC from Texas Instruments. + * + * See: + * https://www.ti.com/microcontrollers-mcus-processors/arm-based-microcontrollers/arm-cortex-m0-mcus/overview.html + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/bits.h> +#include <helper/time_support.h> + +/* MSPM0 Region memory map */ +#define MSPM0_FLASH_BASE_NONMAIN 0x41C00000 +#define MSPM0_FLASH_END_NONMAIN 0x41C00400 +#define MSPM0_FLASH_BASE_MAIN 0x0 +#define MSPM0_FLASH_BASE_DATA 0x41D00000 + +/* MSPM0 FACTORYREGION registers */ +#define MSPM0_FACTORYREGION 0x41C40000 +#define MSPM0_TRACEID (MSPM0_FACTORYREGION + 0x000) +#define MSPM0_DID (MSPM0_FACTORYREGION + 0x004) +#define MSPM0_USERID (MSPM0_FACTORYREGION + 0x008) +#define MSPM0_SRAMFLASH (MSPM0_FACTORYREGION + 0x018) + +/* MSPM0 FCTL registers */ +#define FLASH_CONTROL_BASE 0x400CD000 +#define FCTL_REG_DESC (FLASH_CONTROL_BASE + 0x10FC) +#define FCTL_REG_CMDEXEC (FLASH_CONTROL_BASE + 0x1100) +#define FCTL_REG_CMDTYPE (FLASH_CONTROL_BASE + 0x1104) +#define FCTL_REG_CMDADDR (FLASH_CONTROL_BASE + 0x1120) +#define FCTL_REG_CMDBYTEN (FLASH_CONTROL_BASE + 0x1124) +#define FCTL_REG_CMDDATA0 (FLASH_CONTROL_BASE + 0x1130) +#define FCTL_REG_CMDWEPROTA (FLASH_CONTROL_BASE + 0x11D0) +#define FCTL_REG_CMDWEPROTB (FLASH_CONTROL_BASE + 0x11D4) +#define FCTL_REG_CMDWEPROTNM (FLASH_CONTROL_BASE + 0x1210) +#define FCTL_REG_STATCMD (FLASH_CONTROL_BASE + 0x13D0) + +/* FCTL_STATCMD[CMDDONE] Bits */ +#define FCTL_STATCMD_CMDDONE_MASK 0x00000001 +#define FCTL_STATCMD_CMDDONE_STATDONE 0x00000001 + +/* FCTL_STATCMD[CMDPASS] Bits */ +#define FCTL_STATCMD_CMDPASS_MASK 0x00000002 +#define FCTL_STATCMD_CMDPASS_STATPASS 0x00000002 + +/* + * FCTL_CMDEXEC Bits + * FCTL_CMDEXEC[VAL] Bits + */ +#define FCTL_CMDEXEC_VAL_EXECUTE 0x00000001 + +/* FCTL_CMDTYPE[COMMAND] Bits */ +#define FCTL_CMDTYPE_COMMAND_PROGRAM 0x00000001 +#define FCTL_CMDTYPE_COMMAND_ERASE 0x00000002 + +/* FCTL_CMDTYPE[SIZE] Bits */ +#define FCTL_CMDTYPE_SIZE_ONEWORD 0x00000000 +#define FCTL_CMDTYPE_SIZE_SECTOR 0x00000040 + +/* FCTL_FEATURE_VER_B minimum */ +#define FCTL_FEATURE_VER_B 0xA + +#define MSPM0_MAX_PROTREGS 3 + +#define MSPM0_FLASH_TIMEOUT_MS 8000 +#define ERR_STRING_MAX 255 + +/* SYSCTL BASE */ +#define SYSCTL_BASE 0x400AF000 +#define SYSCTL_SECCFG_SECSTATUS (SYSCTL_BASE + 0x00003048) + +/* TI manufacturer ID */ +#define TI_MANUFACTURER_ID 0x17 + +/* Defines for probe status */ +#define MSPM0_NO_ID_FOUND 0 +#define MSPM0_DEV_ID_FOUND 1 +#define MSPM0_DEV_PART_ID_FOUND 2 + +struct mspm0_flash_bank { + /* chip id register */ + uint32_t did; + /* Device Unique ID register */ + uint32_t traceid; + unsigned char version; + + const char *name; + + /* Decoded flash information */ + unsigned int data_flash_size_kb; + unsigned int main_flash_size_kb; + unsigned int main_flash_num_banks; + unsigned int sector_size; + /* Decoded SRAM information */ + unsigned int sram_size_kb; + + /* Flash word size: 64 bit = 8, 128bit = 16 bytes */ + unsigned char flash_word_size_bytes; + + /* Protection register stuff */ + unsigned int protect_reg_base; + unsigned int protect_reg_count; + + /* Flashctl version: A - CMDWEPROTA/B, B- CMDWEPROTB */ + unsigned char flash_version; +}; + +struct mspm0_part_info { + const char *part_name; + unsigned short part; + unsigned char variant; +}; + +struct mspm0_family_info { + const char *family_name; + unsigned short part_num; + unsigned char part_count; + const struct mspm0_part_info *part_info; +}; + +/* https://www.ti.com/lit/ds/symlink/mspm0l1346.pdf Table 8-13 and so on */ +static const struct mspm0_part_info mspm0l_parts[] = { + { "MSPM0L1105TDGS20R", 0x51DB, 0x16 }, + { "MSPM0L1105TDGS28R", 0x51DB, 0x83 }, + { "MSPM0L1105TDYYR", 0x51DB, 0x54 }, + { "MSPM0L1105TRGER", 0x51DB, 0x86 }, + { "MSPM0L1105TRHBR", 0x51DB, 0x68 }, + { "MSPM0L1106TDGS20R", 0x5552, 0x4B }, + { "MSPM0L1106TDGS28R", 0x5552, 0x98 }, + { "MSPM0L1106TDYYR", 0x5552, 0x9D }, + { "MSPM0L1106TRGER", 0x5552, 0x90 }, + { "MSPM0L1106TRHBR", 0x5552, 0x53 }, + { "MSPM0L1303SRGER", 0xef0, 0x17 }, + { "MSPM0L1303TRGER", 0xef0, 0xe2 }, + { "MSPM0L1304QDGS20R", 0xd717, 0x91 }, + { "MSPM0L1304QDGS28R", 0xd717, 0xb6 }, + { "MSPM0L1304QDYYR", 0xd717, 0xa0 }, + { "MSPM0L1304QRHBR", 0xd717, 0xa9 }, + { "MSPM0L1304SDGS20R", 0xd717, 0xfa }, + { "MSPM0L1304SDGS28R", 0xd717, 0x73 }, + { "MSPM0L1304SDYYR", 0xd717, 0xb7 }, + { "MSPM0L1304SRGER", 0xd717, 0x26 }, + { "MSPM0L1304SRHBR", 0xd717, 0xe4 }, + { "MSPM0L1304TDGS20R", 0xd717, 0x33 }, + { "MSPM0L1304TDGS28R", 0xd717, 0xa8 }, + { "MSPM0L1304TDYYR", 0xd717, 0xf9 }, + { "MSPM0L1304TRGER", 0xd717, 0xb7 }, + { "MSPM0L1304TRHBR", 0xd717, 0x5a }, + { "MSPM0L1305QDGS20R", 0x4d03, 0xb7 }, + { "MSPM0L1305QDGS28R", 0x4d03, 0x74 }, + { "MSPM0L1305QDYYR", 0x4d03, 0xec }, + { "MSPM0L1305QRHBR", 0x4d03, 0x78 }, + { "MSPM0L1305SDGS20R", 0x4d03, 0xc7 }, + { "MSPM0L1305SDGS28R", 0x4d03, 0x64 }, + { "MSPM0L1305SDYYR", 0x4d03, 0x91 }, + { "MSPM0L1305SRGER", 0x4d03, 0x73 }, + { "MSPM0L1305SRHBR", 0x4d03, 0x2d }, + { "MSPM0L1305TDGS20R", 0x4d03, 0xa0 }, + { "MSPM0L1305TDGS28R", 0x4d03, 0xfb }, + { "MSPM0L1305TDYYR", 0x4d03, 0xde }, + { "MSPM0L1305TRGER", 0x4d03, 0xea }, + { "MSPM0L1305TRHBR", 0x4d03, 0x85 }, + { "MSPM0L1306QDGS20R", 0xbb70, 0x59 }, + { "MSPM0L1306QDGS28R", 0xbb70, 0xf7 }, + { "MSPM0L1306QDYYR", 0xbb70, 0x9f }, + { "MSPM0L1306QRHBR", 0xbb70, 0xc2 }, + { "MSPM0L1306SDGS20R", 0xbb70, 0xf4 }, + { "MSPM0L1306SDGS28R", 0xbb70, 0x5 }, + { "MSPM0L1306SDYYR", 0xbb70, 0xe }, + { "MSPM0L1306SRGER", 0xbb70, 0x7f }, + { "MSPM0L1306SRHBR", 0xbb70, 0x3c }, + { "MSPM0L1306TDGS20R", 0xbb70, 0xa }, + { "MSPM0L1306TDGS28R", 0xbb70, 0x63 }, + { "MSPM0L1306TDYYR", 0xbb70, 0x35 }, + { "MSPM0L1306TRGER", 0xbb70, 0xaa }, + { "MSPM0L1306TRHBR", 0xbb70, 0x52 }, + { "MSPM0L1343TDGS20R", 0xb231, 0x2e }, + { "MSPM0L1344TDGS20R", 0x40b0, 0xd0 }, + { "MSPM0L1345TDGS28R", 0x98b4, 0x74 }, + { "MSPM0L1346TDGS28R", 0xf2b5, 0xef }, +}; + +/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-20 */ +static const struct mspm0_part_info mspm0g_parts[] = { + { "MSPM0G1105TPTR", 0x8934, 0xD }, + { "MSPM0G1105TRGZR", 0x8934, 0xFE }, + { "MSPM0G1106TPMR", 0x477B, 0xD4 }, + { "MSPM0G1106TPTR", 0x477B, 0x71 }, + { "MSPM0G1106TRGZR", 0x477B, 0xBB }, + { "MSPM0G1106TRHBR", 0x477B, 0x0 }, + { "MSPM0G1107TDGS28R", 0x807B, 0x82 }, + { "MSPM0G1107TPMR", 0x807B, 0xB3 }, + { "MSPM0G1107TPTR", 0x807B, 0x32 }, + { "MSPM0G1107TRGER", 0x807B, 0x79 }, + { "MSPM0G1107TRGZR", 0x807B, 0x20 }, + { "MSPM0G1107TRHBR", 0x807B, 0xBC }, + { "MSPM0G1505SDGS28R", 0x13C4, 0x73 }, + { "MSPM0G1505SPMR", 0x13C4, 0x53 }, + { "MSPM0G1505SPTR", 0x13C4, 0x3E }, + { "MSPM0G1505SRGER", 0x13C4, 0x47 }, + { "MSPM0G1505SRGZR", 0x13C4, 0x34 }, + { "MSPM0G1505SRHBR", 0x13C4, 0x30 }, + { "MSPM0G1506SDGS28R", 0x5AE0, 0x3A }, + { "MSPM0G1506SPMR", 0x5AE0, 0xF6 }, + { "MSPM0G1506SRGER", 0x5AE0, 0x67 }, + { "MSPM0G1506SRGZR", 0x5AE0, 0x75 }, + { "MSPM0G1506SRHBR", 0x5AE0, 0x57 }, + { "MSPM0G1507SDGS28R", 0x2655, 0x6D }, + { "MSPM0G1507SPMR", 0x2655, 0x97 }, + { "MSPM0G1507SRGER", 0x2655, 0x83 }, + { "MSPM0G1507SRGZR", 0x2655, 0xD3 }, + { "MSPM0G1507SRHBR", 0x2655, 0x4D }, + { "MSPM0G3105SDGS20R", 0x4749, 0x21 }, + { "MSPM0G3105SDGS28R", 0x4749, 0xDD }, + { "MSPM0G3105SRHBR", 0x4749, 0xBE }, + { "MSPM0G3106SDGS20R", 0x54C7, 0xD2 }, + { "MSPM0G3106SDGS28R", 0x54C7, 0xB9 }, + { "MSPM0G3106SRHBR", 0x54C7, 0x67 }, + { "MSPM0G3107SDGS20R", 0xAB39, 0x5C }, + { "MSPM0G3107SDGS28R", 0xAB39, 0xCC }, + { "MSPM0G3107SRHBR", 0xAB39, 0xB7 }, + { "MSPM0G3505SDGS28R", 0xc504, 0x8e }, + { "MSPM0G3505SPMR", 0xc504, 0x1d }, + { "MSPM0G3505SPTR", 0xc504, 0x93 }, + { "MSPM0G3505SRGZR", 0xc504, 0xc7 }, + { "MSPM0G3505SRHBR", 0xc504, 0xe7 }, + { "MSPM0G3505TDGS28R", 0xc504, 0xdf }, + { "MSPM0G3506SDGS28R", 0x151f, 0x8 }, + { "MSPM0G3506SPMR", 0x151f, 0xd4 }, + { "MSPM0G3506SPTR", 0x151f, 0x39 }, + { "MSPM0G3506SRGZR", 0x151f, 0xfe }, + { "MSPM0G3506SRHBR", 0x151f, 0xb5 }, + { "MSPM0G3507SDGS28R", 0xae2d, 0xca }, + { "MSPM0G3507SPMR", 0xae2d, 0xc7 }, + { "MSPM0G3507SPTR", 0xae2d, 0x3f }, + { "MSPM0G3507SRGZR", 0xae2d, 0xf7 }, + { "MSPM0G3507SRHBR", 0xae2d, 0x4c }, + { "M0G3107QPMRQ1", 0x4e2f, 0x51 }, + { "M0G3107QPTRQ1", 0x4e2f, 0xc7}, + { "M0G3107QRGZRQ1", 0x4e2f, 0x8a }, + { "M0G3107QRHBRQ1", 0x4e2f, 0x9a}, + { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5}, + { "M0G3107QDGS28RQ1", 0x4e2f, 0x67}, + { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd}, + { "M0G3106QPMRQ1", 0x54C7, 0x08}, + { "M0G3105QDGS32RQ1", 0x1349, 0x08}, + { "M0G3106QPTRQ1", 0x54C7, 0x3F}, + { "M0G3105QDGS28RQ1", 0x1349, 0x1B}, + { "M0G3106QRGZRQ1", 0x94AD, 0xE6}, + { "M0G3105QDGS20RQ1", 0x1349, 0xFB}, + { "M0G3106QRHBRQ1", 0x94AD, 0x20}, + { "M0G3106QDGS32RQ1", 0x94AD, 0x8D}, + { "M0G3106QDGS28RQ1", 0x94AD, 0x03}, + { "M0G3106QDGS20RQ1", 0x94AD, 0x6F}, + { "M0G3105QPMRQ1", 0x1349, 0xD0}, + { "M0G3105QPTRQ1", 0x1349, 0xEF}, + { "M0G3105QRGZRQ1", 0x1349, 0x70}, + { "M0G3105QRHBRQ1", 0x1349, 0x01}, +}; + +/* https://www.ti.com/lit/gpn/mspm0c1104 Table 8-12 and so on */ +static const struct mspm0_part_info mspm0c_parts[] = { + { "MSPS003F4SPW20R", 0x57b3, 0x70}, + { "MSPM0C1104SDGS20R", 0x57b3, 0x71}, + { "MSPM0C1104SRUKR", 0x57b3, 0x73}, + { "MSPM0C1104SDYYR", 0x57b3, 0x75}, + { "MSPM0C1104SDDFR", 0x57b3, 0x77}, + { "MSPM0C1104SDSGR", 0x57b3, 0x79}, +}; + +/* https://www.ti.com/lit/gpn/MSPM0L2228 Table 8-16 and so on */ +static const struct mspm0_part_info mspm0lx22x_parts[] = { + { "MSPM0L1227SRGER", 0x7C32, 0xF1}, + { "MSPM0L1227SPTR", 0x7C32, 0xC9}, + { "MSPM0L1227SPMR", 0x7C32, 0x1C}, + { "MSPM0L1227SPNAR", 0x7C32, 0x91}, + { "MSPM0L1227SPNR", 0x7C32, 0x39}, + { "MSPM0L1228SRGER", 0x33F7, 0x13}, + { "MSPM0L1228SRHBR", 0x33F7, 0x3A}, + { "MSPM0L1228SRGZR", 0x33F7, 0xBC}, + { "MSPM0L1228SPTR", 0x33F7, 0xF8}, + { "MSPM0L1228SPMR", 0x33F7, 0xCE}, + { "MSPM0L1228SPNAR", 0x33F7, 0x59}, + { "MSPM0L1228SPNR", 0x33F7, 0x7}, + { "MSPM0L2227SRGZR", 0x5E8F, 0x90}, + { "MSPM0L2227SPTR", 0x5E8F, 0xA}, + { "MSPM0L2227SPMR", 0x5E8F, 0x6D}, + { "MSPM0L2227SPNAR", 0x5E8F, 0x24}, + { "MSPM0L2227SPNR", 0x5E8F, 0x68}, + { "MSPM0L2228SRGZR", 0x2C38, 0xB8}, + { "MSPM0L2228SPTR", 0x2C38, 0x25}, + { "MSPM0L2228SPMR", 0x2C38, 0x6E}, + { "MSPM0L2228SPNAR", 0x2C38, 0x63}, + { "MSPM0L2228SPNR", 0x2C38, 0x3C}, +}; + +static const struct mspm0_family_info mspm0_finf[] = { + { "MSPM0L", 0xbb82, ARRAY_SIZE(mspm0l_parts), mspm0l_parts }, + { "MSPM0Lx22x", 0xbb9f, ARRAY_SIZE(mspm0lx22x_parts), mspm0lx22x_parts }, + { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts), mspm0g_parts }, + { "MSPM0C", 0xbba1, ARRAY_SIZE(mspm0c_parts), mspm0c_parts }, +}; + +/* + * OpenOCD command interface + */ + +/* + * flash_bank mspm0 <base> <size> 0 0 <target#> + */ +FLASH_BANK_COMMAND_HANDLER(mspm0_flash_bank_command) +{ + struct mspm0_flash_bank *mspm0_info; + + switch (bank->base) { + case MSPM0_FLASH_BASE_NONMAIN: + case MSPM0_FLASH_BASE_MAIN: + case MSPM0_FLASH_BASE_DATA: + break; + default: + LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FAIL; + } + + mspm0_info = calloc(1, sizeof(struct mspm0_flash_bank)); + if (!mspm0_info) { + LOG_ERROR("%s: Out of memory for mspm0_info!", __func__); + return ERROR_FAIL; + } + + bank->driver_priv = mspm0_info; + + mspm0_info->sector_size = 0x400; + + return ERROR_OK; +} + +/* + * Chip identification and status + */ +static int get_mspm0_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + + if (mspm0_info->did == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + command_print_sameline(cmd, + "\nTI MSPM0 information: Chip is " + "%s rev %d Device Unique ID: 0x%" PRIu32 "\n", + mspm0_info->name, mspm0_info->version, + mspm0_info->traceid); + command_print_sameline(cmd, + "main flash: %uKiB in %u bank(s), sram: %uKiB, data flash: %uKiB", + mspm0_info->main_flash_size_kb, + mspm0_info->main_flash_num_banks, mspm0_info->sram_size_kb, + mspm0_info->data_flash_size_kb); + + return ERROR_OK; +} + +/* Extract a bitfield helper */ +static unsigned int mspm0_extract_val(unsigned int var, unsigned char hi, unsigned char lo) +{ + return (var & GENMASK(hi, lo)) >> lo; +} + +static int mspm0_read_part_info(struct flash_bank *bank) +{ + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + struct target *target = bank->target; + const struct mspm0_family_info *minfo = NULL; + + /* Read and parse chip identification and flash version register */ + uint32_t did; + int retval = target_read_u32(target, MSPM0_DID, &did); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read device ID"); + return retval; + } + retval = target_read_u32(target, MSPM0_TRACEID, &mspm0_info->traceid); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read trace ID"); + return retval; + } + uint32_t userid; + retval = target_read_u32(target, MSPM0_USERID, &userid); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read user ID"); + return retval; + } + uint32_t flashram; + retval = target_read_u32(target, MSPM0_SRAMFLASH, &flashram); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read sramflash register"); + return retval; + } + uint32_t flashdesc; + retval = target_read_u32(target, FCTL_REG_DESC, &flashdesc); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read flashctl description register"); + return retval; + } + + unsigned char version = mspm0_extract_val(did, 31, 28); + unsigned short pnum = mspm0_extract_val(did, 27, 12); + unsigned char variant = mspm0_extract_val(userid, 23, 16); + unsigned short part = mspm0_extract_val(userid, 15, 0); + unsigned short manufacturer = mspm0_extract_val(did, 11, 1); + + /* + * Valid DIE and manufacturer ID? + * Check the ALWAYS_1 bit to be 1 and manufacturer to be 0x17. All MSPM0 + * devices within the Device ID field of the factory constants will + * always read 0x17 as it is TI's JEDEC bank and company code. If 1 + * and 0x17 is not read from their respective registers then it truly + * is not a MSPM0 device so we will return an error instead of + * going any further. + */ + if (!(did & BIT(0)) || !(manufacturer & TI_MANUFACTURER_ID)) { + LOG_WARNING("Unknown Device ID[0x%" PRIx32 "], cannot identify target", + did); + LOG_DEBUG("did 0x%" PRIx32 ", traceid 0x%" PRIx32 ", userid 0x%" PRIx32 + ", flashram 0x%" PRIx32 "", did, mspm0_info->traceid, userid, + flashram); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Initialize master index selector and probe status*/ + unsigned char minfo_idx = 0xff; + unsigned char probe_status = MSPM0_NO_ID_FOUND; + + /* Check if we at least know the family of devices */ + for (unsigned int i = 0; i < ARRAY_SIZE(mspm0_finf); i++) { + if (mspm0_finf[i].part_num == pnum) { + minfo_idx = i; + minfo = &mspm0_finf[i]; + probe_status = MSPM0_DEV_ID_FOUND; + break; + } + } + + /* Initialize part index selector*/ + unsigned char pinfo_idx = 0xff; + + /* + * If we can identify the part number then we will attempt to identify + * the specific chip. Otherwise, if we do not know the part number then + * it would be useless to identify the specific chip. + */ + if (probe_status == MSPM0_DEV_ID_FOUND) { + /* Can we specifically identify the chip */ + for (unsigned int i = 0; i < minfo->part_count; i++) { + if (minfo->part_info[i].part == part + && minfo->part_info[i].variant == variant) { + pinfo_idx = i; + probe_status = MSPM0_DEV_PART_ID_FOUND; + break; + } + } + } + + /* + * We will check the status of our probe within this switch-case statement + * using these three scenarios. + * + * 1) Device, part, and variant ID is unknown. + * 2) Device ID is known but the part/variant ID is unknown. + * 3) Device ID and part/variant ID is known + * + * For scenario 1, we allow the user to continue because if the + * manufacturer matches TI's JEDEC value and ALWAYS_1 from the device ID + * field is correct then the assumption the user is using an MSPM0 device + * can be made. + */ + switch (probe_status) { + case MSPM0_NO_ID_FOUND: + mspm0_info->name = "mspm0x"; + LOG_INFO("Unidentified PART[0x%x]/variant[0x%x" + "], unknown DeviceID[0x%x" + "]. Attempting to proceed as %s.", part, variant, pnum, + mspm0_info->name); + break; + case MSPM0_DEV_ID_FOUND: + mspm0_info->name = mspm0_finf[minfo_idx].family_name; + LOG_INFO("Unidentified PART[0x%x]/variant[0x%x" + "], known DeviceID[0x%x" + "]. Attempting to proceed as %s.", part, variant, pnum, + mspm0_info->name); + break; + case MSPM0_DEV_PART_ID_FOUND: + default: + mspm0_info->name = mspm0_finf[minfo_idx].part_info[pinfo_idx].part_name; + LOG_DEBUG("Part: %s detected", mspm0_info->name); + break; + } + + mspm0_info->did = did; + mspm0_info->version = version; + mspm0_info->data_flash_size_kb = mspm0_extract_val(flashram, 31, 26); + mspm0_info->main_flash_size_kb = mspm0_extract_val(flashram, 11, 0); + mspm0_info->main_flash_num_banks = mspm0_extract_val(flashram, 13, 12) + 1; + mspm0_info->sram_size_kb = mspm0_extract_val(flashram, 25, 16); + mspm0_info->flash_version = mspm0_extract_val(flashdesc, 15, 12); + + /* + * Hardcode flash_word_size unless we find some other pattern + * See section 7.7 (Foot note mentions the flash word size). + * almost all values seem to be 8 bytes, but if there are variance, + * then we should update mspm0_part_info structure with this info. + */ + mspm0_info->flash_word_size_bytes = 8; + + LOG_DEBUG("Detected: main flash: %uKb in %u banks, sram: %uKb, data flash: %uKb", + mspm0_info->main_flash_size_kb, mspm0_info->main_flash_num_banks, + mspm0_info->sram_size_kb, mspm0_info->data_flash_size_kb); + + return ERROR_OK; +} + +/* + * Decode error values + */ +static const struct { + const unsigned char bit_offset; + const char *fail_string; +} mspm0_fctl_fail_decode_strings[] = { + { 2, "CMDINPROGRESS" }, + { 4, "FAILWEPROT" }, + { 5, "FAILVERIFY" }, + { 6, "FAILILLADDR" }, + { 7, "FAILMODE" }, + { 12, "FAILMISC" }, +}; + +static const char *mspm0_fctl_translate_ret_err(unsigned int return_code) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(mspm0_fctl_fail_decode_strings); i++) { + if (return_code & BIT(mspm0_fctl_fail_decode_strings[i].bit_offset)) + return mspm0_fctl_fail_decode_strings[i].fail_string; + } + + /* If unknown error notify the user*/ + return "FAILUNKNOWN"; +} + +static int mspm0_fctl_get_sector_reg(struct flash_bank *bank, unsigned int addr, + unsigned int *reg, unsigned int *sector_mask) +{ + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + struct target *target = bank->target; + int ret = ERROR_OK; + unsigned int sector_num = (addr >> 10); + unsigned int sector_in_bank = sector_num; + unsigned int phys_sector_num = sector_num; + uint32_t sysctl_sec_status; + unsigned int exec_upper_bank; + + /* + * If the device has dual banks we will need to check if it is configured + * to execute from the upper bank. In the scenario that we are executing + * from upper bank then we will need to protect it using CMDWEPROTA rather + * than CMDWEPROTB. We also need to take into account what sector + * we're using when going between banks. + */ + if (mspm0_info->main_flash_num_banks > 1 && + bank->base == MSPM0_FLASH_BASE_MAIN) { + ret = target_read_u32(target, SYSCTL_SECCFG_SECSTATUS, &sysctl_sec_status); + if (ret != ERROR_OK) + return ret; + exec_upper_bank = mspm0_extract_val(sysctl_sec_status, 12, 12); + if (exec_upper_bank) { + if (sector_num > (mspm0_info->main_flash_size_kb / 2)) { + phys_sector_num = + sector_num - (mspm0_info->main_flash_size_kb / 2); + } else { + phys_sector_num = + sector_num + (mspm0_info->main_flash_size_kb / 2); + } + } + sector_in_bank = + sector_num % (mspm0_info->main_flash_size_kb / + mspm0_info->main_flash_num_banks); + } + + /* + * NOTE: MSPM0 devices of version A will use CMDWEPROTA and CMDWEPROTB + * for MAIN flash. CMDWEPROTC is included in the TRM/DATASHEET but for + * all practical purposes, it is considered reserved. If the flash + * version on the device is version B, then we will only use + * CMDWEPROTB for MAIN and DATA flash if the device has it. + */ + switch (bank->base) { + case MSPM0_FLASH_BASE_MAIN: + case MSPM0_FLASH_BASE_DATA: + if (mspm0_info->flash_version < FCTL_FEATURE_VER_B) { + /* Use CMDWEPROTA */ + if (phys_sector_num < 32) { + *sector_mask = BIT(phys_sector_num); + *reg = FCTL_REG_CMDWEPROTA; + } + + /* Use CMDWEPROTB */ + if (phys_sector_num >= 32 && sector_in_bank < 256) { + /* Dual bank system */ + if (mspm0_info->main_flash_num_banks > 1) + *sector_mask = BIT(sector_in_bank / 8); + else /* Single bank system */ + *sector_mask = BIT((sector_in_bank - 32) / 8); + *reg = FCTL_REG_CMDWEPROTB; + } + } else { + *sector_mask = BIT((sector_in_bank / 8) % 32); + *reg = FCTL_REG_CMDWEPROTB; + } + break; + case MSPM0_FLASH_BASE_NONMAIN: + *sector_mask = BIT(sector_num % 32); + *reg = FCTL_REG_CMDWEPROTNM; + break; + default: + /* + * Not expected to reach here due to check in mspm0_address_check() + * but adding it as another layer of safety. + */ + ret = ERROR_FLASH_DST_OUT_OF_BANK; + break; + } + + if (ret != ERROR_OK) + LOG_ERROR("Unable to map sector protect reg for address 0x%08x", addr); + + return ret; +} + +static int mspm0_address_check(struct flash_bank *bank, unsigned int addr) +{ + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + unsigned int flash_main_size = mspm0_info->main_flash_size_kb * 1024; + unsigned int flash_data_size = mspm0_info->data_flash_size_kb * 1024; + int ret = ERROR_FLASH_SECTOR_INVALID; + + /* + * Before unprotecting any memory lets make sure that the address and + * bank given is a known bank and whether or not the address falls under + * the proper bank. + */ + switch (bank->base) { + case MSPM0_FLASH_BASE_MAIN: + if (addr <= (MSPM0_FLASH_BASE_MAIN + flash_main_size)) + ret = ERROR_OK; + break; + case MSPM0_FLASH_BASE_NONMAIN: + if (addr >= MSPM0_FLASH_BASE_NONMAIN && addr <= MSPM0_FLASH_END_NONMAIN) + ret = ERROR_OK; + break; + case MSPM0_FLASH_BASE_DATA: + if (addr >= MSPM0_FLASH_BASE_DATA && + addr <= (MSPM0_FLASH_BASE_DATA + flash_data_size)) + ret = ERROR_OK; + break; + default: + ret = ERROR_FLASH_DST_OUT_OF_BANK; + break; + } + + return ret; +} + +static int mspm0_fctl_unprotect_sector(struct flash_bank *bank, unsigned int addr) +{ + struct target *target = bank->target; + unsigned int reg = 0x0; + uint32_t sector_mask = 0x0; + int ret; + + ret = mspm0_address_check(bank, addr); + switch (ret) { + case ERROR_FLASH_SECTOR_INVALID: + LOG_ERROR("Unable to map sector protect reg for address 0x%08x", addr); + break; + case ERROR_FLASH_DST_OUT_OF_BANK: + LOG_ERROR("Unable to determine which bank to use 0x%08x", addr); + break; + default: + mspm0_fctl_get_sector_reg(bank, addr, ®, §or_mask); + ret = target_write_u32(target, reg, ~sector_mask); + break; + } + + return ret; +} + +static int mspm0_fctl_cfg_command(struct flash_bank *bank, + uint32_t addr, + uint32_t cmd, + uint32_t byte_en) +{ + struct target *target = bank->target; + + /* + * Configure the flash operation within the CMDTYPE register, byte_en + * bits if needed, and then set the address where the flash operation + * will execute. + */ + int retval = target_write_u32(target, FCTL_REG_CMDTYPE, cmd); + if (retval != ERROR_OK) + return retval; + if (byte_en != 0) { + retval = target_write_u32(target, FCTL_REG_CMDBYTEN, byte_en); + if (retval != ERROR_OK) + return retval; + } + + return target_write_u32(target, FCTL_REG_CMDADDR, addr); +} + +static int mspm0_fctl_wait_cmd_ok(struct flash_bank *bank) +{ + struct target *target = bank->target; + uint32_t return_code = 0; + int64_t start_ms; + int64_t elapsed_ms; + + start_ms = timeval_ms(); + while ((return_code & FCTL_STATCMD_CMDDONE_MASK) != FCTL_STATCMD_CMDDONE_STATDONE) { + int retval = target_read_u32(target, FCTL_REG_STATCMD, &return_code); + if (retval != ERROR_OK) + return retval; + + elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + if (elapsed_ms > MSPM0_FLASH_TIMEOUT_MS) + break; + } + + if ((return_code & FCTL_STATCMD_CMDPASS_MASK) != FCTL_STATCMD_CMDPASS_STATPASS) { + LOG_ERROR("Flash command failed: %s", mspm0_fctl_translate_ret_err(return_code)); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int mspm0_fctl_sector_erase(struct flash_bank *bank, uint32_t addr) +{ + struct target *target = bank->target; + + /* + * TRM Says: + * Note that the CMDWEPROTx registers are reset to a protected state + * at the end of all program and erase operations. These registers + * must be re-configured by software before a new operation is + * initiated. + * + * This means that as we start erasing sector by sector, the protection + * registers are reset and need to be unprotected *again* for the next + * erase operation. Unfortunately, this means that we cannot do a unitary + * unprotect operation independent of flash erase operation + */ + int retval = mspm0_fctl_unprotect_sector(bank, addr); + if (retval != ERROR_OK) { + LOG_ERROR("Unprotecting sector of memory at address 0x%08" PRIx32 + " failed", addr); + return retval; + } + + /* Actual erase operation */ + retval = mspm0_fctl_cfg_command(bank, addr, + (FCTL_CMDTYPE_COMMAND_ERASE | FCTL_CMDTYPE_SIZE_SECTOR), 0); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, FCTL_REG_CMDEXEC, FCTL_CMDEXEC_VAL_EXECUTE); + if (retval != ERROR_OK) + return retval; + + return mspm0_fctl_wait_cmd_ok(bank); +} + +static int mspm0_protect_check(struct flash_bank *bank) +{ + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + + if (mspm0_info->did == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + /* + * TRM Says: + * Note that the CMDWEPROTx registers are reset to a protected state + * at the end of all program and erase operations. These registers + * must be re-configured by software before a new operation is + * initiated. + * + * This means that when any flash operation is performed at a block level, + * the block is locked back again. This prevents usage where we can set a + * protection level once at the flash level and then do erase / write + * operation without touching the protection register (since it is + * reset by hardware automatically). In effect, we cannot use the hardware + * defined protection scheme in openOCD. + * + * To deal with this protection scheme, the CMDWEPROTx register that + * correlates to the sector is modified at the time of operation and as far + * openOCD is concerned, the flash operates as completely un-protected + * flash. + */ + for (unsigned int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = 0; + + return ERROR_OK; +} + +static int mspm0_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + int retval = ERROR_OK; + uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS]; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Please halt target for erasing flash"); + return ERROR_TARGET_NOT_HALTED; + } + + if (mspm0_info->did == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + /* Pick a copy of the current protection config for later restoration */ + for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) { + retval = target_read_u32(target, + mspm0_info->protect_reg_base + (i * 4), + &protect_reg_cache[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Failed saving flashctl protection status"); + return retval; + } + } + + switch (bank->base) { + case MSPM0_FLASH_BASE_MAIN: + for (unsigned int csa = first; csa <= last; csa++) { + unsigned int addr = csa * mspm0_info->sector_size; + retval = mspm0_fctl_sector_erase(bank, addr); + if (retval != ERROR_OK) + LOG_ERROR("Sector erase on MAIN failed at address 0x%08x " + "(sector: %u)", addr, csa); + } + break; + case MSPM0_FLASH_BASE_NONMAIN: + retval = mspm0_fctl_sector_erase(bank, MSPM0_FLASH_BASE_NONMAIN); + if (retval != ERROR_OK) + LOG_ERROR("Sector erase on NONMAIN failed"); + break; + case MSPM0_FLASH_BASE_DATA: + for (unsigned int csa = first; csa <= last; csa++) { + unsigned int addr = (MSPM0_FLASH_BASE_DATA + + (csa * mspm0_info->sector_size)); + retval = mspm0_fctl_sector_erase(bank, addr); + if (retval != ERROR_OK) + LOG_ERROR("Sector erase on DATA bank failed at address 0x%08x " + "(sector: %u)", addr, csa); + } + break; + default: + LOG_ERROR("Invalid memory region access"); + retval = ERROR_FLASH_BANK_INVALID; + break; + } + + /* If there were any issues in our checks, return the error */ + if (retval != ERROR_OK) + return retval; + + /* + * TRM Says: + * Note that the CMDWEPROTx registers are reset to a protected state + * at the end of all program and erase operations. These registers + * must be re-configured by software before a new operation is + * initiated + * Let us just Dump the protection registers back to the system. + * That way we retain the protection status as requested by the user + */ + for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) { + retval = target_write_u32(target, mspm0_info->protect_reg_base + (i * 4), + protect_reg_cache[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Failed re-applying protection status of flashctl"); + return retval; + } + } + + return retval; +} + +static int mspm0_write(struct flash_bank *bank, const unsigned char *buffer, + unsigned int offset, unsigned int count) +{ + struct target *target = bank->target; + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS]; + int retval; + + /* + * XXX: TRM Says: + * The number of program operations applied to a given word line must be + * monitored to ensure that the maximum word line program limit before + * erase is not violated. + * + * There is no reasonable way we can maintain that state in OpenOCD. So, + * Let the manufacturing path figure this out. + */ + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Please halt target for programming flash"); + return ERROR_TARGET_NOT_HALTED; + } + + if (mspm0_info->did == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + /* + * Pick a copy of the current protection config for later restoration + * We need to restore these regs after every write, so instead of trying + * to figure things out on the fly, we just context save and restore + */ + for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) { + retval = target_read_u32(target, + mspm0_info->protect_reg_base + (i * 4), + &protect_reg_cache[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Failed saving flashctl protection status"); + return retval; + } + } + + /* Add proper memory offset for bank being written to */ + unsigned int addr = bank->base + offset; + + while (count) { + unsigned int num_bytes_to_write; + uint32_t bytes_en; + + /* + * If count is not 64 bit aligned, we will do byte wise op to keep things simple + * Usually this might mean we need to additional write ops towards + * trailing edge, but that is a tiny penalty for image downloads. + * NOTE: we are going to assume the device does not support multi-word + * programming - there does not seem to be discoverability! + */ + if (count < mspm0_info->flash_word_size_bytes) + num_bytes_to_write = count; + else + num_bytes_to_write = mspm0_info->flash_word_size_bytes; + + /* Data bytes to write */ + bytes_en = (1 << num_bytes_to_write) - 1; + /* ECC chunks to write */ + switch (mspm0_info->flash_word_size_bytes) { + case 8: + bytes_en |= BIT(8); + break; + case 16: + bytes_en |= BIT(16); + bytes_en |= (num_bytes_to_write > 8) ? BIT(17) : 0; + break; + default: + LOG_ERROR("Invalid flash_word_size_bytes %d", + mspm0_info->flash_word_size_bytes); + return ERROR_FAIL; + } + + retval = mspm0_fctl_cfg_command(bank, addr, + (FCTL_CMDTYPE_COMMAND_PROGRAM | FCTL_CMDTYPE_SIZE_ONEWORD), + bytes_en); + if (retval != ERROR_OK) + return retval; + + retval = mspm0_fctl_unprotect_sector(bank, addr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_buffer(target, FCTL_REG_CMDDATA0, num_bytes_to_write, buffer); + if (retval != ERROR_OK) + return retval; + + addr += num_bytes_to_write; + buffer += num_bytes_to_write; + count -= num_bytes_to_write; + + retval = target_write_u32(target, FCTL_REG_CMDEXEC, FCTL_CMDEXEC_VAL_EXECUTE); + if (retval != ERROR_OK) + return retval; + + retval = mspm0_fctl_wait_cmd_ok(bank); + if (retval != ERROR_OK) + return retval; + } + + /* + * TRM Says: + * Note that the CMDWEPROTx registers are reset to a protected state + * at the end of all program and erase operations. These registers + * must be re-configured by software before a new operation is + * initiated + * Let us just Dump the protection registers back to the system. + * That way we retain the protection status as requested by the user + */ + for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) { + retval = target_write_u32(target, + mspm0_info->protect_reg_base + (i * 4), + protect_reg_cache[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Failed re-applying protection status of flashctl"); + return retval; + } + } + + return ERROR_OK; +} + +static int mspm0_probe(struct flash_bank *bank) +{ + struct mspm0_flash_bank *mspm0_info = bank->driver_priv; + + /* + * If this is a mspm0 chip, it has flash; probe() is just + * to figure out how much is present. Only do it once. + */ + if (mspm0_info->did != 0) + return ERROR_OK; + + /* + * mspm0_read_part_info() already handled error checking and + * reporting. Note that it doesn't write, so we don't care about + * whether the target is halted or not. + */ + int retval = mspm0_read_part_info(bank); + if (retval != ERROR_OK) + return retval; + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + bank->write_start_alignment = 4; + bank->write_end_alignment = 4; + + switch (bank->base) { + case MSPM0_FLASH_BASE_NONMAIN: + bank->size = 1024; + bank->num_sectors = 0x1; + mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTNM; + mspm0_info->protect_reg_count = 1; + break; + case MSPM0_FLASH_BASE_MAIN: + bank->size = (mspm0_info->main_flash_size_kb * 1024); + bank->num_sectors = bank->size / mspm0_info->sector_size; + /* + * If the feature version bit read from the FCTL_REG_DESC is + * greater than or equal to 0xA then it means that the device + * will exclusively use CMDWEPROTB ONLY for MAIN memory protection + */ + if (mspm0_info->flash_version >= FCTL_FEATURE_VER_B) { + mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTB; + mspm0_info->protect_reg_count = 1; + } else { + mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTA; + mspm0_info->protect_reg_count = 3; + } + break; + case MSPM0_FLASH_BASE_DATA: + if (!mspm0_info->data_flash_size_kb) { + LOG_INFO("Data region NOT available!"); + bank->size = 0x0; + bank->num_sectors = 0x0; + return ERROR_OK; + } + /* + * Any MSPM0 device containing data bank will have a flashctl + * feature version of 0xA or higher. Since data bank is treated + * like MAIN memory, it will also exclusively use CMDWEPROTB for + * protection. + */ + bank->size = (mspm0_info->data_flash_size_kb * 1024); + bank->num_sectors = bank->size / mspm0_info->sector_size; + mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTB; + mspm0_info->protect_reg_count = 1; + break; + default: + LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, + bank->base); + return ERROR_FAIL; + } + + bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); + if (!bank->sectors) { + LOG_ERROR("Out of memory for sectors!"); + return ERROR_FAIL; + } + for (unsigned int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * mspm0_info->sector_size; + bank->sectors[i].size = mspm0_info->sector_size; + bank->sectors[i].is_erased = -1; + } + + return ERROR_OK; +} + +const struct flash_driver mspm0_flash = { + .name = "mspm0", + .flash_bank_command = mspm0_flash_bank_command, + .erase = mspm0_erase, + .protect = NULL, + .write = mspm0_write, + .read = default_flash_read, + .probe = mspm0_probe, + .auto_probe = mspm0_probe, + .erase_check = default_flash_blank_check, + .protect_check = mspm0_protect_check, + .info = get_mspm0_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/niietcm4.c b/src/flash/nor/niietcm4.c index 0c36e2c..aaf0726 100644 --- a/src/flash/nor/niietcm4.c +++ b/src/flash/nor/niietcm4.c @@ -311,7 +311,7 @@ static int niietcm4_uflash_page_erase(struct flash_bank *bank, int page_num, int /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) - return retval; + return retval; return retval; } @@ -394,7 +394,7 @@ COMMAND_HANDLER(niietcm4_handle_uflash_read_byte_command) uint32_t uflash_data; if (strcmp("info", CMD_ARGV[0]) == 0) - uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; + uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; else if (strcmp("main", CMD_ARGV[0]) == 0) uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ; else @@ -539,7 +539,7 @@ COMMAND_HANDLER(niietcm4_handle_uflash_erase_command) int mem_type; if (strcmp("info", CMD_ARGV[0]) == 0) - mem_type = 1; + mem_type = 1; else if (strcmp("main", CMD_ARGV[0]) == 0) mem_type = 0; else diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index f07433e..5cb552a 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -117,20 +117,24 @@ struct nrf5_map { struct nrf5_info { unsigned int refcount; + bool chip_probed; 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() */ + /* chip identification stored in nrf5_probe_chip() + * for use in nrf5_info() and nrf5_setup_bank() */ bool ficr_info_valid; struct nrf52_ficr_info ficr_info; const struct nrf5_device_spec *spec; uint16_t hwid; enum nrf5_features features; - unsigned int flash_size_kb; + uint32_t flash_page_size; + uint32_t flash_num_sectors; unsigned int ram_size_kb; const struct nrf5_map *map; @@ -341,16 +345,19 @@ const struct flash_driver nrf5_flash, nrf51_flash; static bool nrf5_bank_is_probed(const struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); - return nbank->probed; } -static bool nrf5_bank_is_uicr(const struct nrf5_bank *nbank) +static bool nrf5_chip_is_probed(const struct flash_bank *bank) { + struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; - assert(chip); + return chip->chip_probed; +} +static bool nrf5_bank_is_uicr(const struct nrf5_bank *nbank) +{ + struct nrf5_info *chip = nbank->chip; return nbank == &chip->bank[1]; } @@ -470,9 +477,7 @@ static int nrf51_protect_check_clenr0(struct flash_bank *bank) uint32_t clenr0; struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); res = target_read_u32(chip->target, NRF51_FICR_CLENR0, &clenr0); @@ -501,9 +506,7 @@ static int nrf51_protect_check_clenr0(struct flash_bank *bank) static int nrf52_protect_check_bprot(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; uint32_t bprot_reg = 0; @@ -528,9 +531,7 @@ static int nrf52_protect_check_bprot(struct flash_bank *bank) static int nrf5_protect_check(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); /* UICR cannot be write protected so just return early */ if (nrf5_bank_is_uicr(nbank)) @@ -554,9 +555,7 @@ static int nrf51_protect_clenr0(struct flash_bank *bank, int set, unsigned int f uint32_t clenr0, ppfc; struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); if (first != 0) { LOG_ERROR("Code region 0 must start at the beginning of the bank"); @@ -614,9 +613,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); /* UICR cannot be write protected so just bail out early */ if (nrf5_bank_is_uicr(nbank)) { @@ -701,16 +698,15 @@ static int nrf5_get_chip_type_str(const struct nrf5_info *chip, char *buf, unsig static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); char chip_type_str[256]; if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; + unsigned int flash_size_kb = chip->flash_num_sectors * chip->flash_page_size / 1024; command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", - chip_type_str, chip->flash_size_kb, chip->ram_size_kb); + chip_type_str, flash_size_kb, chip->ram_size_kb); return ERROR_OK; } @@ -838,14 +834,12 @@ static int nrf51_get_ram_size(struct target *target, uint32_t *ram_size) return res; } -static int nrf5_probe(struct flash_bank *bank) +static int nrf5_probe_chip(struct flash_bank *bank) { int res = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); struct target *target = chip->target; chip->spec = NULL; @@ -968,9 +962,8 @@ static int nrf5_probe(struct flash_bank *bank) } /* The value stored in FICR CODEPAGESIZE is the number of bytes in one page of FLASH. */ - uint32_t flash_page_size; res = target_read_u32(chip->target, ficr_base + ficr_offsets->codepagesize, - &flash_page_size); + &chip->flash_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); return res; @@ -978,69 +971,93 @@ static int nrf5_probe(struct flash_bank *bank) /* Note the register name is misleading, * 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, ficr_base + ficr_offsets->codesize, - &num_sectors); + &chip->flash_num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; } - chip->flash_size_kb = num_sectors * flash_page_size / 1024; + char chip_type_str[256]; + if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + return ERROR_FAIL; - if (!chip->bank[0].probed && !chip->bank[1].probed) { - char chip_type_str[256]; - if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) - return ERROR_FAIL; - const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); - LOG_INFO("%s%s %ukB Flash, %ukB RAM", - device_is_unknown ? "Unknown device: " : "", - chip_type_str, - chip->flash_size_kb, - chip->ram_size_kb); - } + unsigned int flash_size_kb = chip->flash_num_sectors * chip->flash_page_size / 1024; + const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); + LOG_INFO("%s%s %ukB Flash, %ukB RAM", + device_is_unknown ? "Unknown device: " : "", + chip_type_str, + flash_size_kb, + chip->ram_size_kb); - free(bank->sectors); + chip->chip_probed = true; + return ERROR_OK; +} + +static int nrf5_setup_bank(struct flash_bank *bank) +{ + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; if (bank->base == chip->map->flash_base) { + unsigned int flash_size_kb = chip->flash_num_sectors * chip->flash_page_size / 1024; /* Sanity check */ - if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) + if (chip->spec && 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) + if (chip->ficr_info_valid && 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->num_sectors = chip->flash_num_sectors; + bank->size = chip->flash_num_sectors * chip->flash_page_size; - bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + bank->sectors = alloc_block_array(0, chip->flash_page_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; chip->bank[0].probed = true; - } else { + } else if (bank->base == chip->map->uicr_base) { /* UICR bank */ bank->num_sectors = 1; - bank->size = flash_page_size; + bank->size = chip->flash_page_size; - bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + bank->sectors = alloc_block_array(0, chip->flash_page_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; bank->sectors[0].is_protected = 0; chip->bank[1].probed = true; + } else { + LOG_ERROR("Invalid nRF bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } +static int nrf5_probe(struct flash_bank *bank) +{ + /* probe always reads actual info from the device */ + int res = nrf5_probe_chip(bank); + if (res != ERROR_OK) + return res; + + return nrf5_setup_bank(bank); +} + static int nrf5_auto_probe(struct flash_bank *bank) { if (nrf5_bank_is_probed(bank)) return ERROR_OK; - return nrf5_probe(bank); + if (!nrf5_chip_is_probed(bank)) { + int res = nrf5_probe_chip(bank); + if (res != ERROR_OK) + return res; + } + + return nrf5_setup_bank(bank); } @@ -1214,9 +1231,7 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, } struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); assert(offset % 4 == 0); assert(count % 4 == 0); @@ -1276,9 +1291,7 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, } struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); /* UICR CLENR0 based protection used on nRF51 prevents erase * absolutely silently. NVMC has no flag to indicate the protection @@ -1322,7 +1335,6 @@ error: static void nrf5_free_driver_priv(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; if (!chip) return; @@ -1372,8 +1384,8 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) case NRF53NET_UICR_BASE: break; default: - LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); - return ERROR_FAIL; + LOG_ERROR("Invalid nRF bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FLASH_BANK_INVALID; } chip = nrf5_get_chip(bank->target); @@ -1418,17 +1430,13 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) if (res != ERROR_OK) return res; - assert(bank); - if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c index e00c365..61af908 100644 --- a/src/flash/nor/ocl.c +++ b/src/flash/nor/ocl.c @@ -160,7 +160,7 @@ static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer); if (retval != ERROR_OK) { free(dcc_buffer); - return retval; + return retval; } /* wait for response, fixed timeout of 1 s */ diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 1064fa9..72cf0ee 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -384,15 +384,15 @@ static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, u * bit 7..0 family ID (lowest 8 bits) */ if (silicon_id) - *silicon_id = ((part0 & 0x0000ffff) << 16) - | ((part0 & 0x00ff0000) >> 8) - | (part1 & 0x000000ff); + *silicon_id = ((part0 & 0x0000ffff) << 16) + | ((part0 & 0x00ff0000) >> 8) + | (part1 & 0x000000ff); if (family_id) - *family_id = part1 & 0x0fff; + *family_id = part1 & 0x0fff; if (protection) - *protection = (part1 >> 12) & 0x0f; + *protection = (part1 >> 12) & 0x0f; return ERROR_OK; } diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c index 407efbc..e8c9019 100644 --- a/src/flash/nor/psoc5lp.c +++ b/src/flash/nor/psoc5lp.c @@ -102,10 +102,10 @@ struct psoc5lp_device { uint32_t id; - unsigned fam; - unsigned speed_mhz; - unsigned flash_kb; - unsigned eeprom_kb; + unsigned int fam; + unsigned int speed_mhz; + unsigned int flash_kb; + unsigned int eeprom_kb; }; /* @@ -245,7 +245,7 @@ static int psoc5lp_find_device(struct target *target, const struct psoc5lp_device **device) { uint32_t device_id; - unsigned i; + unsigned int i; int retval; *device = NULL; @@ -381,9 +381,9 @@ static int psoc5lp_spc_load_byte(struct target *target, } static int psoc5lp_spc_load_row(struct target *target, - uint8_t array_id, const uint8_t *data, unsigned row_size) + uint8_t array_id, const uint8_t *data, unsigned int row_size) { - unsigned i; + unsigned int i; int retval; retval = psoc5lp_spc_write_opcode(target, SPC_LOAD_ROW); @@ -853,7 +853,7 @@ static int psoc5lp_eeprom_write(struct flash_bank *bank, { struct target *target = bank->target; uint8_t temp[2]; - unsigned row; + unsigned int row; int retval; if (offset % EEPROM_ROW_SIZE != 0) { @@ -1124,7 +1124,7 @@ static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer, struct working_area *code_area, *even_row_area, *odd_row_area; uint32_t row_size; uint8_t temp[2], buf[12], ecc_bytes[ROW_ECC_SIZE]; - unsigned array_id, row; + unsigned int array_id, row; int i, retval; if (offset + byte_count > bank->size) { @@ -1183,7 +1183,7 @@ static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer, row < ROWS_PER_BLOCK && byte_count > 0; row++) { bool even_row = (row % 2 == 0); struct working_area *data_area = even_row ? even_row_area : odd_row_area; - unsigned len = MIN(ROW_SIZE, byte_count); + unsigned int len = MIN(ROW_SIZE, byte_count); LOG_DEBUG("Writing load command for array %u row %u at " TARGET_ADDR_FMT, array_id, row, data_area->address); @@ -1307,8 +1307,8 @@ static int psoc5lp_protect_check(struct flash_bank *bank) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; uint8_t row_data[ROW_SIZE]; - const unsigned protection_bytes_per_sector = ROWS_PER_SECTOR * 2 / 8; - unsigned i, k, num_sectors; + const unsigned int protection_bytes_per_sector = ROWS_PER_SECTOR * 2 / 8; + unsigned int i, k, num_sectors; int retval; if (bank->target->state != TARGET_HALTED) { diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 859b3e9..662910a 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -223,6 +223,8 @@ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_ { int hr; uint32_t reg_val; + struct armv7m_common *armv7m = target_to_armv7m(target); + bool is_cm0 = (armv7m->arm.arch == ARM_ARCH_V6M); struct timeout to; timeout_init(&to, IPC_TIMEOUT_MS); @@ -244,7 +246,7 @@ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_ return ERROR_OK; } - if (target->coreid) { + if (!is_cm0) { LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. " "Please perform all Flash-related operations via CM0+ target on dual-core devices."); } @@ -485,7 +487,7 @@ static int psoc6_get_info(struct flash_bank *bank, struct command_invocation *cm { struct psoc6_target_info *psoc6_info = bank->driver_priv; - if (psoc6_info->is_probed == false) + if (!psoc6_info->is_probed) return ERROR_FAIL; int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); @@ -886,7 +888,8 @@ static int handle_reset_halt(struct target *target) { int hr; uint32_t reset_addr; - bool is_cm0 = (target->coreid == 0); + struct armv7m_common *armv7m = target_to_armv7m(target); + bool is_cm0 = (armv7m->arm.arch == ARM_ARCH_V6M); /* Halt target device */ if (target->state != TARGET_HALTED) { diff --git a/src/flash/nor/rsl10.c b/src/flash/nor/rsl10.c index c286e9a..c330997 100644 --- a/src/flash/nor/rsl10.c +++ b/src/flash/nor/rsl10.c @@ -155,11 +155,6 @@ static int rsl10_get_probed_chip_if_halted(struct flash_bank *bank, struct rsl10 static int rsl10_protect_check(struct flash_bank *bank) { - struct rsl10_bank *nbank = bank->driver_priv; - struct rsl10_info *chip = nbank->chip; - - assert(chip); - uint32_t status; int retval = target_read_u32(bank->target, RSL10_FLASH_REG_IF_STATUS, &status); diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c index 5bfb541..8e25ba6 100644 --- a/src/flash/nor/sfdp.c +++ b/src/flash/nor/sfdp.c @@ -12,7 +12,6 @@ #include "spi.h" #include "sfdp.h" -#define SFDP_MAGIC 0x50444653 #define SFDP_ACCESS_PROT 0xFF #define SFDP_BASIC_FLASH 0xFF00 #define SFDP_4BYTE_ADDR 0xFF84 @@ -100,11 +99,11 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, goto err; for (k = 0; k < nph; k++) { - uint8_t words = (pheaders[k].revision >> 24) & 0xFF; + unsigned int words = (pheaders[k].revision >> 24) & 0xFF; uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF); uint32_t ptr = pheaders[k].ptr & 0xFFFFFF; - LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16 + LOG_DEBUG("pheader %d len=0x%02x id=0x%04" PRIx16 " ptr=0x%06" PRIx32, k, words, id, ptr); /* retrieve parameter table */ diff --git a/src/flash/nor/sfdp.h b/src/flash/nor/sfdp.h index 1c9af32..0d43519 100644 --- a/src/flash/nor/sfdp.h +++ b/src/flash/nor/sfdp.h @@ -7,6 +7,8 @@ #ifndef OPENOCD_FLASH_NOR_SFDP_H #define OPENOCD_FLASH_NOR_SFDP_H +#define SFDP_MAGIC 0x50444653 + /* per JESD216D 'addr' is *byte* based but must be word aligned, * 'buffer' is word based, word aligned and always little-endian encoded, * in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8 @@ -16,7 +18,7 @@ * * buffer contents is supposed to be returned in ***host*** endianness */ typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr, - uint32_t words, uint32_t *buffer); + unsigned int words, uint32_t *buffer); extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, read_sfdp_block_t read_sfdp_block); diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 42550d0..58d7913 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -859,7 +859,7 @@ static int sim3x_flash_info(struct flash_bank *bank, struct command_invocation * * reg 3:2 - register * reg 1:0 - no effect */ -static int ap_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) +static int ap_write_register(struct adiv5_dap *dap, unsigned int reg, uint32_t value) { LOG_DEBUG("DAP_REG[0x%02x] <- %08" PRIX32, reg, value); @@ -886,7 +886,7 @@ static int ap_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value return ERROR_OK; } -static int ap_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) +static int ap_read_register(struct adiv5_dap *dap, unsigned int reg, uint32_t *result) { struct adiv5_ap *ap = dap_get_ap(dap, SIM3X_AP); if (!ap) { @@ -912,7 +912,7 @@ static int ap_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *resul return ERROR_OK; } -static int ap_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value, int timeout) +static int ap_poll_register(struct adiv5_dap *dap, unsigned int reg, uint32_t mask, uint32_t value, int timeout) { uint32_t val; int retval; diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index eab6244..1f53b2f 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -530,7 +530,7 @@ static void stellaris_set_flash_timing(struct flash_bank *bank) target_write_u32(target, SCB_BASE | USECRL, usecrl); } -static const unsigned rcc_xtal[32] = { +static const unsigned int rcc_xtal[32] = { [0x00] = 1000000, /* no pll */ [0x01] = 1843200, /* no pll */ [0x02] = 2000000, /* no pll */ @@ -569,7 +569,7 @@ static void stellaris_read_clock_info(struct flash_bank *bank) struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc; - unsigned xtal; + unsigned int xtal; unsigned long mainfreq; target_read_u32(target, SCB_BASE | RCC, &rcc); @@ -1029,7 +1029,7 @@ static int stellaris_write_block(struct flash_bank *bank, int retval = ERROR_OK; /* power of two, and multiple of word size */ - static const unsigned buf_min = 128; + static const unsigned int buf_min = 128; /* for small buffers it's faster not to download an algorithm */ if (wcount * 4 < buf_min) @@ -1056,8 +1056,8 @@ static int stellaris_write_block(struct flash_bank *bank, target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", - target_name(target), (unsigned) buffer_size); + LOG_DEBUG("retry target_alloc_working_area(%s, size=%" PRIu32 ")", + target_name(target), buffer_size); } target_write_buffer(target, write_algorithm->address, diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 0399385..fa57db8 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -120,6 +120,18 @@ * http://www.st.com/resource/en/reference_manual/dm00346336.pdf */ +/* STM32U0xxx series for reference. + * + * RM0503 (STM32U0xx) + * https://www.st.com/resource/en/reference_manual/rm0503-stm32u0-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + */ + +/* STM32U5xxx series for reference. + * + * RM0456 (STM32U5xx) + * http://www.st.com/resource/en/reference_manual/dm00477635.pdf + */ + /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 @@ -272,7 +284,7 @@ struct stm32l4_wrp { }; /* human readable list of families this drivers supports (sorted alphabetically) */ -static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U5/WB/WL"; +static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U0/U5/WB/WL"; static const struct stm32l4_rev stm32l47_l48xx_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } @@ -291,6 +303,10 @@ static const struct stm32l4_rev stm32c03xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32c071xx_revs[] = { + { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32g05_g06xx_revs[] = { { 0x1000, "A" }, }; @@ -319,6 +335,10 @@ static const struct stm32l4_rev stm32g0b_g0cxx_revs[] = { { 0x1000, "A" }, }; +static const struct stm32l4_rev stm32u0xx_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32g43_g44xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; @@ -344,9 +364,21 @@ static const struct stm32l4_rev stm32g49_g4axx_revs[] = { { 0x1000, "A" }, }; +static const struct stm32l4_rev stm32u53_u54xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32u57_u58xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" }, - { 0x2001, "X" }, { 0x3000, "C" }, + { 0x2001, "X" }, { 0x3000, "C" }, { 0x3001, "W" }, { 0x3007, "U" }, +}; + +static const struct stm32l4_rev stm32u59_u5axx_revs[] = { + { 0x3001, "X" }, { 0x3002, "W" }, +}; + +static const struct stm32l4_rev stm32u5f_u5gxx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, }; static const struct stm32l4_rev stm32wba5x_revs[] = { @@ -419,6 +451,30 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { + .id = DEVID_STM32C071XX, + .revs = stm32c071xx_revs, + .num_revs = ARRAY_SIZE(stm32c071xx_revs), + .device_str = "STM32C071xx", + .max_flash_size_kb = 128, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32U53_U54XX, + .revs = stm32u53_u54xx_revs, + .num_revs = ARRAY_SIZE(stm32u53_u54xx_revs), + .device_str = "STM32U535/U545", + .max_flash_size_kb = 512, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { .id = DEVID_STM32G05_G06XX, .revs = stm32g05_g06xx_revs, .num_revs = ARRAY_SIZE(stm32g05_g06xx_revs), @@ -575,6 +631,42 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { + .id = DEVID_STM32U031XX, + .revs = stm32u0xx_revs, + .num_revs = ARRAY_SIZE(stm32u0xx_revs), + .device_str = "STM32U031xx", + .max_flash_size_kb = 64, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF3EA0, + .otp_base = 0x1FFF6800, + .otp_size = 1024, + }, + { + .id = DEVID_STM32U073_U083XX, + .revs = stm32u0xx_revs, + .num_revs = ARRAY_SIZE(stm32u0xx_revs), + .device_str = "STM32U073/U083xx", + .max_flash_size_kb = 256, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF6EA0, + .otp_base = 0x1FFF6800, + .otp_size = 1024, + }, + { + .id = DEVID_STM32U59_U5AXX, + .revs = stm32u59_u5axx_revs, + .num_revs = ARRAY_SIZE(stm32u59_u5axx_revs), + .device_str = "STM32U59/U5Axx", + .max_flash_size_kb = 4096, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { .id = DEVID_STM32U57_U58XX, .revs = stm32u57_u58xx_revs, .num_revs = ARRAY_SIZE(stm32u57_u58xx_revs), @@ -587,6 +679,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 512, }, { + .id = DEVID_STM32U5F_U5GXX, + .revs = stm32u5f_u5gxx_revs, + .num_revs = ARRAY_SIZE(stm32u5f_u5gxx_revs), + .device_str = "STM32U5F/U5Gxx", + .max_flash_size_kb = 4096, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { .id = DEVID_STM32WBA5X, .revs = stm32wba5x_revs, .num_revs = ARRAY_SIZE(stm32wba5x_revs), @@ -679,7 +783,8 @@ struct range { }; static void bitmap_to_ranges(unsigned long *bitmap, unsigned int nbits, - struct range *ranges, unsigned int *ranges_count) { + struct range *ranges, unsigned int *ranges_count) +{ *ranges_count = 0; bool last_bit = 0, cur_bit; for (unsigned int i = 0; i < nbits; i++) { @@ -1916,8 +2021,11 @@ static int stm32l4_probe(struct flash_bank *bank) case DEVID_STM32L43_L44XX: case DEVID_STM32C01XX: case DEVID_STM32C03XX: + case DEVID_STM32C071XX: case DEVID_STM32G05_G06XX: case DEVID_STM32G07_G08XX: + case DEVID_STM32U031XX: + case DEVID_STM32U073_U083XX: case DEVID_STM32L45_L46XX: case DEVID_STM32L41_L42XX: case DEVID_STM32G03_G04XX: @@ -2000,10 +2108,23 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->bank1_sectors = num_pages / 2; } break; + case DEVID_STM32U53_U54XX: case DEVID_STM32U57_U58XX: - /* if flash size is max (2M) the device is always dual bank - * otherwise check DUALBANK + case DEVID_STM32U59_U5AXX: + case DEVID_STM32U5F_U5GXX: + /* according to RM0456 Rev 4, Chapter 7.3.1 and 7.9.13 + * U53x/U54x have 512K max flash size: + * 512K variants are always in DUAL BANK mode + * 256K and 128K variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set + * U57x/U58x have 2M max flash size: + * 2M variants are always in DUAL BANK mode + * 1M variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set + * U59x/U5Ax/U5Fx/U5Gx have 4M max flash size: + * 4M variants are always in DUAL BANK mode + * 2M variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set + * Note: flash banks are always contiguous */ + page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; @@ -2572,7 +2693,7 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .name = "option_write", .handler = stm32l4_handle_option_write_command, .mode = COMMAND_EXEC, - .usage = "bank_id reg_offset value mask", + .usage = "bank_id reg_offset value [mask]", .help = "Write device option bit fields with provided value.", }, { diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 3dc0909..3199d4f 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -89,7 +89,9 @@ #define DEVID_STM32L43_L44XX 0x435 #define DEVID_STM32C01XX 0x443 #define DEVID_STM32C03XX 0x453 +#define DEVID_STM32U53_U54XX 0x455 #define DEVID_STM32G05_G06XX 0x456 +#define DEVID_STM32U031XX 0x459 #define DEVID_STM32G07_G08XX 0x460 #define DEVID_STM32L49_L4AXX 0x461 #define DEVID_STM32L45_L46XX 0x462 @@ -101,9 +103,13 @@ #define DEVID_STM32L4R_L4SXX 0x470 #define DEVID_STM32L4P_L4QXX 0x471 #define DEVID_STM32L55_L56XX 0x472 +#define DEVID_STM32U5F_U5GXX 0x476 #define DEVID_STM32G49_G4AXX 0x479 +#define DEVID_STM32U59_U5AXX 0x481 #define DEVID_STM32U57_U58XX 0x482 +#define DEVID_STM32U073_U083XX 0x489 #define DEVID_STM32WBA5X 0x492 +#define DEVID_STM32C071XX 0x493 #define DEVID_STM32WB1XX 0x494 #define DEVID_STM32WB5XX 0x495 #define DEVID_STM32WB3XX 0x496 diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index a1e1d34..df58f6c 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -1807,7 +1807,7 @@ err: /* Read SFDP parameter block */ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, - uint32_t words, uint32_t *buffer) + unsigned int words, uint32_t *buffer) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; @@ -1848,7 +1848,7 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, } } - LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08" PRIx32 " dummy=%u", + LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08x dummy=%u", __func__, addr, words, *dummy); /* Abort any previous operation */ diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index c39eb3a..eff7df5 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -68,7 +68,7 @@ static int str9xpec_erase_area(struct flash_bank *bank, unsigned int first, static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector); static int str9xpec_write_options(struct flash_bank *bank); -static int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) +static int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, enum tap_state end_state) { if (!tap) return ERROR_TARGET_INVALID; diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 15edd1a..a19b1a6 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -36,7 +36,7 @@ COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index, if (*bank) return ERROR_OK; - unsigned bank_num; + unsigned int bank_num; COMMAND_PARSE_NUMBER(uint, name, bank_num); if (do_probe) { @@ -48,7 +48,7 @@ COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index, } } -COMMAND_HELPER(flash_command_get_bank, unsigned name_index, +COMMAND_HELPER(flash_command_get_bank, unsigned int name_index, struct flash_bank **bank) { return CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, @@ -518,7 +518,7 @@ COMMAND_HANDLER(handle_flash_fill_command) uint64_t pattern; uint32_t count; struct target *target = get_current_target(CMD_CTX); - unsigned i; + unsigned int i; uint32_t wordsize; int retval; @@ -1317,7 +1317,7 @@ COMMAND_HANDLER(handle_flash_banks_command) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned n = 0; + unsigned int n = 0; for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) { command_print(CMD, "#%d : %s (%s) at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", " "buswidth %u, chipwidth %u", p->bank_number, diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index e01d2df..00ee77b 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -16,7 +16,7 @@ * ---------------------------------------------------------------------- */ struct tms470_flash_bank { - unsigned ordinal; + unsigned int ordinal; /* device identification register */ uint32_t device_ident_reg; @@ -239,8 +239,8 @@ static int tms470_read_part_info(struct flash_bank *bank) break; default: - LOG_WARNING("Could not identify part 0x%02x as a member of the TMS470 family.", - (unsigned)part_number); + LOG_WARNING("Could not identify part 0x%02" PRIx32 " as a member of the TMS470 family.", + part_number); return ERROR_FLASH_OPERATION_FAILED; } @@ -391,7 +391,7 @@ static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set) /* only perform the key match when 3VSTAT is clear */ target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (!(fmmstat & 0x08)) { - unsigned i; + unsigned int i; uint32_t fmbptr, fmbac2, orig_fmregopt; target_write_u32(target, 0xFFE8BC04, fmmstat & ~0x07); @@ -455,7 +455,7 @@ static int tms470_unlock_flash(struct flash_bank *bank) { struct target *target = bank->target; const uint32_t *p_key_sets[5]; - unsigned i, key_set_count; + unsigned int i, key_set_count; if (keys_set) { key_set_count = 5; diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index 1d67b09..4011fa4 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -143,28 +143,27 @@ static int isc_enter(struct flash_bank *bank) struct xcf_status status = read_status(bank); - if (true == status.isc_mode) + if (status.isc_mode) return ERROR_OK; - else { - struct scan_field scan; - scan.check_mask = NULL; - scan.check_value = NULL; - scan.num_bits = 16; - scan.out_value = cmd_isc_enable; - scan.in_value = NULL; + struct scan_field scan; - jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); - jtag_execute_queue(); + scan.check_mask = NULL; + scan.check_value = NULL; + scan.num_bits = 16; + scan.out_value = cmd_isc_enable; + scan.in_value = NULL; - status = read_status(bank); - if (!status.isc_mode) { - LOG_ERROR("*** XCF: FAILED to enter ISC mode"); - return ERROR_FLASH_OPERATION_FAILED; - } + jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); + jtag_execute_queue(); - return ERROR_OK; + status = read_status(bank); + if (!status.isc_mode) { + LOG_ERROR("*** XCF: FAILED to enter ISC mode"); + return ERROR_FLASH_OPERATION_FAILED; } + + return ERROR_OK; } static int isc_leave(struct flash_bank *bank) @@ -174,27 +173,26 @@ static int isc_leave(struct flash_bank *bank) if (!status.isc_mode) return ERROR_OK; - else { - struct scan_field scan; - - scan.check_mask = NULL; - scan.check_value = NULL; - scan.num_bits = 16; - scan.out_value = cmd_isc_disable; - scan.in_value = NULL; - - jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); - jtag_execute_queue(); - alive_sleep(1); /* device needs 50 uS to leave ISC mode */ - - status = read_status(bank); - if (status.isc_mode) { - LOG_ERROR("*** XCF: FAILED to leave ISC mode"); - return ERROR_FLASH_OPERATION_FAILED; - } - return ERROR_OK; + struct scan_field scan; + + scan.check_mask = NULL; + scan.check_value = NULL; + scan.num_bits = 16; + scan.out_value = cmd_isc_disable; + scan.in_value = NULL; + + jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); + jtag_execute_queue(); + alive_sleep(1); /* device needs 50 uS to leave ISC mode */ + + status = read_status(bank); + if (status.isc_mode) { + LOG_ERROR("*** XCF: FAILED to leave ISC mode"); + return ERROR_FLASH_OPERATION_FAILED; } + + return ERROR_OK; } static int sector_state(uint8_t wrpt, int sector) diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c index 6e30fc1..4aa97a9 100644 --- a/src/flash/nor/xmc1xxx.c +++ b/src/flash/nor/xmc1xxx.c @@ -84,7 +84,7 @@ static int xmc1xxx_erase(struct flash_bank *bank, unsigned int first, struct working_area *workarea; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_algo; - unsigned i; + unsigned int i; int retval; const uint8_t erase_code[] = { #include "../../../contrib/loaders/flash/xmc1xxx/erase.inc" @@ -159,7 +159,7 @@ static int xmc1xxx_erase_check(struct flash_bank *bank) struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_algo; uint16_t val; - unsigned i; + unsigned int i; int retval; const uint8_t erase_check_code[] = { #include "../../../contrib/loaders/flash/xmc1xxx/erase_check.inc" @@ -245,7 +245,7 @@ static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer, struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_algo; uint32_t block_count = DIV_ROUND_UP(byte_count, NVM_BLOCK_SIZE); - unsigned i; + unsigned int i; int retval; const uint8_t write_code[] = { #include "../../../contrib/loaders/flash/xmc1xxx/write.inc" diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 654f201..0dd84ef 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -5,7 +5,7 @@ # # program utility proc # usage: program filename -# optional args: verify, reset, exit and address +# optional args: preverify, verify, reset, exit and address # lappend _telnet_autocomplete_skip program_error @@ -101,8 +101,8 @@ proc program {filename args} { return } -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\] \[pre-verify\] \[verify\] \[reset\] \[exit\]" +add_help_text program "write an image to flash, address is only required for binary images. preverify, verify, reset, exit are optional" +add_usage_text program "<filename> \[address\] \[preverify\] \[verify\] \[reset\] \[exit\]" # stm32[f0x|f3x] uses the same flash driver as the stm32f1x proc stm32f0x args { eval stm32f1x $args } |