#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
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;
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);
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;
}
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) {
}
+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;
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';
}
-/* 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(®_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(®_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;
#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;
/* 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;
}
}
-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;
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;
{
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;
+ }
}
{
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;
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) {
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");
}
}
- 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 */
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);
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;
{
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;
}
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);
}
return result;
- } else
+ } else {
/* no FCF fiddling, normal write */
return kinetis_write_inner(bank, buffer, offset, count);
+ }
}
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;
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:
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:
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:
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:
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:
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");
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;
/* 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;
/* 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");
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:
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:
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;
/* 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);
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;
/* 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;
/* 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:
/* 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;
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;
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:
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",
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",
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;
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) {
case 0x06:
k_chip->dflash_size = k_chip->nvm_size - (4096 << fcfg1_depart);
break;
+ case 0x07:
case 0x08:
k_chip->dflash_size = 0;
break;
}
switch (fcfg1_pfsize) {
+ case 0x00:
+ k_chip->pflash_size = 8192;
+ break;
+ case 0x01:
case 0x03:
case 0x05:
case 0x07:
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
/* 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';
* 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;
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);
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;
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;
}
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;
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;
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;
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;
}
.usage = "",
.handler = kinetis_mdm_mass_erase,
},
- { .name = "reset",
+ {
+ .name = "reset",
.mode = COMMAND_EXEC,
.help = "Issue a reset via the MDM-AP",
.usage = "",
-struct flash_driver kinetis_flash = {
+const struct flash_driver kinetis_flash = {
.name = "kinetis",
.commands = kinetis_command_handler,
.flash_bank_command = kinetis_flash_bank_command,
.erase_check = kinetis_blank_check,
.protect_check = kinetis_protect_check,
.info = kinetis_info,
+ .free_driver_priv = kinetis_free_driver_priv,
};