flash/kinetis: use coherent indentation in struct initialization
[openocd.git] / src / flash / nor / kinetis.c
index dc3dc45976b0f9066a01c95a96e5bdc65d58aac9..9b2c014ca928e8fe585c010c225bb907a93d3f52 100644 (file)
 #define FTFx_FCCOB3    0x40020004
 #define FTFx_FPROT3    0x40020010
 #define FTFx_FDPROT    0x40020017
-#define SIM_SDID       0x40048024
-#define SIM_SOPT1      0x40047000
-#define SIM_FCFG1      0x4004804c
-#define SIM_FCFG2      0x40048050
-#define WDOG_STCTRH    0x40052000
+#define SIM_BASE       0x40047000
+#define SIM_BASE_KL28  0x40074000
+#define SIM_COPC       0x40048100
+       /* SIM_COPC does not exist on devices with changed SIM_BASE */
+#define WDOG_BASE      0x40052000
+#define WDOG32_KE1X    0x40052000
+#define WDOG32_KL28    0x40076000
 #define SMC_PMCTRL     0x4007E001
 #define SMC_PMSTAT     0x4007E003
+#define SMC32_PMCTRL   0x4007E00C
+#define SMC32_PMSTAT   0x4007E014
 #define MCM_PLACR      0xF000300C
 
+/* Offsets */
+#define SIM_SOPT1_OFFSET    0x0000
+#define SIM_SDID_OFFSET            0x1024
+#define SIM_FCFG1_OFFSET    0x104c
+#define SIM_FCFG2_OFFSET    0x1050
+
+#define WDOG_STCTRLH_OFFSET      0
+#define WDOG32_CS_OFFSET         0
+
 /* Values */
 #define PM_STAT_RUN            0x01
 #define PM_STAT_VLPR           0x04
@@ -265,18 +278,38 @@ struct kinetis_chip {
        uint32_t dflash_size;           /* accessible rest of FlexNVM if EEPROM backup uses part of FlexNVM */
 
        uint32_t progr_accel_ram;
+       uint32_t sim_base;
 
        enum {
                FS_PROGRAM_SECTOR = 1,
                FS_PROGRAM_LONGWORD = 2,
                FS_PROGRAM_PHRASE = 4,          /* Unsupported */
-               FS_INVALIDATE_CACHE_K = 8,      /* using FMC->PFB0CR/PFB01CR */
-               FS_INVALIDATE_CACHE_L = 0x10,   /* using MCM->PLACR */
-               FS_INVALIDATE_CACHE_MSCM = 0x20,
+
                FS_NO_CMD_BLOCKSTAT = 0x40,
                FS_WIDTH_256BIT = 0x80,
+               FS_ECC = 0x100,
        } flash_support;
 
+       enum {
+               KINETIS_CACHE_NONE,
+               KINETIS_CACHE_K,        /* invalidate using FMC->PFB0CR/PFB01CR */
+               KINETIS_CACHE_L,        /* invalidate using MCM->PLACR */
+               KINETIS_CACHE_MSCM,     /* devices like KE1xF, invalidate MSCM->OCMDR0 */
+       } cache_type;
+
+       enum {
+               KINETIS_WDOG_NONE,
+               KINETIS_WDOG_K,
+               KINETIS_WDOG_COP,
+               KINETIS_WDOG32_KE1X,
+               KINETIS_WDOG32_KL28,
+       } watchdog_type;
+
+       enum {
+               KINETIS_SMC,
+               KINETIS_SMC32,
+       } sysmodectrlr_type;
+
        char name[40];
 
        unsigned num_banks;
@@ -356,12 +389,14 @@ static const struct kinetis_type kinetis_types_old[] = {
 
 static bool allow_fcf_writes;
 static uint8_t fcf_fopt = 0xff;
+static bool fcf_fopt_configured;
 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);
 static int kinetis_auto_probe(struct flash_bank *bank);
 
 
@@ -823,11 +858,25 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target)
        return NULL;
 }
 
