X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fkinetis.c;h=396fe42a9c8f3c709993ed7e72cd8869329f3082;hb=03f46e368830c7293f83186658268a6cd4557b20;hp=5e192c067c90f25076e8d327541051e21d5a9933;hpb=1ab86419d72dd90dbbde028263582346fa1e9dd1;p=openocd.git diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 5e192c067c..396fe42a9c 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -31,10 +31,12 @@ #include "config.h" #endif +#include "jtag/interface.h" #include "imp.h" #include #include #include +#include /* * Implementation Notes @@ -86,7 +88,7 @@ * */ -const struct { +static const struct { unsigned pflash_sector_size_bytes; unsigned nvm_sector_size_bytes; unsigned num_blocks; @@ -149,19 +151,30 @@ const struct { * Therefore we combine it with the DIEID bits which may possibly * break if Freescale bumps the DIEID for a particular MCU. */ #define KINETIS_K_SDID_TYPE_MASK 0x00000FF0 -#define KINETIS_K_SDID_K10 0x00000000 -#define KINETIS_K_SDID_K11 0x00000220 -#define KINETIS_K_SDID_K12 0x00000200 -#define KINETIS_K_SDID_K20 0x00000290 -#define KINETIS_K_SDID_K21 0x00000230 -#define KINETIS_K_SDID_K22 0x00000210 -#define KINETIS_K_SDID_K30 0x00000120 -#define KINETIS_K_SDID_K40 0x00000130 -#define KINETIS_K_SDID_K50 0x000000E0 -#define KINETIS_K_SDID_K51 0x000000F0 -#define KINETIS_K_SDID_K53 0x00000170 -#define KINETIS_K_SDID_K60 0x000001C0 -#define KINETIS_K_SDID_K70 0x000001D0 +#define KINETIS_K_SDID_K10_M50 0x00000000 +#define KINETIS_K_SDID_K10_M72 0x00000080 +#define KINETIS_K_SDID_K10_M100 0x00000100 +#define KINETIS_K_SDID_K10_M120 0x00000180 +#define KINETIS_K_SDID_K11 0x00000220 +#define KINETIS_K_SDID_K12 0x00000200 +#define KINETIS_K_SDID_K20_M50 0x00000010 +#define KINETIS_K_SDID_K20_M72 0x00000090 +#define KINETIS_K_SDID_K20_M100 0x00000110 +#define KINETIS_K_SDID_K20_M120 0x00000190 +#define KINETIS_K_SDID_K21_M50 0x00000230 +#define KINETIS_K_SDID_K21_M120 0x00000330 +#define KINETIS_K_SDID_K22_M50 0x00000210 +#define KINETIS_K_SDID_K22_M120 0x00000310 +#define KINETIS_K_SDID_K30_M72 0x000000A0 +#define KINETIS_K_SDID_K30_M100 0x00000120 +#define KINETIS_K_SDID_K40_M72 0x000000B0 +#define KINETIS_K_SDID_K40_M100 0x00000130 +#define KINETIS_K_SDID_K50_M72 0x000000E0 +#define KINETIS_K_SDID_K51_M72 0x000000F0 +#define KINETIS_K_SDID_K53 0x00000170 +#define KINETIS_K_SDID_K60_M100 0x00000140 +#define KINETIS_K_SDID_K60_M150 0x000001C0 +#define KINETIS_K_SDID_K70_M150 0x000001D0 #define KINETIS_KL_SDID_SERIESID_MASK 0x00F00000 #define KINETIS_KL_SDID_SERIESID_KL 0x00100000 @@ -185,6 +198,289 @@ struct kinetis_flash_bank { } flash_class; }; + + +#define MDM_REG_STAT 0x00 +#define MDM_REG_CTRL 0x04 +#define MDM_REG_ID 0xfc + +#define MDM_STAT_FMEACK (1<<0) +#define MDM_STAT_FREADY (1<<1) +#define MDM_STAT_SYSSEC (1<<2) +#define MDM_STAT_SYSRES (1<<3) +#define MDM_STAT_FMEEN (1<<5) +#define MDM_STAT_BACKDOOREN (1<<6) +#define MDM_STAT_LPEN (1<<7) +#define MDM_STAT_VLPEN (1<<8) +#define MDM_STAT_LLSMODEXIT (1<<9) +#define MDM_STAT_VLLSXMODEXIT (1<<10) +#define MDM_STAT_CORE_HALTED (1<<16) +#define MDM_STAT_CORE_SLEEPDEEP (1<<17) +#define MDM_STAT_CORESLEEPING (1<<18) + +#define MEM_CTRL_FMEIP (1<<0) +#define MEM_CTRL_DBG_DIS (1<<1) +#define MEM_CTRL_DBG_REQ (1<<2) +#define MEM_CTRL_SYS_RES_REQ (1<<3) +#define MEM_CTRL_CORE_HOLD_RES (1<<4) +#define MEM_CTRL_VLLSX_DBG_REQ (1<<5) +#define MEM_CTRL_VLLSX_DBG_ACK (1<<6) +#define MEM_CTRL_VLLSX_STAT_ACK (1<<7) + +#define MDM_ACCESS_TIMEOUT 3000 /* iterations */ + +static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) +{ + int retval; + LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); + + retval = dap_queue_ap_write(dap, reg, value); + if (retval != ERROR_OK) { + LOG_DEBUG("MDM: failed to queue a write request"); + return retval; + } + + retval = dap_run(dap); + if (retval != ERROR_OK) { + LOG_DEBUG("MDM: dap_run failed"); + return retval; + } + + + return ERROR_OK; +} + +static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) +{ + int retval; + retval = dap_queue_ap_read(dap, reg, result); + if (retval != ERROR_OK) { + LOG_DEBUG("MDM: failed to queue a read request"); + return retval; + } + + retval = dap_run(dap); + if (retval != ERROR_OK) { + LOG_DEBUG("MDM: dap_run failed"); + return retval; + } + + LOG_DEBUG("MDM_REG[0x%02x]: %08" PRIX32, reg, *result); + return ERROR_OK; +} + +static int kinetis_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value) +{ + uint32_t val; + int retval; + int timeout = MDM_ACCESS_TIMEOUT; + + do { + retval = kinetis_mdm_read_register(dap, reg, &val); + if (retval != ERROR_OK || (val & mask) == value) + return retval; + + alive_sleep(1); + } while (timeout--); + + LOG_DEBUG("MDM: polling timed out"); + return ERROR_FAIL; +} + +/* + * This function implements the procedure to mass erase the flash via + * SWD/JTAG on Kinetis K and L series of devices as it is described in + * AN4835 "Production Flash Programming Best Practices for Kinetis K- + * and L-series MCUs" Section 4.2.1 + */ +COMMAND_HANDLER(kinetis_mdm_mass_erase) +{ + struct target *target = get_current_target(CMD_CTX); + struct cortex_m_common *cortex_m = target_to_cm(target); + struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; + + if (!dap) { + LOG_ERROR("Cannot perform mass erase with a high-level adapter"); + return ERROR_FAIL; + } + + int retval; + const uint8_t original_ap = dap->ap_current; + + /* + * ... Power on the processor, or if power has already been + * applied, assert the RESET pin to reset the processor. For + * devices that do not have a RESET pin, write the System + * Reset Request bit in the MDM-AP control register after + * establishing communication... + */ + + /* assert SRST */ + if (jtag_get_reset_config() & RESET_HAS_SRST) + adapter_assert_reset(); + else + LOG_WARNING("Attempting mass erase without hardware reset. This is not reliable; " + "it's recommended you connect SRST and use ``reset_config srst_only''."); + + dap_ap_select(dap, 1); + + retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MEM_CTRL_SYS_RES_REQ); + if (retval != ERROR_OK) + return retval; + + /* + * ... Read the MDM-AP status register until the Flash Ready bit sets... + */ + retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT, + MDM_STAT_FREADY | MDM_STAT_SYSRES, + MDM_STAT_FREADY); + if (retval != ERROR_OK) { + LOG_ERROR("MDM : flash ready timeout"); + return retval; + } + + /* + * ... Write the MDM-AP control register to set the Flash Mass + * Erase in Progress bit. This will start the mass erase + * process... + */ + retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, + MEM_CTRL_SYS_RES_REQ | MEM_CTRL_FMEIP); + if (retval != ERROR_OK) + return retval; + + /* As a sanity check make sure that device started mass erase procedure */ + retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT, + MDM_STAT_FMEACK, MDM_STAT_FMEACK); + if (retval != ERROR_OK) + return retval; + + /* + * ... Read the MDM-AP control register until the Flash Mass + * Erase in Progress bit clears... + */ + retval = kinetis_mdm_poll_register(dap, MDM_REG_CTRL, + MEM_CTRL_FMEIP, + 0); + if (retval != ERROR_OK) + return retval; + + /* + * ... Negate the RESET signal or clear the System Reset Request + * bit in the MDM-AP control register... + */ + retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0); + if (retval != ERROR_OK) + return retval; + + if (jtag_get_reset_config() & RESET_HAS_SRST) + adapter_deassert_reset(); + + dap_ap_select(dap, original_ap); + return ERROR_OK; +} + +static const uint32_t kinetis_known_mdm_ids[] = { + 0x001C0000, /* Kinetis-K Series */ + 0x001C0020, /* Kinetis-L/M/V/E Series */ +}; + +/* + * This function implements the procedure to connect to + * SWD/JTAG on Kinetis K and L series of devices as it is described in + * AN4835 "Production Flash Programming Best Practices for Kinetis K- + * and L-series MCUs" Section 4.1.1 + */ +COMMAND_HANDLER(kinetis_check_flash_security_status) +{ + struct target *target = get_current_target(CMD_CTX); + struct cortex_m_common *cortex_m = target_to_cm(target); + struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; + + if (!dap) { + LOG_WARNING("Cannot check flash security status with a high-level adapter"); + return ERROR_OK; + } + + uint32_t val; + int retval; + const uint8_t origninal_ap = dap->ap_current; + + dap_ap_select(dap, 1); + + + /* + * ... The MDM-AP ID register can be read to verify that the + * connection is working correctly... + */ + retval = kinetis_mdm_read_register(dap, MDM_REG_ID, &val); + if (retval != ERROR_OK) { + LOG_ERROR("MDM: failed to read ID register"); + goto fail; + } + + bool found = false; + for (size_t i = 0; i < ARRAY_SIZE(kinetis_known_mdm_ids); i++) { + if (val == kinetis_known_mdm_ids[i]) { + found = true; + break; + } + } + + if (!found) + LOG_WARNING("MDM: unknown ID %08" PRIX32, val); + + /* + * ... Read the MDM-AP status register until the Flash Ready bit sets... + */ + retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT, + MDM_STAT_FREADY, + MDM_STAT_FREADY); + if (retval != ERROR_OK) { + LOG_ERROR("MDM: flash ready timeout"); + goto fail; + } + + /* + * ... Read the System Security bit to determine if security is enabled. + * If System Security = 0, then proceed. If System Security = 1, then + * communication with the internals of the processor, including the + * flash, will not be possible without issuing a mass erase command or + * unsecuring the part through other means (backdoor key unlock)... + */ + retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val); + if (retval != ERROR_OK) { + LOG_ERROR("MDM: failed to read MDM_REG_STAT"); + goto fail; + } + + if (val & MDM_STAT_SYSSEC) { + jtag_poll_set_enabled(false); + + LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********"); + LOG_WARNING("**** ****"); + LOG_WARNING("**** Your Kinetis MCU is in secured state, which means that, ****"); + LOG_WARNING("**** with exception for very basic communication, JTAG/SWD ****"); + LOG_WARNING("**** interface will NOT work. In order to restore its ****"); + LOG_WARNING("**** functionality please issue 'kinetis mdm mass_erase' ****"); + LOG_WARNING("**** command, power cycle the MCU and restart OpenOCD. ****"); + LOG_WARNING("**** ****"); + LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********"); + } else { + LOG_INFO("MDM: Chip is unsecured. Continuing."); + jtag_poll_set_enabled(true); + } + + dap_ap_select(dap, origninal_ap); + + return ERROR_OK; + +fail: + LOG_ERROR("MDM: Failed to check security status of the MCU. Cannot proceed further"); + jtag_poll_set_enabled(false); + return retval; +} + FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) { struct kinetis_flash_bank *bank_info; @@ -267,7 +563,7 @@ static const uint8_t kinetis_flash_write_code[] = { }; /* Program LongWord Block Write */ -static int kinetis_write_block(struct flash_bank *bank, uint8_t *buffer, +static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t wcount) { struct target *target = bank->target; @@ -338,11 +634,6 @@ static int kinetis_write_block(struct flash_bank *bank, uint8_t *buffer, while (wcount > 0) { uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount; - retval = target_write_buffer(target, write_algorithm->address, 8, - kinetis_flash_write_code); - if (retval != ERROR_OK) - break; - retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer); if (retval != ERROR_OK) break; @@ -483,7 +774,7 @@ static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t return result; /* wait for done */ - for (i = 0; i < 240; i++) { /* Need Entire Erase Nemui Changed */ + for (i = 0; i < 240; i++) { /* Need longtime for "Mass Erase" Command Nemui Changed */ result = target_read_memory(bank->target, FTFx_FSTAT, 1, 1, ftfx_fstat); @@ -506,42 +797,31 @@ static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t return ERROR_OK; } -static int kinetis_mass_erase(struct flash_bank *bank) +COMMAND_HANDLER(kinetis_securing_test) { int result; uint8_t ftfx_fstat; + struct target *target = get_current_target(CMD_CTX); + struct flash_bank *bank = NULL; - if (bank->target->state != TARGET_HALTED) { + result = get_flash_bank_by_addr(target, 0x00000000, true, &bank); + if (result != ERROR_OK) + return result; + + assert(bank != NULL); + + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - /* check if whole bank is blank */ - LOG_INFO("Kinetis L Series Erase All Blocks"); - /* set command and sector address */ - result = kinetis_ftfx_command(bank, FTFx_CMD_MASSERASE, 0, - 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); - /* Anyway Result, write unsecure byte */ - /* if (result != ERROR_OK) - return result;*/ - - /* Write to MCU security status unsecure in Flash security byte(Work around) */ - LOG_INFO("Write to MCU security status unsecure Anyway!"); - uint8_t padding[4] = {0xFE, 0xFF, 0xFF, 0xFF}; /* Write 0xFFFFFFFE */ - - result = kinetis_ftfx_command(bank, FTFx_CMD_LWORDPROG, (bank->base + 0x0000040C), - padding[3], padding[2], padding[1], padding[0], - 0, 0, 0, 0, &ftfx_fstat); - if (result != ERROR_OK) - return ERROR_FLASH_OPERATION_FAILED; - - return ERROR_OK; + return kinetis_ftfx_command(bank, FTFx_CMD_SECTERASE, bank->base + 0x00000400, + 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); } static int kinetis_erase(struct flash_bank *bank, int first, int last) { int result, i; - struct kinetis_flash_bank *kinfo = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -551,9 +831,6 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) if ((first > bank->num_sectors) || (last > bank->num_sectors)) return ERROR_FLASH_OPERATION_FAILED; - if ((first == 0) && (last == (bank->num_sectors - 1)) && (kinfo->klxx)) - return kinetis_mass_erase(bank); - /* * FIXME: TODO: use the 'Erase Flash Block' command if the * requested erase is PFlash or NVM and encompasses the entire @@ -581,7 +858,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) return ERROR_OK; } -static int kinetis_write(struct flash_bank *bank, uint8_t *buffer, +static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { unsigned int i, result, fallback = 0; @@ -726,7 +1003,7 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer, } LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " " "and padding with 0xff", old_count, count); - memset(buffer, 0xff, count); + memset(new_buffer, 0xff, count); buffer = memcpy(new_buffer, buffer, old_count); } @@ -788,28 +1065,39 @@ static int kinetis_read_part_info(struct flash_bank *bank) uint32_t mcu_type = kinfo->sim_sdid & KINETIS_K_SDID_TYPE_MASK; switch (mcu_type) { - case KINETIS_K_SDID_K20: + case KINETIS_K_SDID_K10_M50: + case KINETIS_K_SDID_K20_M50: /* 1kB sectors */ granularity = 0; break; - case KINETIS_K_SDID_K30: - case KINETIS_K_SDID_K40: - case KINETIS_K_SDID_K50: + case KINETIS_K_SDID_K10_M72: + case KINETIS_K_SDID_K20_M72: + case KINETIS_K_SDID_K30_M72: + case KINETIS_K_SDID_K30_M100: + case KINETIS_K_SDID_K40_M72: + case KINETIS_K_SDID_K40_M100: + case KINETIS_K_SDID_K50_M72: /* 2kB sectors, 1kB FlexNVM sectors */ granularity = 1; break; + case KINETIS_K_SDID_K10_M100: + case KINETIS_K_SDID_K20_M100: case KINETIS_K_SDID_K11: case KINETIS_K_SDID_K12: - case KINETIS_K_SDID_K21: - case KINETIS_K_SDID_K22: - case KINETIS_K_SDID_K51: + case KINETIS_K_SDID_K21_M50: + case KINETIS_K_SDID_K22_M50: + case KINETIS_K_SDID_K51_M72: case KINETIS_K_SDID_K53: - case KINETIS_K_SDID_K60: + case KINETIS_K_SDID_K60_M100: /* 2kB sectors */ granularity = 2; break; - case KINETIS_K_SDID_K10: - case KINETIS_K_SDID_K70: + case KINETIS_K_SDID_K10_M120: + case KINETIS_K_SDID_K20_M120: + case KINETIS_K_SDID_K21_M120: + case KINETIS_K_SDID_K22_M120: + case KINETIS_K_SDID_K60_M150: + case KINETIS_K_SDID_K70_M150: /* 4kB sectors */ granularity = 3; break; @@ -1134,8 +1422,58 @@ static int kinetis_blank_check(struct flash_bank *bank) return ERROR_OK; } +static const struct command_registration kinetis_securtiy_command_handlers[] = { + { + .name = "check_security", + .mode = COMMAND_EXEC, + .help = "", + .usage = "", + .handler = kinetis_check_flash_security_status, + }, + { + .name = "mass_erase", + .mode = COMMAND_EXEC, + .help = "", + .usage = "", + .handler = kinetis_mdm_mass_erase, + }, + { + .name = "test_securing", + .mode = COMMAND_EXEC, + .help = "", + .usage = "", + .handler = kinetis_securing_test, + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration kinetis_exec_command_handlers[] = { + { + .name = "mdm", + .mode = COMMAND_ANY, + .help = "", + .usage = "", + .chain = kinetis_securtiy_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration kinetis_command_handler[] = { + { + .name = "kinetis", + .mode = COMMAND_ANY, + .help = "kinetis NAND flash controller commands", + .usage = "", + .chain = kinetis_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + + + struct flash_driver kinetis_flash = { .name = "kinetis", + .commands = kinetis_command_handler, .flash_bank_command = kinetis_flash_bank_command, .erase = kinetis_erase, .protect = kinetis_protect,