flash/nor/kinetis: add support for NXP S32K series

S32K General-Purpose Microcontrollers

Scalable, low-power Arm® Cortex®-M series-based microcontrollers AEC-Q100
qualified with advanced safety and security and software support for
industrial and automotive ASIL B/D applications in body, zone control,
and electrification.

Change-Id: I4143258535437c18b81802436267bfd561de9d31
Signed-off-by: David Vidrie Leon <davidvidrie@geotab.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/8012
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Tested-by: jenkins
This commit is contained in:
David Vidrie Leon 2022-04-27 14:45:04 -04:00 committed by Antonio Borneo
parent 0886730f5a
commit a77d280bd0
3 changed files with 334 additions and 21 deletions

View File

@ -6824,16 +6824,23 @@ nor is Chip Erase (only Sector Erase is implemented).}
@deffn {Flash Driver} {kinetis}
@cindex kinetis
Kx, KLx, KVx and KE1x members of the Kinetis microcontroller family
from NXP (former Freescale) include
internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically
Several microcontrollers from NXP (former Freescale), including
Kx, KLx, KVx and KE1x members of the Kinetis family,
and S32K11x/S32K14x microcontrollers, include
internal flash and use ARM Cortex-M0+ or M4 cores.
Kinetis and S32K1 families use incompatible
identification registers, so the driver assumes Kinetis and requires
a driver option to indicate S32K1 is to be used.
Within the familiy, the driver automatically
recognizes flash size and a number of flash banks (1-4) using the chip
identification register, and autoconfigures itself.
Use kinetis_ke driver for KE0x and KEAx devices.
The @var{kinetis} driver defines option:
@itemize
@item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries two known locations if option is omitted.
@item -s32k select S32K11x/S32K14x microcontroller flash support.
@item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries known locations if option is omitted.
@end itemize
@example
@ -6882,6 +6889,7 @@ command completes.
@deffn {Command} {kinetis nvm_partition}
For FlexNVM devices only (KxxDX and KxxFX).
Not supported (yet) on S32K1 devices.
Command shows or sets data flash or EEPROM backup size in kilobytes,
sets two EEPROM blocks sizes in bytes and enables/disables loading
of EEPROM contents to FlexRAM during reset.

View File