+static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[])
+{
+       int i;
+       for (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);
+               } else
+                       LOG_ERROR("Unsupported flash bank option %s", argv[i]);
+       }
+       return ERROR_OK;
+}
+
 FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
 {
        struct target *target = bank->target;
        struct kinetis_chip *k_chip;
        struct kinetis_flash_bank *k_bank;
+       int retval;
 
        if (CMD_ARGC < 6)
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -844,6 +893,11 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
                }
 
                k_chip->target = target;
+
+               /* only the first defined bank can define chip options */
+               retval = kinetis_chip_options(k_chip, CMD_ARGC - 6, CMD_ARGV + 6);
+               if (retval != ERROR_OK)
+                       return retval;
        }
 
        if (k_chip->num_banks >= KINETIS_MAX_BANKS) {
@@ -861,13 +915,29 @@ 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;
@@ -878,19 +948,21 @@ 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';
@@ -941,11 +1013,53 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
 }
 
 
-/* Disable the watchdog on Kinetis devices */
-int kinetis_disable_wdog(struct target *target, uint32_t sim_sdid)
+static int kinetis_disable_wdog_algo(struct target *target, size_t code_size, const uint8_t *code, uint32_t wdog_base)
 {
        struct working_area *wdog_algorithm;
        struct armv7m_algorithm armv7m_info;
+       struct reg_param reg_params[1];
+       int retval;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       retval = target_alloc_working_area(target, code_size, &wdog_algorithm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_buffer(target, wdog_algorithm->address,
+                       code_size, code);
+       if (retval == ERROR_OK) {
+               armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+               armv7m_info.core_mode = ARM_MODE_THREAD;
+
+               init_reg_param(&reg_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,
+                       wdog_algorithm->address,
+                       wdog_algorithm->address + code_size - 2,
+                       500, &armv7m_info);
+
+               destroy_reg_param(&reg_params[0]);
+
+               if (retval != ERROR_OK)
+                       LOG_ERROR("Error executing Kinetis WDOG unlock algorithm");
+       }
+
+       target_free_working_area(target, wdog_algorithm);
+
+       return retval;
+}
+
+/* Disable the watchdog on Kinetis devices
+ * Standard Kx WDOG peripheral checks timing and therefore requires to run algo.
+ */
+static int kinetis_disable_wdog_kx(struct target *target)
+{
+       const uint32_t wdog_base = WDOG_BASE;
        uint16_t wdog;
        int retval;
 
@@ -953,14 +1067,7 @@ int kinetis_disable_wdog(struct target *target, uint32_t sim_sdid)
 #include "../../../contrib/loaders/watchdog/armv7m_kinetis_wdog.inc"
        };
 
-       /* Decide whether the connected device needs watchdog disabling.
-        * Disable for all Kx and KVx devices, return if it is a KLx */
-
-       if ((sim_sdid & KINETIS_SDID_SERIESID_MASK) == KINETIS_SDID_SERIESID_KL)
-               return ERROR_OK;
-
-       /* The connected device requires watchdog disabling. */
-       retval = target_read_u16(target, WDOG_STCTRH, &wdog);
+       retval = target_read_u16(target, wdog_base + WDOG_STCTRLH_OFFSET, &wdog);
        if (retval != ERROR_OK)
                return retval;
 
@@ -968,60 +1075,116 @@ int kinetis_disable_wdog(struct target *target, uint32_t sim_sdid)
                /* watchdog already disabled */
                return ERROR_OK;
        }
-       LOG_INFO("Disabling Kinetis watchdog (initial WDOG_STCTRLH = 0x%x)", wdog);
+       LOG_INFO("Disabling Kinetis watchdog (initial WDOG_STCTRLH = 0x%04" PRIx16 ")", wdog);
 
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       retval = kinetis_disable_wdog_algo(target, sizeof(kinetis_unlock_wdog_code), kinetis_unlock_wdog_code, wdog_base);
+       if (retval != ERROR_OK)
+               return retval;
 
