X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fkinetis.c;h=07c5eac36850fe025a36df366e4bc6603a1c0288;hb=fd9a7a8c8ab2431a2bc69ab515d868cdf5178761;hp=cc86f971a4ee4c36a70b4bb1c8a9724685fb3cf5;hpb=8dcb91fb83e59d475af9da377066021ae2e03969;p=openocd.git diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index cc86f971a4..07c5eac368 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -287,6 +287,7 @@ struct kinetis_chip { FS_NO_CMD_BLOCKSTAT = 0x40, FS_WIDTH_256BIT = 0x80, + FS_ECC = 0x100, } flash_support; enum { @@ -391,7 +392,7 @@ static uint8_t fcf_fopt = 0xff; static bool create_banks; -struct flash_driver kinetis_flash; +const struct flash_driver kinetis_flash; static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); static int kinetis_probe_chip(struct kinetis_chip *k_chip); @@ -785,9 +786,8 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) { uint32_t stats[32]; - int i; - for (i = 0; i < 32; i++) { + for (unsigned int i = 0; i < 32; i++) { stats[i] = MDM_STAT_FREADY; dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]); } @@ -796,7 +796,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) LOG_DEBUG("MDM: dap_run failed when validating secured state"); return ERROR_OK; } - for (i = 0; i < 32; i++) { + for (unsigned int i = 0; i < 32; i++) { if (stats[i] & MDM_STAT_SYSSEC) secured_score++; if (!(stats[i] & MDM_STAT_FREADY)) @@ -858,8 +858,7 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target) static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[]) { - int i; - for (i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-sim-base") == 0) { if (i + 1 < argc) k_chip->sim_base = strtoul(argv[++i], NULL, 0); @@ -913,13 +912,28 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) } +static void kinetis_free_driver_priv(struct flash_bank *bank) +{ + struct kinetis_flash_bank *k_bank = bank->driver_priv; + if (k_bank == NULL) + return; + + struct kinetis_chip *k_chip = k_bank->k_chip; + if (k_chip == NULL) + return; + + k_chip->num_banks--; + if (k_chip->num_banks == 0) + free(k_chip); +} + + static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) { - unsigned bank_idx; unsigned num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; - char base_name[80], name[80], num[4]; + char base_name[69], name[80], num[4]; char *class, *p; num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; @@ -930,25 +944,27 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) bank = k_chip->banks[0].bank; if (bank && bank->name) { - strncpy(base_name, bank->name, sizeof(base_name)); + strncpy(base_name, bank->name, sizeof(base_name) - 1); + base_name[sizeof(base_name) - 1] = '\0'; p = strstr(base_name, ".pflash"); if (p) { *p = '\0'; if (k_chip->num_pflash_blocks > 1) { /* rename first bank if numbering is needed */ snprintf(name, sizeof(name), "%s.pflash0", base_name); - free((void *)bank->name); + free(bank->name); bank->name = strdup(name); } } } else { - strncpy(base_name, target_name(k_chip->target), sizeof(base_name)); + strncpy(base_name, target_name(k_chip->target), sizeof(base_name) - 1); + base_name[sizeof(base_name) - 1] = '\0'; p = strstr(base_name, ".cpu"); if (p) *p = '\0'; } - for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) { + for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank = k_bank->bank; @@ -1015,7 +1031,7 @@ static int kinetis_disable_wdog_algo(struct target *target, size_t code_size, co armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - init_reg_param(®_params[0], "r0", 32, PARAM_IN); + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, wdog_base); retval = target_run_algorithm(target, 0, NULL, 1, reg_params, @@ -1199,11 +1215,11 @@ static int kinetis_ftfx_clear_error(struct target *target) static int kinetis_ftfx_prepare(struct target *target) { - int result, i; + int result; uint8_t fstat; /* wait until busy */ - for (i = 0; i < 50; i++) { + for (unsigned int i = 0; i < 50; i++) { result = target_read_u8(target, FTFx_FSTAT, &fstat); if (result != ERROR_OK) return result; @@ -1233,7 +1249,7 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t wcount) { struct target *target = bank->target; - uint32_t buffer_size = 2048; /* Default minimum value */ + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; struct kinetis_flash_bank *k_bank = bank->driver_priv; @@ -1244,10 +1260,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, int retval; uint8_t fstat; - /* Increase buffer_size if needed */ - if (buffer_size < (target->working_area_size/2)) - buffer_size = (target->working_area_size/2); - /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(kinetis_flash_write_code), &write_algorithm) != ERROR_OK) { @@ -1260,16 +1272,19 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; - /* memory buffer */ - while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 4; - if (buffer_size <= 256) { - /* free working area, write algorithm already allocated */ - target_free_working_area(target, write_algorithm); + /* memory buffer, size *must* be multiple of word */ + buffer_size = target_get_working_area_avail(target) & ~(sizeof(uint32_t) - 1); + if (buffer_size < 256) { + LOG_WARNING("large enough working area not available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } else if (buffer_size > 16384) { + /* probably won't benefit from more than 16k ... */ + buffer_size = 16384; + } - LOG_WARNING("No large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + if (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; @@ -1321,10 +1336,9 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } -static int kinetis_protect(struct flash_bank *bank, int set, int first, int last) +static int kinetis_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) { - int i; - if (allow_fcf_writes) { LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!"); return ERROR_FAIL; @@ -1335,7 +1349,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last return ERROR_FLASH_BANK_INVALID; } - for (i = first; i < bank->num_prot_blocks && i <= last; i++) + for (unsigned int i = first; i < bank->num_prot_blocks && i <= last; i++) bank->prot_blocks[i].is_protected = set; LOG_INFO("Protection bits will be written at the next FCF sector erase or write."); @@ -1349,7 +1363,7 @@ static int kinetis_protect_check(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; int result; - int i, b; + int b; uint32_t fprot; if (k_bank->flash_class == FC_PFLASH) { @@ -1377,7 +1391,7 @@ static int kinetis_protect_check(struct flash_bank *bank) } b = k_bank->protection_block; - for (i = 0; i < bank->num_prot_blocks; i++) { + for (unsigned int i = 0; i < bank->num_prot_blocks; i++) { if ((fprot >> b) & 1) bank->prot_blocks[i].is_protected = 0; else @@ -1395,8 +1409,6 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) uint32_t fprot = 0xffffffff; uint8_t fsec = 0xfe; /* set MCU unsecure */ uint8_t fdprot = 0xff; - int i; - unsigned bank_idx; unsigned num_blocks; uint32_t pflash_bit; uint8_t dflash_bit; @@ -1412,7 +1424,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) /* iterate over all kinetis banks */ /* current bank is bank 0, it contains FCF */ num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; - for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) { + for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank_iter = k_bank->bank; @@ -1423,8 +1435,10 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) kinetis_auto_probe(bank_iter); + assert(bank_iter->prot_blocks); + if (k_bank->flash_class == FC_PFLASH) { - for (i = 0; i < bank_iter->num_prot_blocks; i++) { + for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fprot &= ~pflash_bit; @@ -1432,7 +1446,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) } } else if (k_bank->flash_class == FC_FLEX_NVM) { - for (i = 0; i < bank_iter->num_prot_blocks; i++) { + for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fdprot &= ~dflash_bit; @@ -1520,7 +1534,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) static int kinetis_check_run_mode(struct kinetis_chip *k_chip) { - int result, i; + int result; uint8_t pmstat; struct target *target; @@ -1558,7 +1572,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip) if (result != ERROR_OK) return result; - for (i = 100; i; i--) { + for (unsigned int i = 100; i > 0; i--) { result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; @@ -1601,9 +1615,10 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip) } -static int kinetis_erase(struct flash_bank *bank, int first, int last) +static int kinetis_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) { - int result, i; + int result; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; @@ -1624,18 +1639,16 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) * requested erase is PFlash or NVM and encompasses the entire * block. Should be quicker. */ - for (i = first; i <= last; i++) { + for (unsigned int i = first; i <= last; i++) { /* set command and sector address */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) { - LOG_WARNING("erase sector %d failed", i); + LOG_WARNING("erase sector %u failed", i); return ERROR_FLASH_OPERATION_FAILED; } - bank->sectors[i].is_erased = 1; - if (k_bank->prog_base == 0 && bank->sectors[i].offset <= FCF_ADDRESS && bank->sectors[i].offset + bank->sectors[i].size > FCF_ADDRESS + FCF_SIZE) { @@ -1649,7 +1662,8 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) result = kinetis_write_inner(bank, fcf_buffer, FCF_ADDRESS, FCF_SIZE); if (result != ERROR_OK) LOG_WARNING("Flash Configuration Field write failed"); - bank->sectors[i].is_erased = 0; + else + LOG_DEBUG("Generated FCF written"); } } } @@ -1735,13 +1749,15 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer result = target_write_memory(bank->target, k_chip->progr_accel_ram, 4, size_aligned / 4, buffer_aligned); - LOG_DEBUG("section @ %08" PRIx32 " aligned begin %" PRIu32 ", end %" PRIu32, + LOG_DEBUG("section @ " TARGET_ADDR_FMT " aligned begin %" PRIu32 + ", end %" PRIu32, bank->base + offset, align_begin, align_end); } else result = target_write_memory(bank->target, k_chip->progr_accel_ram, 4, size_aligned / 4, buffer); - LOG_DEBUG("write section @ %08" PRIx32 " with length %" PRIu32 " bytes", + LOG_DEBUG("write section @ " TARGET_ADDR_FMT " with length %" PRIu32 + " bytes", bank->base + offset, size); if (result != ERROR_OK) { @@ -1756,12 +1772,14 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) { - LOG_ERROR("Error writing section at %08" PRIx32, bank->base + offset); + LOG_ERROR("Error writing section at " TARGET_ADDR_FMT, + bank->base + offset); break; } if (ftfx_fstat & 0x01) { - LOG_ERROR("Flash write error at %08" PRIx32, bank->base + offset); + LOG_ERROR("Flash write error at " TARGET_ADDR_FMT, + bank->base + offset); if (k_bank->prog_base == 0 && offset == FCF_ADDRESS + FCF_SIZE && (k_chip->flash_support & FS_WIDTH_256BIT)) { LOG_ERROR("Flash write immediately after the end of Flash Config Field shows error"); @@ -1774,6 +1792,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer buffer += size; offset += size; count -= size; + + keep_alive(); } free(buffer_aligned); @@ -1784,25 +1804,26 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - int result, fallback = 0; + int result; + bool fallback = false; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) { /* fallback to longword write */ - fallback = 1; + fallback = true; LOG_INFO("This device supports Program Longword execution only."); } else { result = kinetis_make_ram_ready(bank->target); if (result != ERROR_OK) { - fallback = 1; + fallback = true; LOG_WARNING("FlexRAM not ready, fallback to slow longword write."); } } - LOG_DEBUG("flash write @ %08" PRIx32, bank->base + offset); + LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset); - if (fallback == 0) { + if (!fallback) { /* program section command */ kinetis_write_sections(bank, buffer, offset, count); } else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) { @@ -1853,16 +1874,20 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) { - LOG_ERROR("Error writing longword at %08" PRIx32, bank->base + offset); + LOG_ERROR("Error writing longword at " TARGET_ADDR_FMT, + bank->base + offset); break; } if (ftfx_fstat & 0x01) - LOG_ERROR("Flash write error at %08" PRIx32, bank->base + offset); + LOG_ERROR("Flash write error at " TARGET_ADDR_FMT, + bank->base + offset); buffer += 4; offset += 4; words_remaining--; + + keep_alive(); } } free(new_buffer); @@ -1881,9 +1906,14 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, { int result; bool set_fcf = false; + bool fcf_in_data_valid = false; + bool fcf_differs = false; int sect = 0; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; + uint8_t fcf_buffer[FCF_SIZE]; + uint8_t fcf_current[FCF_SIZE]; + uint8_t fcf_in_data[FCF_SIZE]; result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) @@ -1904,11 +1934,55 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, } if (set_fcf) { - uint8_t fcf_buffer[FCF_SIZE]; - uint8_t fcf_current[FCF_SIZE]; - kinetis_fill_fcf(bank, fcf_buffer); + fcf_in_data_valid = offset <= FCF_ADDRESS + && offset + count >= FCF_ADDRESS + FCF_SIZE; + if (fcf_in_data_valid) { + memcpy(fcf_in_data, buffer + FCF_ADDRESS - offset, FCF_SIZE); + if (memcmp(fcf_in_data, fcf_buffer, 8)) { + fcf_differs = true; + LOG_INFO("Setting of backdoor key is not supported in mode 'kinetis fcf_source protection'."); + } + if (memcmp(fcf_in_data + FCF_FPROT, fcf_buffer + FCF_FPROT, 4)) { + fcf_differs = true; + LOG_INFO("Flash protection requested in the programmed file differs from current setting."); + } + if (fcf_in_data[FCF_FDPROT] != fcf_buffer[FCF_FDPROT]) { + fcf_differs = true; + LOG_INFO("Data flash protection requested in the programmed file differs from current setting."); + } + if ((fcf_in_data[FCF_FSEC] & 3) != 2) { + fcf_in_data_valid = false; + LOG_INFO("Device security requested in the programmed file! Write denied."); + } else if (fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) { + fcf_differs = true; + LOG_INFO("Strange unsecure mode 0x%02" PRIx8 + " requested in the programmed file, set FSEC = 0x%02" PRIx8 + " in the startup code!", + fcf_in_data[FCF_FSEC], fcf_buffer[FCF_FSEC]); + } + if (fcf_in_data[FCF_FOPT] != fcf_buffer[FCF_FOPT]) { + fcf_differs = true; + LOG_INFO("FOPT requested in the programmed file differs from current setting, set 'kinetis fopt 0x%02" + PRIx8 "'.", fcf_in_data[FCF_FOPT]); + } + + /* If the device has ECC flash, then we cannot re-program FCF */ + if (fcf_differs) { + if (k_chip->flash_support & FS_ECC) { + fcf_in_data_valid = false; + LOG_INFO("Cannot re-program FCF. Expect verify errors at FCF (0x400-0x40f)."); + } else { + LOG_INFO("Trying to re-program FCF."); + if (!(k_chip->flash_support & FS_PROGRAM_LONGWORD)) + LOG_INFO("Flash re-programming may fail on this device!"); + } + } + } + } + + if (set_fcf && !fcf_in_data_valid) { if (offset < FCF_ADDRESS) { /* write part preceding FCF */ result = kinetis_write_inner(bank, buffer, offset, FCF_ADDRESS - offset); @@ -1937,9 +2011,10 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, } return result; - } else + } else { /* no FCF fiddling, normal write */ return kinetis_write_inner(bank, buffer, offset, count); + } } @@ -1957,9 +2032,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned familyid = 0, subfamid = 0; unsigned cpu_mhz = 120; - unsigned idx; bool use_nvm_marking = false; - char flash_marking[8], nvm_marking[2]; + char flash_marking[12], nvm_marking[2]; char name[40]; k_chip->probed = false; @@ -2052,7 +2126,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) LOG_ERROR("Unsupported K-family FAMID"); } - for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { + for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { if (kinetis_types_old[idx].sdid == mcu_type) { strcpy(name, kinetis_types_old[idx].name); use_nvm_marking = true; @@ -2126,6 +2200,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX1: /* errata 7534 - should be K63 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ subfamid += 2; /* errata 7534 fix */ + /* fallthrough */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: /* K63FN1M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX4: @@ -2145,10 +2220,21 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) k_chip->nvm_sector_size = 4<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 4; - k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC; cpu_mhz = 180; break; + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX7: + /* K27FN2M0 */ + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8: + /* K28FN2M0 */ + k_chip->pflash_sector_size = 4<<10; + k_chip->max_flash_prog_size = 1<<10; + num_blocks = 4; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC; + cpu_mhz = 150; + break; + case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2: @@ -2210,6 +2296,45 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) familyid, subfamid, cpu_mhz / 10); break; + case KINETIS_SDID_SERIESID_KW: + /* Newer KW-series (all KW series except KW2xD, KW01Z) */ + cpu_mhz = 48; + switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { + case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX0: + /* KW40Z */ + case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX0: + /* KW30Z */ + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX0: + /* KW20Z */ + /* FTFA, 1kB sectors */ + k_chip->pflash_sector_size = 1<<10; + k_chip->nvm_sector_size = 1<<10; + /* autodetect 1 or 2 blocks */ + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + k_chip->watchdog_type = KINETIS_WDOG_COP; + break; + case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX1: + /* KW41Z */ + case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX1: + /* KW31Z */ + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX1: + /* KW21Z */ + /* FTFA, 2kB sectors */ + k_chip->pflash_sector_size = 2<<10; + k_chip->nvm_sector_size = 2<<10; + /* autodetect 1 or 2 blocks */ + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + k_chip->watchdog_type = KINETIS_WDOG_COP; + break; + default: + LOG_ERROR("Unsupported KW FAMILYID SUBFAMID"); + } + snprintf(name, sizeof(name), "MKW%u%uZ%%s%u", + familyid, subfamid, cpu_mhz / 10); + break; + case KINETIS_SDID_SERIESID_KV: /* KV-series */ k_chip->watchdog_type = KINETIS_WDOG_K; @@ -2260,7 +2385,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) k_chip->max_flash_prog_size = 1<<10; num_blocks = 1; maxaddr_shift = 14; - k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT | FS_ECC; k_chip->pflash_base = 0x10000000; k_chip->progr_accel_ram = 0x18000000; cpu_mhz = 240; @@ -2348,7 +2473,9 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) if (num_blocks == 0) num_blocks = k_chip->fcfg2_maxaddr1_shifted ? 2 : 1; - else if (k_chip->fcfg2_maxaddr1_shifted == 0 && num_blocks >= 2) { + else if (k_chip->fcfg2_maxaddr1_shifted == 0 && num_blocks >= 2 && fcfg2_pflsh) { + /* fcfg2_maxaddr1 may be zero due to partitioning whole NVM as EEPROM backup + * Do not adjust block count in this case! */ num_blocks = 1; LOG_WARNING("MAXADDR1 is zero, number of flash banks adjusted to 1"); } else if (k_chip->fcfg2_maxaddr1_shifted != 0 && num_blocks == 1) { @@ -2405,6 +2532,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) case 0x06: k_chip->dflash_size = k_chip->nvm_size - (4096 << fcfg1_depart); break; + case 0x07: case 0x08: k_chip->dflash_size = 0; break; @@ -2422,6 +2550,10 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) } switch (fcfg1_pfsize) { + case 0x00: + k_chip->pflash_size = 8192; + break; + case 0x01: case 0x03: case 0x05: case 0x07: @@ -2432,6 +2564,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) break; case 0x0f: /* a peculiar case: Freescale states different sizes for 0xf + * KL03P24M48SF0RM 32 KB .... duplicate of code 0x3 * K02P64M100SFARM 128 KB ... duplicate of code 0x7 * K22P121M120SF8RM 256 KB ... duplicate of code 0x9 * K22P121M120SF7RM 512 KB ... duplicate of code 0xb @@ -2458,8 +2591,13 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) /* Program section size is equal to sector size by default */ } - k_chip->num_pflash_blocks = num_blocks / (2 - fcfg2_pflsh); - k_chip->num_nvm_blocks = num_blocks - k_chip->num_pflash_blocks; + if (fcfg2_pflsh) { + k_chip->num_pflash_blocks = num_blocks; + k_chip->num_nvm_blocks = 0; + } else { + k_chip->num_pflash_blocks = (num_blocks + 1) / 2; + k_chip->num_nvm_blocks = num_blocks - k_chip->num_pflash_blocks; + } if (use_nvm_marking) { nvm_marking[0] = k_chip->num_nvm_blocks ? 'X' : 'N'; @@ -2494,12 +2632,15 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) static int kinetis_probe(struct flash_bank *bank) { - int result, i; + int result; uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; unsigned num_blocks, first_nvm_bank; uint32_t size_k; struct kinetis_flash_bank *k_bank = bank->driver_priv; - struct kinetis_chip *k_chip = k_bank->k_chip; + struct kinetis_chip *k_chip; + + assert(k_bank); + k_chip = k_bank->k_chip; k_bank->probed = false; @@ -2523,7 +2664,7 @@ static int kinetis_probe(struct flash_bank *bank) * parts with more than 32K of PFlash. For parts with * less the protection unit is set to 1024 bytes */ k_bank->protection_size = MAX(k_chip->pflash_size / 32, 1024); - bank->num_prot_blocks = 32 / k_chip->num_pflash_blocks; + bank->num_prot_blocks = bank->size / k_bank->protection_size; k_bank->protection_block = bank->num_prot_blocks * k_bank->bank_number; size_k = bank->size / 1024; @@ -2543,6 +2684,7 @@ static int kinetis_probe(struct flash_bank *bank) if (k_chip->dflash_size == 0) { k_bank->protection_size = 0; } else { + int i; for (i = k_chip->dflash_size; ~i & 1; i >>= 1) ; if (i == 1) @@ -2561,7 +2703,7 @@ static int kinetis_probe(struct flash_bank *bank) if (bank->size > limit) { bank->size = limit; - LOG_DEBUG("FlexNVM bank %d limited to 0x%08" PRIx32 " due to active EEPROM backup", + LOG_DEBUG("FlexNVM bank %u limited to 0x%08" PRIx32 " due to active EEPROM backup", k_bank->bank_number, limit); } @@ -2570,7 +2712,7 @@ static int kinetis_probe(struct flash_bank *bank) k_bank->bank_number, size_k, k_bank->prog_base, k_bank->sector_size); } else { - LOG_ERROR("Cannot determine parameters for bank %d, only %d banks on device", + LOG_ERROR("Cannot determine parameters for bank %u, only %u banks on device", k_bank->bank_number, num_blocks); return ERROR_FLASH_BANK_INVALID; } @@ -2604,7 +2746,7 @@ static int kinetis_probe(struct flash_bank *bank) } if (k_bank->sector_size == 0) { - LOG_ERROR("Unknown sector size for bank %d", bank->bank_number); + LOG_ERROR("Unknown sector size for bank %u", bank->bank_number); return ERROR_FLASH_BANK_INVALID; } @@ -2650,7 +2792,7 @@ static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size) uint32_t size_k = bank->size / 1024; snprintf(buf, buf_size, - "%s %s: %" PRIu32 "k %s bank %s at 0x%08" PRIx32, + "%s %s: %" PRIu32 "k %s bank %s at " TARGET_ADDR_FMT, bank->driver->name, k_chip->name, size_k, bank_class_names[k_bank->flash_class], bank->name, bank->base); @@ -2699,8 +2841,7 @@ static int kinetis_blank_check(struct flash_bank *bank) if (block_dirty) { /* the whole bank is not erased, check sector-by-sector */ - int i; - for (i = 0; i < bank->num_sectors; i++) { + for (unsigned int i = 0; i < bank->num_sectors; i++) { /* normal margin */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT, k_bank->prog_base + bank->sectors[i].offset, @@ -2716,8 +2857,7 @@ static int kinetis_blank_check(struct flash_bank *bank) } } else { /* the whole bank is erased, update all sectors */ - int i; - for (i = 0; i < bank->num_sectors; i++) + for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; } } else { @@ -2770,7 +2910,7 @@ COMMAND_HANDLER(kinetis_nvm_partition) flex_nvm_partition_code = (uint8_t)((sim_fcfg1 >> 8) & 0x0f); switch (flex_nvm_partition_code) { case 0: - command_print(CMD_CTX, "No EEPROM backup, data flash only"); + command_print(CMD, "No EEPROM backup, data flash only"); break; case 1: case 2: @@ -2778,10 +2918,10 @@ COMMAND_HANDLER(kinetis_nvm_partition) case 4: case 5: case 6: - command_print(CMD_CTX, "EEPROM backup %d KB", 4 << flex_nvm_partition_code); + command_print(CMD, "EEPROM backup %d KB", 4 << flex_nvm_partition_code); break; case 8: - command_print(CMD_CTX, "No data flash, EEPROM backup only"); + command_print(CMD, "No data flash, EEPROM backup only"); break; case 0x9: case 0xA: @@ -2789,13 +2929,13 @@ COMMAND_HANDLER(kinetis_nvm_partition) case 0xC: case 0xD: case 0xE: - command_print(CMD_CTX, "data flash %d KB", 4 << (flex_nvm_partition_code & 7)); + command_print(CMD, "data flash %d KB", 4 << (flex_nvm_partition_code & 7)); break; case 0xf: - command_print(CMD_CTX, "No EEPROM backup, data flash only (DEPART not set)"); + command_print(CMD, "No EEPROM backup, data flash only (DEPART not set)"); break; default: - command_print(CMD_CTX, "Unsupported EEPROM backup size code 0x%02" PRIx8, flex_nvm_partition_code); + command_print(CMD, "Unsupported EEPROM backup size code 0x%02" PRIx8, flex_nvm_partition_code); } return ERROR_OK; @@ -2861,7 +3001,7 @@ COMMAND_HANDLER(kinetis_nvm_partition) if (result != ERROR_OK) return result; - command_print(CMD_CTX, "FlexNVM partition set. Please reset MCU."); + command_print(CMD, "FlexNVM partition set. Please reset MCU."); if (k_chip) { first_nvm_bank = k_chip->num_pflash_blocks; @@ -2871,7 +3011,7 @@ COMMAND_HANDLER(kinetis_nvm_partition) k_chip->probed = false; } - command_print(CMD_CTX, "FlexNVM banks will be re-probed to set new data flash size."); + command_print(CMD, "FlexNVM banks will be re-probed to set new data flash size."); return ERROR_OK; } @@ -2890,12 +3030,12 @@ COMMAND_HANDLER(kinetis_fcf_source_handler) } if (allow_fcf_writes) { - command_print(CMD_CTX, "Arbitrary Flash Configuration Field writes enabled."); - command_print(CMD_CTX, "Protection info writes to FCF disabled."); + command_print(CMD, "Arbitrary Flash Configuration Field writes enabled."); + command_print(CMD, "Protection info writes to FCF disabled."); LOG_WARNING("BEWARE: incorrect flash configuration may permanently lock the device."); } else { - command_print(CMD_CTX, "Protection info writes to Flash Configuration Field enabled."); - command_print(CMD_CTX, "Arbitrary FCF writes disabled. Mode safe from unwanted locking of the device."); + command_print(CMD, "Protection info writes to Flash Configuration Field enabled."); + command_print(CMD, "Arbitrary FCF writes disabled. Mode safe from unwanted locking of the device."); } return ERROR_OK; @@ -2906,10 +3046,11 @@ COMMAND_HANDLER(kinetis_fopt_handler) if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC == 1) + if (CMD_ARGC == 1) { fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0); - else - command_print(CMD_CTX, "FCF_FOPT 0x%02" PRIx8, fcf_fopt); + } else { + command_print(CMD, "FCF_FOPT 0x%02" PRIx8, fcf_fopt); + } return ERROR_OK; } @@ -2947,7 +3088,8 @@ static const struct command_registration kinetis_security_command_handlers[] = { .usage = "", .handler = kinetis_mdm_mass_erase, }, - { .name = "reset", + { + .name = "reset", .mode = COMMAND_EXEC, .help = "Issue a reset via the MDM-AP", .usage = "", @@ -2999,6 +3141,7 @@ static const struct command_registration kinetis_exec_command_handlers[] = { .mode = COMMAND_CONFIG, .help = "Driver creates additional banks if device with two/four flash blocks is probed", .handler = kinetis_create_banks_handler, + .usage = "", }, COMMAND_REGISTRATION_DONE }; @@ -3016,7 +3159,7 @@ static const struct command_registration kinetis_command_handler[] = { -struct flash_driver kinetis_flash = { +const struct flash_driver kinetis_flash = { .name = "kinetis", .commands = kinetis_command_handler, .flash_bank_command = kinetis_flash_bank_command, @@ -3029,4 +3172,5 @@ struct flash_driver kinetis_flash = { .erase_check = kinetis_blank_check, .protect_check = kinetis_protect_check, .info = kinetis_info, + .free_driver_priv = kinetis_free_driver_priv, };