@ -80,6 +80,7 @@
#define FLEXRAM 0x14000000
#define MSCM_OCMDR0 0x40001400
#define MSCM_OCMDR1 0x40001404
#define FMC_PFB01CR 0x4001f004
#define FTFX_FSTAT 0x40020000
#define FTFX_FCNFG 0x40020001
@ -230,6 +231,28 @@
#define KINETIS_SDID_PROJECTID_KE1XF 0x00000080
#define KINETIS_SDID_PROJECTID_KE1XZ 0x00000100
/* The S32K series uses a different, incompatible SDID layout :
* Bit 31-28 : GENERATION
* Bit 27-24 : SUBSERIES
* Bit 23-20 : DERIVATE
* Bit 19-16 : RAMSIZE
* Bit 15-12 : REVID
* Bit 11-8 : PACKAGE
* Bit 7-0 : FEATURES
*/
#define KINETIS_SDID_S32K_SERIES_MASK 0xFF000000 /* GENERATION + SUBSERIES */
#define KINETIS_SDID_S32K_SERIES_K11X 0x11000000
#define KINETIS_SDID_S32K_SERIES_K14X 0x14000000
#define KINETIS_SDID_S32K_DERIVATE_MASK 0x00F00000
#define KINETIS_SDID_S32K_DERIVATE_KXX2 0x00200000
#define KINETIS_SDID_S32K_DERIVATE_KXX3 0x00300000
#define KINETIS_SDID_S32K_DERIVATE_KXX4 0x00400000
#define KINETIS_SDID_S32K_DERIVATE_KXX5 0x00500000
#define KINETIS_SDID_S32K_DERIVATE_KXX6 0x00600000
#define KINETIS_SDID_S32K_DERIVATE_KXX8 0x00800000
struct kinetis_flash_bank {
struct kinetis_chip *k_chip;
bool probed;
@ -275,6 +298,11 @@ struct kinetis_chip {
uint32_t progr_accel_ram;
uint32_t sim_base;
enum {
CT_KINETIS = 0,
CT_S32K,
} chip_type;
enum {
FS_PROGRAM_SECTOR = 1,
FS_PROGRAM_LONGWORD = 2,
@ -290,6 +318,7 @@ struct kinetis_chip {
KINETIS_CACHE_K, /* invalidate using FMC->PFB0CR/PFB01CR */
KINETIS_CACHE_L, /* invalidate using MCM->PLACR */
KINETIS_CACHE_MSCM, /* devices like KE1xF, invalidate MSCM->OCMDR0 */
KINETIS_CACHE_MSCM2, /* devices like S32K, invalidate MSCM->OCMDR0 and MSCM->OCMDR1 */
} cache_type;
enum {
@ -392,6 +421,7 @@ 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_probe_chip_s32k(struct kinetis_chip *k_chip);
static int kinetis_auto_probe(struct flash_bank *bank);
@ -877,6 +907,8 @@ static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const cha
if (strcmp(argv[i], "-sim-base") == 0) {
if (i + 1 < argc)
k_chip->sim_base = strtoul(argv[++i], NULL, 0);
} else if (strcmp(argv[i], "-s32k") == 0) {
k_chip->chip_type = CT_S32K;
} else
LOG_ERROR("Unsupported flash bank option %s", argv[i]);
}
@ -1140,7 +1172,13 @@ static int kinetis_disable_wdog(struct kinetis_chip *k_chip)
int retval;
if (!k_chip->probed) {
retval = kinetis_probe_chip(k_chip);
switch (k_chip->chip_type) {
case CT_S32K:
retval = kinetis_probe_chip_s32k(k_chip);
break;
default:
retval = kinetis_probe_chip(k_chip);
}
if (retval != ERROR_OK)
return retval;
}
@ -1639,6 +1677,12 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip)
/* disable data prefetch and flash speculate */
break;
case KINETIS_CACHE_MSCM2:
target_write_u32(target, MSCM_OCMDR0, 0x30);
target_write_u32(target, MSCM_OCMDR1, 0x30);
/* disable data prefetch and flash speculate */
break;
default:
break;
}
@ -2048,6 +2092,174 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
}
static int kinetis_probe_chip_s32k(struct kinetis_chip *k_chip)
{
int result;
uint8_t fcfg1_eesize, fcfg1_depart;
uint32_t ee_size = 0;
uint32_t pflash_size_k, nvm_size_k, dflash_size_k;
unsigned int generation = 0, subseries = 0, derivate = 0;
struct target *target = k_chip->target;
k_chip->probed = false;
k_chip->pflash_sector_size = 0;
k_chip->pflash_base = 0;
k_chip->nvm_base = 0x10000000;
k_chip->progr_accel_ram = FLEXRAM;
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
k_chip->watchdog_type = KINETIS_WDOG32_KE1X;
if (k_chip->sim_base == 0)
k_chip->sim_base = SIM_BASE;
result = target_read_u32(target, k_chip->sim_base + SIM_SDID_OFFSET, &k_chip->sim_sdid);
if (result != ERROR_OK)
return result;
generation = (k_chip->sim_sdid) >> 28 & 0x0f;
subseries = (k_chip->sim_sdid) >> 24 & 0x0f;
derivate = (k_chip->sim_sdid) >> 20 & 0x0f;
switch (k_chip->sim_sdid & KINETIS_SDID_S32K_SERIES_MASK) {
case KINETIS_SDID_S32K_SERIES_K11X:
k_chip->cache_type = KINETIS_CACHE_L;
k_chip->num_pflash_blocks = 1;
k_chip->num_nvm_blocks = 1;
/* Non-interleaved */
k_chip->max_flash_prog_size = 512;
switch (k_chip->sim_sdid & KINETIS_SDID_S32K_DERIVATE_MASK) {
case KINETIS_SDID_S32K_DERIVATE_KXX6:
/* S32K116 CPU 48Mhz Flash 128KB RAM 17KB+2KB */
/* Non-Interleaved */
k_chip->pflash_size = 128 << 10;
k_chip->pflash_sector_size = 2 << 10;
/* Non-Interleaved */
k_chip->nvm_size = 32 << 10;
k_chip->nvm_sector_size = 2 << 10;
break;
case KINETIS_SDID_S32K_DERIVATE_KXX8:
/* S32K118 CPU 80Mhz Flash 256KB+32KB RAM 32KB+4KB */
/* Non-Interleaved */
k_chip->pflash_size = 256 << 10;
k_chip->pflash_sector_size = 2 << 10;
/* Non-Interleaved */
k_chip->nvm_size = 32 << 10;
k_chip->nvm_sector_size = 2 << 10;
break;
}
break;
case KINETIS_SDID_S32K_SERIES_K14X:
k_chip->cache_type = KINETIS_CACHE_MSCM2;
k_chip->num_pflash_blocks = 1;
k_chip->num_nvm_blocks = 1;
/* Non-interleaved */
k_chip->max_flash_prog_size = 512;
switch (k_chip->sim_sdid & KINETIS_SDID_S32K_DERIVATE_MASK) {
case KINETIS_SDID_S32K_DERIVATE_KXX2:
case KINETIS_SDID_S32K_DERIVATE_KXX3:
/* S32K142/S32K142W CPU 80Mhz Flash 256KB+64KB RAM 32KB+4KB */
/* Non-Interleaved */
k_chip->pflash_size = 256 << 10;
k_chip->pflash_sector_size = 2 << 10;
/* Non-Interleaved */
k_chip->nvm_size = 64 << 10;
k_chip->nvm_sector_size = 2 << 10;
break;
case KINETIS_SDID_S32K_DERIVATE_KXX4:
case KINETIS_SDID_S32K_DERIVATE_KXX5:
/* S32K144/S32K144W CPU 80Mhz Flash 512KB+64KB RAM 64KB+4KB */
/* Interleaved */
k_chip->pflash_size = 512 << 10;
k_chip->pflash_sector_size = 4 << 10;
/* Non-Interleaved */
k_chip->nvm_size = 64 << 10;
k_chip->nvm_sector_size = 2 << 10;
break;
case KINETIS_SDID_S32K_DERIVATE_KXX6:
/* S32K146 CPU 80Mhz Flash 1024KB+64KB RAM 128KB+4KB */
/* Interleaved */
k_chip->pflash_size = 1024 << 10;
k_chip->pflash_sector_size = 4 << 10;
k_chip->num_pflash_blocks = 2;
/* Non-Interleaved */
k_chip->nvm_size = 64 << 10;
k_chip->nvm_sector_size = 2 << 10;
break;
case KINETIS_SDID_S32K_DERIVATE_KXX8:
/* S32K148 CPU 80Mhz Flash 1536KB+512KB RAM 256KB+4KB */
/* Interleaved */
k_chip->pflash_size = 1536 << 10;
k_chip->pflash_sector_size = 4 << 10;
k_chip->num_pflash_blocks = 3;
/* Interleaved */
k_chip->nvm_size = 512 << 10;
k_chip->nvm_sector_size = 4 << 10;
/* Interleaved */
k_chip->max_flash_prog_size = 1 << 10;
break;
}
break;
default:
LOG_ERROR("Unsupported S32K1xx-series");
}
if (k_chip->pflash_sector_size == 0) {
LOG_ERROR("MCU is unsupported, SDID 0x%08" PRIx32, k_chip->sim_sdid);
return ERROR_FLASH_OPER_UNSUPPORTED;
}
result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &k_chip->sim_fcfg1);
if (result != ERROR_OK)
return result;
k_chip->sim_fcfg2 = 0; /* S32K1xx does not implement FCFG2 register. */
fcfg1_depart = (k_chip->sim_fcfg1 >> 12) & 0x0f;
fcfg1_eesize = (k_chip->sim_fcfg1 >> 16) & 0x0f;
if (fcfg1_eesize <= 9)
ee_size = (16 << (10 - fcfg1_eesize));
if ((fcfg1_depart & 0x8) == 0) {
/* Binary 0xxx values encode the amount reserved for EEPROM emulation. */
if (fcfg1_depart)
k_chip->dflash_size = k_chip->nvm_size - (4096 << fcfg1_depart);
else
k_chip->dflash_size = k_chip->nvm_size;
} else {
/* Binary 1xxx valued encode the DFlash size. */
if (fcfg1_depart & 0x7)
k_chip->dflash_size = 4096 << (fcfg1_depart & 0x7);
else
k_chip->dflash_size = 0;
}
snprintf(k_chip->name, sizeof(k_chip->name), "S32K%u%u%u",
generation, subseries, derivate);
pflash_size_k = k_chip->pflash_size / 1024;
dflash_size_k = k_chip->dflash_size / 1024;
LOG_INFO("%s detected: %u flash blocks", k_chip->name, k_chip->num_pflash_blocks + k_chip->num_nvm_blocks);
LOG_INFO("%u PFlash banks: %" PRIu32 " KiB total", k_chip->num_pflash_blocks, pflash_size_k);
nvm_size_k = k_chip->nvm_size / 1024;
if (k_chip->num_nvm_blocks) {
LOG_INFO("%u FlexNVM banks: %" PRIu32 " KiB total, %" PRIu32 " KiB available as data flash, %"
PRIu32 " bytes FlexRAM",
k_chip->num_nvm_blocks, nvm_size_k, dflash_size_k, ee_size);
}
k_chip->probed = true;
if (create_banks)
kinetis_create_missing_banks(k_chip);
return ERROR_OK;
}
static int kinetis_probe_chip(struct kinetis_chip *k_chip)
{
int result;
@ -2693,7 +2905,13 @@ static int kinetis_probe(struct flash_bank *bank)
k_bank->probed = false;
if (!k_chip->probed) {
result = kinetis_probe_chip(k_chip);
switch (k_chip->chip_type) {
case CT_S32K:
result = kinetis_probe_chip_s32k(k_chip);
break;
default:
result = kinetis_probe_chip(k_chip);
}
if (result != ERROR_OK)
return result;
}
@ -2765,23 +2983,26 @@ static int kinetis_probe(struct flash_bank *bank)
return ERROR_FLASH_BANK_INVALID;
}
fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01);
fcfg2_maxaddr0 = (uint8_t)((k_chip->sim_fcfg2 >> 24) & 0x7f);
fcfg2_maxaddr1 = (uint8_t)((k_chip->sim_fcfg2 >> 16) & 0x7f);
/* S32K1xx does not implement FCFG2 register. Skip checks. */
if (k_chip->chip_type != CT_S32K) {
fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01);
fcfg2_maxaddr0 = (uint8_t)((k_chip->sim_fcfg2 >> 24) & 0x7f);
fcfg2_maxaddr1 = (uint8_t)((k_chip->sim_fcfg2 >> 16) & 0x7f);
if (k_bank->bank_number == 0 && k_chip->fcfg2_maxaddr0_shifted != bank->size)
LOG_WARNING("MAXADDR0 0x%02" PRIx8 " check failed,"
" please report to OpenOCD mailing list", fcfg2_maxaddr0);
if (k_bank->bank_number == 0 && k_chip->fcfg2_maxaddr0_shifted != bank->size)
LOG_WARNING("MAXADDR0 0x%02" PRIx8 " check failed,"
" please report to OpenOCD mailing list", fcfg2_maxaddr0);
if (fcfg2_pflsh) {
if (k_bank->bank_number == 1 && k_chip->fcfg2_maxaddr1_shifted != bank->size)
LOG_WARNING("MAXADDR1 0x%02" PRIx8 " check failed,"
" please report to OpenOCD mailing list", fcfg2_maxaddr1);
} else {
if (k_bank->bank_number == first_nvm_bank
&& k_chip->fcfg2_maxaddr1_shifted != k_chip->dflash_size)
LOG_WARNING("FlexNVM MAXADDR1 0x%02" PRIx8 " check failed,"
" please report to OpenOCD mailing list", fcfg2_maxaddr1);
if (fcfg2_pflsh) {
if (k_bank->bank_number == 1 && k_chip->fcfg2_maxaddr1_shifted != bank->size)
LOG_WARNING("MAXADDR1 0x%02" PRIx8 " check failed,"
" please report to OpenOCD mailing list", fcfg2_maxaddr1);
} else {
if (k_bank->bank_number == first_nvm_bank
&& k_chip->fcfg2_maxaddr1_shifted != k_chip->dflash_size)
LOG_WARNING("FlexNVM MAXADDR1 0x%02" PRIx8 " check failed,"
" please report to OpenOCD mailing list", fcfg2_maxaddr1);
}
}
free(bank->sectors);
@ -2932,6 +3153,11 @@ COMMAND_HANDLER(kinetis_nvm_partition)
k_chip = kinetis_get_chip(target);
if (k_chip->chip_type == CT_S32K) {
LOG_ERROR("NVM partition not supported on S32K1xx (yet).");
return ERROR_FAIL;
}
if (CMD_ARGC >= 2) {
if (strcmp(CMD_ARGV[0], "dataflash") == 0)
sz_type = DF_SIZE;

79
tcl/target/s32k.cfg Normal file
View File

@ -0,0 +1,79 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Freescale S32K devices
# Similar to Kinetis Kx series devices.
#
source [find target/swj-dp.tcl]
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME s32k
}
# Work-area is a space in RAM used for flash programming
# By default use 4kB
if { [info exists WORKAREASIZE] } {
set _WORKAREASIZE $WORKAREASIZE
} else {
set _WORKAREASIZE 0x1000
}
if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID
} else {
set _CPUTAPID 0x0995001d
}
swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.pflash
flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME -s32k
kinetis create_banks
adapter speed 1000
reset_config srst_nogate
if {[using_hla]} {
echo ""
echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!"
echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions."
echo " A high level adapter (like a ST-Link) you are currently using cannot access"
echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your"
echo " configuration. Also security locked state of the device will not be reported."
echo " Expect problems connecting to a blank device without boot ROM."
echo ""
echo " Be very careful as you can lock the device though there is no way to unlock"
echo " it without mass erase. Don't set write protection on the first block."
echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!"
echo ""
} else {
# Detect secured MCU or boot lock-up in RESET/WDOG loop
$_TARGETNAME configure -event examine-fail {
kinetis mdm check_security
}
# During RESET/WDOG loop the target is sometimes falsely examined
$_TARGETNAME configure -event examine-end {
kinetis mdm check_security
}
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
}
# Disable watchdog not to disturb OpenOCD algorithms running on MCU
# (e.g. armv7m_checksum_memory() in verify_image)
# Flash driver also disables watchdog before FTFA flash programming.
$_TARGETNAME configure -event reset-init {
kinetis disable_wdog
}