-       retval = target_alloc_working_area(target, sizeof(kinetis_unlock_wdog_code), &wdog_algorithm);
+       retval = target_read_u16(target, wdog_base + WDOG_STCTRLH_OFFSET, &wdog);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = target_write_buffer(target, wdog_algorithm->address,
-                       sizeof(kinetis_unlock_wdog_code), (uint8_t *)kinetis_unlock_wdog_code);
-       if (retval != ERROR_OK) {
-               target_free_working_area(target, wdog_algorithm);
+       LOG_INFO("WDOG_STCTRLH = 0x%04" PRIx16, wdog);
+       return (wdog & 0x1) ? ERROR_FAIL : ERROR_OK;
+}
+
+static int kinetis_disable_wdog32(struct target *target, uint32_t wdog_base)
+{
+       uint32_t wdog_cs;
+       int retval;
+
+       static const uint8_t kinetis_unlock_wdog_code[] = {
+#include "../../../contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc"
+       };
+
+       retval = target_read_u32(target, wdog_base + WDOG32_CS_OFFSET, &wdog_cs);
+       if (retval != ERROR_OK)
                return retval;
-       }
 
-       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
-       armv7m_info.core_mode = ARM_MODE_THREAD;
+       if ((wdog_cs & 0x80) == 0)
+               return ERROR_OK; /* watchdog already disabled */
 
-       retval = target_run_algorithm(target, 0, NULL, 0, NULL, wdog_algorithm->address,
-                       wdog_algorithm->address + (sizeof(kinetis_unlock_wdog_code) - 2),
-                       10000, &armv7m_info);
+       LOG_INFO("Disabling Kinetis watchdog (initial WDOG_CS 0x%08" PRIx32 ")", wdog_cs);
 
+       retval = kinetis_disable_wdog_algo(target, sizeof(kinetis_unlock_wdog_code), kinetis_unlock_wdog_code, wdog_base);
        if (retval != ERROR_OK)
-               LOG_ERROR("error executing kinetis wdog unlock algorithm");
+               return retval;
 
-       retval = target_read_u16(target, WDOG_STCTRH, &wdog);
+       retval = target_read_u32(target, wdog_base + WDOG32_CS_OFFSET, &wdog_cs);
        if (retval != ERROR_OK)
                return retval;
-       LOG_INFO("WDOG_STCTRLH = 0x%x", wdog);
 
-       target_free_working_area(target, wdog_algorithm);
+       if ((wdog_cs & 0x80) == 0)
+               return ERROR_OK; /* watchdog disabled successfully */
 
