target algo: do not write reg_param if direction is PARAM_IN
[openocd.git] / src / flash / nor / kinetis.c
index 1f2383d..eca74a8 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 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
 
@@ -272,6 +278,7 @@ 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,
@@ -280,6 +287,7 @@ struct kinetis_chip {
 
                FS_NO_CMD_BLOCKSTAT = 0x40,
                FS_WIDTH_256BIT = 0x80,
+               FS_ECC = 0x100,
        } flash_support;
 
        enum {
@@ -297,6 +305,11 @@ struct kinetis_chip {
                KINETIS_WDOG32_KL28,
        } watchdog_type;
 
+       enum {
+               KINETIS_SMC,
+               KINETIS_SMC32,
+       } sysmodectrlr_type;
+
        char name[40];
 
        unsigned num_banks;
@@ -376,6 +389,7 @@ 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;
 
 
@@ -844,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;
@@ -865,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) {
@@ -882,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;
@@ -899,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';
@@ -984,7 +1035,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(&reg_params[0], "r0", 32, PARAM_IN);
+               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,
@@ -1467,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;
 
@@ -1487,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;
 
@@ -1539,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;
 
@@ -1814,10 +1901,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;
 
@@ -1836,11 +1928,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);
@@ -1869,9 +1991,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);
+       }
 }
 
 
@@ -1891,7 +2014,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;
@@ -1902,7 +2025,18 @@ 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;
 
@@ -2004,7 +2138,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        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;
 
@@ -2047,6 +2181,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:
@@ -2066,10 +2201,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:
@@ -2112,12 +2258,64 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
                        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;
@@ -2168,7 +2366,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;
@@ -2234,11 +2432,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;
 
@@ -2256,7 +2454,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) {
@@ -2313,6 +2513,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;
@@ -2330,6 +2531,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:
@@ -2340,6 +2545,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
@@ -2366,8 +2572,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';
@@ -2431,7 +2642,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;
@@ -2573,7 +2784,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;
 
@@ -2653,6 +2864,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;
@@ -2665,7 +2878,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;
 
@@ -2748,7 +2965,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;
 
@@ -2765,7 +2982,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;
@@ -2809,10 +3025,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;
 }
@@ -2932,4 +3150,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,
 };