#define SIM_SOPT1 0x40047000
#define SIM_FCFG1 0x4004804c
#define SIM_FCFG2 0x40048050
-#define WDOG_STCTRH 0x40052000
+#define SIM_COPC 0x40048100
+#define WDOG_BASE 0x40052000
+#define WDOG32_KE1X 0x40052000
+#define WDOG32_KL28 0x40076000
#define SMC_PMCTRL 0x4007E001
#define SMC_PMSTAT 0x4007E003
#define MCM_PLACR 0xF000300C
+/* Offsets */
+#define WDOG_STCTRLH_OFFSET 0
+#define WDOG32_CS_OFFSET 0
+
/* Values */
#define PM_STAT_RUN 0x01
#define PM_STAT_VLPR 0x04
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,
} 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;
+
char name[40];
unsigned num_banks;
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);
}
-/* 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_IN);
+ 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;
}
{
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;
+ }
}
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);
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;
/* 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;
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;
cpu_mhz = 180;
break;
/* 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))
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;
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",