-       return retval;
+       LOG_ERROR("Cannot disable Kinetis watchdog (WDOG_CS 0x%08" PRIx32 "), issue 'reset init'", wdog_cs);
+       return ERROR_FAIL;
+}
+
+static int kinetis_disable_wdog(struct kinetis_chip *k_chip)
+{
+       struct target *target = k_chip->target;
+       uint8_t sim_copc;
+       int retval;
+
+       if (!k_chip->probed) {
+               retval = kinetis_probe_chip(k_chip);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       switch (k_chip->watchdog_type) {
+       case KINETIS_WDOG_K:
+               return kinetis_disable_wdog_kx(target);
+
+       case KINETIS_WDOG_COP:
+               retval = target_read_u8(target, SIM_COPC, &sim_copc);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if ((sim_copc & 0xc) == 0)
+                       return ERROR_OK; /* watchdog already disabled */
+
+               LOG_INFO("Disabling Kinetis watchdog (initial SIM_COPC 0x%02" PRIx8 ")", sim_copc);
+               retval = target_write_u8(target, SIM_COPC, sim_copc & ~0xc);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = target_read_u8(target, SIM_COPC, &sim_copc);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if ((sim_copc & 0xc) == 0)
+                       return ERROR_OK; /* watchdog disabled successfully */
+
+               LOG_ERROR("Cannot disable Kinetis watchdog (SIM_COPC 0x%02" PRIx8 "), issue 'reset init'", sim_copc);
+               return ERROR_FAIL;
+
+       case KINETIS_WDOG32_KE1X:
+               return kinetis_disable_wdog32(target, WDOG32_KE1X);
+
+       case KINETIS_WDOG32_KL28:
+               return kinetis_disable_wdog32(target, WDOG32_KL28);
+
+       default:
+               return ERROR_OK;
+       }
 }
 
 COMMAND_HANDLER(kinetis_disable_wdog_handler)
 {
        int result;
-       uint32_t sim_sdid;
        struct target *target = get_current_target(CMD_CTX);
+       struct kinetis_chip *k_chip = kinetis_get_chip(target);
+
+       if (k_chip == NULL)
+               return ERROR_FAIL;
 
        if (CMD_ARGC > 0)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       result = target_read_u32(target, SIM_SDID, &sim_sdid);
-       if (result != ERROR_OK) {
-               LOG_ERROR("Failed to read SIMSDID");
-               return result;
-       }
-
-       result = kinetis_disable_wdog(target, sim_sdid);
+       result = kinetis_disable_wdog(k_chip);
        return result;
 }
 
@@ -1355,17 +1518,44 @@ static int kinetis_ftfx_command(struct target *target, uint8_t fcmd, uint32_t fa
 }
 
 
-static int kinetis_check_run_mode(struct target *target)
+static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat)
+{
+       int result;
+       uint32_t stat32;
+       struct target *target = k_chip->target;
+
+       switch (k_chip->sysmodectrlr_type) {
+       case KINETIS_SMC:
+               result = target_read_u8(target, SMC_PMSTAT, pmstat);
+               return result;
+
+       case KINETIS_SMC32:
+               result = target_read_u32(target, SMC32_PMSTAT, &stat32);
+               if (result == ERROR_OK)
+                       *pmstat = stat32 & 0xff;
+               return result;
+       }
+       return ERROR_FAIL;
+}
+
+static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
 {
        int result, i;
-       uint8_t pmctrl, pmstat;
+       uint8_t pmstat;
+       struct target *target;
+
+       if (k_chip == NULL) {
+               LOG_ERROR("Chip not probed.");
+               return ERROR_FAIL;
+       }
+       target = k_chip->target;
 
        if (target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       result = target_read_u8(target, SMC_PMSTAT, &pmstat);
+       result = kinetis_read_pmstat(k_chip, &pmstat);
        if (result != ERROR_OK)
                return result;
 
@@ -1375,13 +1565,21 @@ static int kinetis_check_run_mode(struct target *target)
        if (pmstat == PM_STAT_VLPR) {
                /* It is safe to switch from VLPR to RUN mode without changing clock */
                LOG_INFO("Switching from VLPR to RUN mode.");
-               pmctrl = PM_CTRL_RUNM_RUN;
-               result = target_write_u8(target, SMC_PMCTRL, pmctrl);
+
+               switch (k_chip->sysmodectrlr_type) {
+               case KINETIS_SMC:
+                       result = target_write_u8(target, SMC_PMCTRL, PM_CTRL_RUNM_RUN);
+                       break;
+
+               case KINETIS_SMC32:
+                       result = target_write_u32(target, SMC32_PMCTRL, PM_CTRL_RUNM_RUN);
+                       break;
+               }
                if (result != ERROR_OK)
                        return result;
 
                for (i = 100; i; i--) {
-                       result = target_read_u8(target, SMC_PMSTAT, &pmstat);
+                       result = kinetis_read_pmstat(k_chip, &pmstat);
                        if (result != ERROR_OK)
                                return result;
 
@@ -1400,20 +1598,26 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip)
 {
        struct target *target = k_chip->target;
 
-       if (k_chip->flash_support & FS_INVALIDATE_CACHE_K)
+       switch (k_chip->cache_type) {
+       case KINETIS_CACHE_K:
                target_write_u8(target, FMC_PFB01CR + 2, 0xf0);
                /* Set CINV_WAY bits - request invalidate of all cache ways */
                /* FMC_PFB0CR has same address and CINV_WAY bits as FMC_PFB01CR */
+               break;
 
-       else if (k_chip->flash_support & FS_INVALIDATE_CACHE_L)
+       case KINETIS_CACHE_L:
                target_write_u8(target, MCM_PLACR + 1, 0x04);
                /* set bit CFCC - Clear Flash Controller Cache */
+               break;
 
-       else if (k_chip->flash_support & FS_INVALIDATE_CACHE_MSCM)
+       case KINETIS_CACHE_MSCM:
                target_write_u32(target, MSCM_OCMDR0, 0x30);
                /* disable data prefetch and flash speculate */
+               break;
 
-       return;
+       default:
+               break;
+       }
 }
 
 
@@ -1421,8 +1625,9 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
 {
        int result, i;
        struct kinetis_flash_bank *k_bank = bank->driver_priv;
+       struct kinetis_chip *k_chip = k_bank->k_chip;
 
-       result = kinetis_check_run_mode(bank->target);
+       result = kinetis_check_run_mode(k_chip);
        if (result != ERROR_OK)
                return result;
 
@@ -1550,13 +1755,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) {
@@ -1571,12 +1778,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");
@@ -1615,7 +1824,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
                }
        }
 
-       LOG_DEBUG("flash write @ %08" PRIx32, bank->base + offset);
+       LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset);
 
        if (fallback == 0) {
                /* program section command */
@@ -1647,7 +1856,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
 
                uint32_t words_remaining = count / 4;
 
-               kinetis_disable_wdog(bank->target, k_chip->sim_sdid);
+               kinetis_disable_wdog(k_chip);
 
                /* try using a block write */
                result = kinetis_write_block(bank, buffer, offset, words_remaining);
@@ -1668,12 +1877,14 @@ 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;
@@ -1696,10 +1907,15 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
 {
        int result;
        bool set_fcf = false;
+       bool fcf_in_data_valid = 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(bank->target);
+       result = kinetis_check_run_mode(k_chip);
        if (result != ERROR_OK)
                return result;
 
@@ -1718,11 +1934,41 @@ 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_FPROT, fcf_buffer, 4)) {
+                               fcf_in_data_valid = false;
+                               LOG_INFO("Flash protection requested in programmed file differs from current setting.");
+                       }
+                       if (fcf_in_data[FCF_FDPROT] != fcf_buffer[FCF_FDPROT]) {
+                               fcf_in_data_valid = false;
+                               LOG_INFO("Data flash protection requested in 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 programmed file!");
+                       } else if (k_chip->flash_support & FS_ECC
+                           && fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) {
+                               fcf_in_data_valid = false;
+                               LOG_INFO("Strange unsecure mode 0x%02" PRIx8
+                                        "requested in programmed file!",
+                                        fcf_in_data[FCF_FSEC]);
+                       }
+                       if ((k_chip->flash_support & FS_ECC || fcf_fopt_configured)
+                           && fcf_in_data[FCF_FOPT] != fcf_fopt) {
+                               fcf_in_data_valid = false;
+                               LOG_INFO("FOPT requested in programmed file differs from current setting.");
+                       }
+                       if (!fcf_in_data_valid)
+                               LOG_INFO("Expect verify errors at FCF (0x408-0x40f).");
+               }
+       }
+
+       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);
@@ -1751,9 +1997,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);
+       }
 }
 
 
@@ -1773,7 +2020,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
        unsigned cpu_mhz = 120;
        unsigned idx;
        bool use_nvm_marking = false;
-       char flash_marking[8], nvm_marking[2];
+       char flash_marking[12], nvm_marking[2];
        char name[40];
 
        k_chip->probed = false;
@@ -1784,13 +2031,26 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
 
        name[0] = '\0';
 
-       result = target_read_u32(target, SIM_SDID, &k_chip->sim_sdid);
+       if (k_chip->sim_base)
+               result = target_read_u32(target, k_chip->sim_base + SIM_SDID_OFFSET, &k_chip->sim_sdid);
+       else {
+               result = target_read_u32(target, SIM_BASE + SIM_SDID_OFFSET, &k_chip->sim_sdid);
+               if (result == ERROR_OK)
+                       k_chip->sim_base = SIM_BASE;
+               else {
+                       result = target_read_u32(target, SIM_BASE_KL28 + SIM_SDID_OFFSET, &k_chip->sim_sdid);
+                       if (result == ERROR_OK)
+                               k_chip->sim_base = SIM_BASE_KL28;
+               }
+       }
        if (result != ERROR_OK)
                return result;
 
        if ((k_chip->sim_sdid & (~KINETIS_SDID_K_SERIES_MASK)) == 0) {
                /* older K-series MCU */
                uint32_t mcu_type = k_chip->sim_sdid & KINETIS_K_SDID_TYPE_MASK;
+               k_chip->cache_type = KINETIS_CACHE_K;
+               k_chip->watchdog_type = KINETIS_WDOG_K;
 
                switch (mcu_type) {
                case KINETIS_K_SDID_K10_M50:
@@ -1799,7 +2059,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        k_chip->pflash_sector_size = 1<<10;
                        k_chip->nvm_sector_size = 1<<10;
                        num_blocks = 2;
-                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR;
                        break;
                case KINETIS_K_SDID_K10_M72:
                case KINETIS_K_SDID_K20_M72:
@@ -1812,7 +2072,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        k_chip->pflash_sector_size = 2<<10;
                        k_chip->nvm_sector_size = 1<<10;
                        num_blocks = 2;
-                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR;
                        k_chip->max_flash_prog_size = 1<<10;
                        break;
                case KINETIS_K_SDID_K10_M100:
@@ -1828,7 +2088,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        k_chip->pflash_sector_size = 2<<10;
                        k_chip->nvm_sector_size = 2<<10;
                        num_blocks = 2;
-                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR;
                        break;
                case KINETIS_K_SDID_K21_M120:
                case KINETIS_K_SDID_K22_M120:
@@ -1837,7 +2097,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        k_chip->max_flash_prog_size = 1<<10;
                        k_chip->nvm_sector_size = 4<<10;
                        num_blocks = 2;
-                       k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                       k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
                        break;
                case KINETIS_K_SDID_K10_M120:
                case KINETIS_K_SDID_K20_M120:
@@ -1847,7 +2107,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        k_chip->pflash_sector_size = 4<<10;
                        k_chip->nvm_sector_size = 4<<10;
                        num_blocks = 4;
-                       k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                       k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
                        break;
                default:
                        LOG_ERROR("Unsupported K-family FAMID");
@@ -1869,19 +2129,22 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                switch (k_chip->sim_sdid & KINETIS_SDID_SERIESID_MASK) {
                case KINETIS_SDID_SERIESID_K:
                        use_nvm_marking = true;
+                       k_chip->cache_type = KINETIS_CACHE_K;
+                       k_chip->watchdog_type = KINETIS_WDOG_K;
+
                        switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) {
                        case KINETIS_SDID_FAMILYID_K0X | KINETIS_SDID_SUBFAMID_KX2:
                                /* K02FN64, K02FN128: FTFA, 2kB sectors */
                                k_chip->pflash_sector_size = 2<<10;
                                num_blocks = 1;
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD;
                                cpu_mhz = 100;
                                break;
 
                        case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX2: {
                                /* MK24FN1M reports as K22, this should detect it (according to errata note 1N83J) */
                                uint32_t sopt1;
-                               result = target_read_u32(target, SIM_SOPT1, &sopt1);
+                               result = target_read_u32(target, k_chip->sim_base + SIM_SOPT1_OFFSET, &sopt1);
                                if (result != ERROR_OK)
                                        return result;
 
@@ -1890,7 +2153,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                        /* MK24FN1M */
                                        k_chip->pflash_sector_size = 4<<10;
                                        num_blocks = 2;
-                                       k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                                       k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
                                        k_chip->max_flash_prog_size = 1<<10;
                                        subfamid = 4; /* errata 1N83J fix */
                                        break;
@@ -1901,7 +2164,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                        /* K22 with new-style SDID - smaller pflash with FTFA, 2kB sectors */
                                        k_chip->pflash_sector_size = 2<<10;
                                        /* autodetect 1 or 2 blocks */
-                                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
+                                       k_chip->flash_support = FS_PROGRAM_LONGWORD;
                                        break;
                                }
                                LOG_ERROR("Unsupported Kinetis K22 DIEID");
@@ -1912,18 +2175,19 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                if ((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN256) {
                                        /* K24FN256 - smaller pflash with FTFA */
                                        num_blocks = 1;
-                                       k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
+                                       k_chip->flash_support = FS_PROGRAM_LONGWORD;
                                        break;
                                }
                                /* K24FN1M without errata 7534 */
                                num_blocks = 2;
-                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
                                k_chip->max_flash_prog_size = 1<<10;
                                break;
 
                        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:
@@ -1932,7 +2196,7 @@ 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 = 2;
-                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
+                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
                                break;
 
                        case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX6:
@@ -1943,17 +2207,28 @@ 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 | FS_INVALIDATE_CACHE_K;
+                               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:
                                /* K80FN256, K81FN256, K82FN256 */
                                k_chip->pflash_sector_size = 4<<10;
                                num_blocks = 1;
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K | FS_NO_CMD_BLOCKSTAT;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_NO_CMD_BLOCKSTAT;
                                cpu_mhz = 150;
                                break;
 
@@ -1962,7 +2237,9 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                /* KL81Z128, KL82Z128 */
                                k_chip->pflash_sector_size = 2<<10;
                                num_blocks = 1;
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L | FS_NO_CMD_BLOCKSTAT;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_NO_CMD_BLOCKSTAT;
+                               k_chip->cache_type = KINETIS_CACHE_L;
+
                                use_nvm_marking = false;
                                snprintf(name, sizeof(name), "MKL8%uZ%%s7",
                                         subfamid);
@@ -1982,23 +2259,79 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        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 | FS_INVALIDATE_CACHE_L;
+                       k_chip->flash_support = FS_PROGRAM_LONGWORD;
+                       k_chip->cache_type = KINETIS_CACHE_L;
+                       k_chip->watchdog_type = KINETIS_WDOG_COP;
 
                        cpu_mhz = 48;
-                       if (subfamid == 3 && (familyid == 1 || familyid == 2))
+                       switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) {
+                       case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX3:
+                       case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX3:
                                subfamid = 7;
+                               break;
+
+                       case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8:
+                               cpu_mhz = 72;
+                               k_chip->pflash_sector_size = 2<<10;
+                               num_blocks = 2;
+                               k_chip->watchdog_type = KINETIS_WDOG32_KL28;
+                               k_chip->sysmodectrlr_type = KINETIS_SMC32;
+                               break;
+                       }
+
                        snprintf(name, sizeof(name), "MKL%u%uZ%%s%u",
                                 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;
                        switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) {
                        case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX0:
                                /* KV10: FTFA, 1kB sectors */
                                k_chip->pflash_sector_size = 1<<10;
                                num_blocks = 1;
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD;
+                               k_chip->cache_type = KINETIS_CACHE_L;
                                strcpy(name, "MKV10Z%s7");
                                break;
 
@@ -2006,7 +2339,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                /* KV11: FTFA, 2kB sectors */
                                k_chip->pflash_sector_size = 2<<10;
                                num_blocks = 1;
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD;
+                               k_chip->cache_type = KINETIS_CACHE_L;
                                strcpy(name, "MKV11Z%s7");
                                break;
 
@@ -2016,7 +2350,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                /* KV31: FTFA, 2kB sectors, 2 blocks */
                                k_chip->pflash_sector_size = 2<<10;
                                /* autodetect 1 or 2 blocks */
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD;
+                               k_chip->cache_type = KINETIS_CACHE_K;
                                break;
 
                        case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX2:
@@ -2025,7 +2360,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                /* KV4x: FTFA, 4kB sectors */
                                k_chip->pflash_sector_size = 4<<10;
                                num_blocks = 1;
-                               k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
+                               k_chip->flash_support = FS_PROGRAM_LONGWORD;
+                               k_chip->cache_type = KINETIS_CACHE_K;
                                cpu_mhz = 168;
                                break;
 
@@ -2036,7 +2372,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;
@@ -2053,6 +2389,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
 
                case KINETIS_SDID_SERIESID_KE:
                        /* KE1x-series */
+                       k_chip->watchdog_type = KINETIS_WDOG32_KE1X;
                        switch (k_chip->sim_sdid &
                                (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK | KINETIS_SDID_PROJECTID_MASK)) {
                        case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1xZ:
@@ -2062,7 +2399,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                k_chip->nvm_sector_size = 2<<10;
                                k_chip->max_flash_prog_size = 1<<9;
                                num_blocks = 2;
-                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_L;
+                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
+                               k_chip->cache_type = KINETIS_CACHE_L;
 
                                cpu_mhz = 72;
                                snprintf(name, sizeof(name), "MKE%u%uZ%%s%u",
@@ -2077,7 +2415,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                                k_chip->nvm_sector_size = 2<<10;
                                k_chip->max_flash_prog_size = 1<<10;
                                num_blocks = 2;
-                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_MSCM;
+                               k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
+                               k_chip->cache_type = KINETIS_CACHE_MSCM;
 
                                cpu_mhz = 168;
                                snprintf(name, sizeof(name), "MKE%u%uF%%s%u",
@@ -2099,11 +2438,11 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                return ERROR_FLASH_OPER_UNSUPPORTED;
        }
 
-       result = target_read_u32(target, SIM_FCFG1, &k_chip->sim_fcfg1);
+       result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &k_chip->sim_fcfg1);
        if (result != ERROR_OK)
                return result;
 
-       result = target_read_u32(target, SIM_FCFG2, &k_chip->sim_fcfg2);
+       result = target_read_u32(target, k_chip->sim_base + SIM_FCFG2_OFFSET, &k_chip->sim_fcfg2);
        if (result != ERROR_OK)
                return result;
 
@@ -2121,7 +2460,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) {
@@ -2178,6 +2519,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;
@@ -2195,6 +2537,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:
@@ -2205,6 +2551,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
@@ -2231,8 +2578,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';
@@ -2296,7 +2648,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;
@@ -2423,7 +2775,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);
@@ -2438,7 +2790,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
        int result;
 
        /* suprisingly blank check does not work in VLPR and HSRUN modes */
-       result = kinetis_check_run_mode(bank->target);
+       result = kinetis_check_run_mode(k_chip);
        if (result != ERROR_OK)
                return result;
 
@@ -2518,6 +2870,8 @@ COMMAND_HANDLER(kinetis_nvm_partition)
        struct kinetis_chip *k_chip;
        uint32_t sim_fcfg1;
 
+       k_chip = kinetis_get_chip(target);
+
        if (CMD_ARGC >= 2) {
                if (strcmp(CMD_ARGV[0], "dataflash") == 0)
                        sz_type = DF_SIZE;
@@ -2530,7 +2884,11 @@ COMMAND_HANDLER(kinetis_nvm_partition)
        }
        switch (sz_type) {
        case SHOW_INFO:
-               result = target_read_u32(target, SIM_FCFG1, &sim_fcfg1);
+               if (k_chip == NULL) {
+                       LOG_ERROR("Chip not probed.");
+                       return ERROR_FAIL;
+               }
+               result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &sim_fcfg1);
                if (result != ERROR_OK)
                        return result;
 
@@ -2613,7 +2971,7 @@ COMMAND_HANDLER(kinetis_nvm_partition)
        LOG_INFO("DEPART 0x%" PRIx8 ", EEPROM size code 0x%" PRIx8,
                 flex_nvm_partition_code, ee_size_code);
 
-       result = kinetis_check_run_mode(target);
+       result = kinetis_check_run_mode(k_chip);
        if (result != ERROR_OK)
                return result;
 
@@ -2630,7 +2988,6 @@ COMMAND_HANDLER(kinetis_nvm_partition)
 
        command_print(CMD_CTX, "FlexNVM partition set. Please reset MCU.");
 
-       k_chip = kinetis_get_chip(target);
        if (k_chip) {
                first_nvm_bank = k_chip->num_pflash_blocks;
                num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks;
@@ -2674,10 +3031,12 @@ 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
+               fcf_fopt_configured = true;
+       } else {
                command_print(CMD_CTX, "FCF_FOPT 0x%02" PRIx8, fcf_fopt);
+       }
 
        return ERROR_OK;
 }
@@ -2715,7 +3074,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 = "",
@@ -2784,7 +3144,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,
@@ -2797,4 +3157,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,
 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)