Kinetis KE04: Flash and debug support

Support for Kinetis KE04 8KiB, 64KiB and 128KiB variants in nxpke04.c
Target monitor commands for sector and mass erase.
Changes to kinetis.c MDM-AP target to support KE04.
Only KE04Z8 tested in HW.
This commit is contained in:
newbrain 2018-06-22 15:44:17 +02:00
parent cdb04a4214
commit 8de1b45c85
5 changed files with 401 additions and 3 deletions

View File

@ -48,6 +48,7 @@ SRC = \
morse.c \
msp432.c \
nrf51.c \
nxpke04.c \
platform.c \
sam3x.c \
sam4l.c \

View File

@ -344,6 +344,7 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
PROBE(kinetis_probe);
PROBE(efm32_probe);
PROBE(msp432_probe);
PROBE(ke04_probe);
PROBE(lpc17xx_probe);
#undef PROBE

View File

@ -335,9 +335,11 @@ static int kl_gen_flash_done(struct target_flash *f)
#define KINETIS_MDM_IDR_KZ03 0x1c0020
static bool kinetis_mdm_cmd_erase_mass(target *t);
static bool kinetis_mdm_cmd_ke04_mode(target *t);
const struct command_s kinetis_mdm_cmd_list[] = {
{"erase_mass", (cmd_handler)kinetis_mdm_cmd_erase_mass, "Erase entire flash memory"},
{"ke04_mode", (cmd_handler)kinetis_mdm_cmd_ke04_mode, "Allow erase for KE04"},
{NULL, NULL, NULL}
};
@ -355,7 +357,7 @@ enum target_halt_reason mdm_halt_poll(target *t, target_addr *watch)
void kinetis_mdm_probe(ADIv5_AP_t *ap)
{
switch(ap->idr) {
case KINETIS_MDM_IDR_KZ03:
case KINETIS_MDM_IDR_KZ03: /* Also valid for KE04, no way to check! */
case KINETIS_MDM_IDR_K22F:
break;
default:
@ -392,21 +394,40 @@ void kinetis_mdm_probe(ADIv5_AP_t *ap)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
/* This is needed as a separate command, as there's no way to *
* tell a KE04 from other kinetis in kinetis_mdm_probe() */
static bool ke04_mode = false;
static bool kinetis_mdm_cmd_ke04_mode(target *t)
{
/* Set a flag to ignore part of the status and assert reset */
ke04_mode = true;
tc_printf(t, "Mass erase for KE04 now allowed\n");
return true;
}
static bool kinetis_mdm_cmd_erase_mass(target *t)
{
ADIv5_AP_t *ap = t->priv;
/* Keep the MCU in reset as stated in KL25PxxM48SF0RM */
if(ke04_mode)
adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_SYS_RESET);
uint32_t status, control;
status = adiv5_ap_read(ap, MDM_STATUS);
control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%"PRIx32")\n", status);
if (!(status & MDM_STATUS_MASS_ERASE_ENABLED)) {
/* This flag does not exist on KE04 */
if (!(status & MDM_STATUS_MASS_ERASE_ENABLED) && !ke04_mode) {
tc_printf(t, "ERROR: Mass erase disabled!\n");
return false;
}
/* Flag is not persistent */
ke04_mode = false;
if (!(status & MDM_STATUS_FLASH_READY)) {
tc_printf(t, "ERROR: Flash not ready!\n");
return false;

375
src/target/nxpke04.c Normal file
View File

@ -0,0 +1,375 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2015 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* Copyright (C) 2018 newbrain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file implements KE04 target specific functions providing
* the XML memory map and Flash memory programming.
*
* An additional command to manually erase a single sector is also provided
*
* While very similar to other Kinetis, the differences in the Flash Module
* registers and the security byte warrant a separate set of routines.
*
* According to Freescale document MKE04P24M48SF0RM and MKE04P80M48SF0RM:
* KE04 Sub-Family Reference Manual
*
* And document MKE04P24M48SF0 and MKE04P80M48SF0:
* KE04 Sub-Family Data Sheet
*/
#include "general.h"
#include "target.h"
#include "target_internal.h"
/* KE04 registers and constants */
/* Memory base addresses */
#define RAM_BASE_ADDR 0x20000000u
#define FLASH_BASE_ADDR 0x00000000u
/* ID register and related constants */
#define SIM_SRSID 0x40048000u
#define SRSID_KE04_MASK 0xFF00u
#define SRSID_KE04_FAMILY 0x0400u
#define SRSID_PIN_MASK 0x000Fu
#define SRSID_PIN__8 0x0000u
#define SRSID_PIN_16 0x0001u
#define SRSID_PIN_20 0x0002u
#define SRSID_PIN_24 0x0003u
#define SRSID_PIN_32 0x0004u
#define SRSID_PIN_44 0x0005u
#define SRSID_PIN_48 0x0006u
#define SRSID_PIN_64 0x0007u
#define SRSID_PIN_80 0x0008u
#define SRSID_PIN100 0x000Au
/* Flash Memory Module registers */
#define FTMRE_BASE 0x40020000u
#define FTMRE_FCCOBIX (FTMRE_BASE + 0x01u)
#define FTMRE_FSEC (FTMRE_BASE + 0x02u)
#define FTMRE_FCLKDIV (FTMRE_BASE + 0x03u)
#define FTMRE_FSTAT (FTMRE_BASE + 0x05u)
#define FTMRE_FCNFG (FTMRE_BASE + 0x07u)
#define FTMRE_FCCOB (FTMRE_BASE + 0x08u)
#define FTMRE_FCCOBLO (FTMRE_BASE + 0x08u)
#define FTMRE_FCCOBHI (FTMRE_BASE + 0x09u)
#define FTMRE_FPROT (FTMRE_BASE + 0x0Bu)
#define FTMRE_FOPT (FTMRE_BASE + 0x0Fu)
/* FTMRE_FSTAT flags */
#define FTMRE_FSTAT_CCIF 0x80u
#define FTMRE_FSTAT_ACCERR 0x20u
#define FTMRE_FSTAT_FPVIOL 0x10u
#define FTMRE_FSTAT_MGBUSY 0x08u
#define FTMRE_FSTAT_MGSTAT1 0x02u
#define FTMRE_FSTAT_MGSTAT0 0x01u
/* Flash Memory Module commands */
#define CMD_PROGRAM_FLASH_32 0x00u /* Special placeholder */
#define CMD_ERASE_VERIFY_ALL_BLOCKS 0x01u /* Unused */
#define CMD_ERASE_VERIFY_BLOCK 0x02u /* Unused */
#define CMD_ERASE_VERIFY_SECTION 0x03u /* Unused */
#define CMD_READ_ONCE 0x04u /* Unused */
#define CMD_PROGRAM_FLASH 0x06u /* Used */
#define CMD_PROGRAM_ONCE 0x07u /* Unused */
#define CMD_ERASE_ALL_BLOCKS 0x08u /* Unused */
#define CMD_ERASE_FLASH_BLOCK 0x09u /* Unused */
#define CMD_ERASE_FLASH_SECTOR 0x0Au /* Used */
#define CMD_UNSECURE_FLASH 0x0Bu /* Used */
#define CMD_VERIFY_BACKDOOR_ACCESS_KEY 0x0Cu /* Unused */
#define CMD_SET_USER_MARGIN_LEVEL 0x0Du /* Unused */
#define CMD_SET_FACTORY_MARGIN_LEVEL 0x0Eu /* Unused */
/* Flash Memory Module write and erase sizes */
#define KE04_WRITE_LEN 8
#define KE04_SECTOR_SIZE 0x200u
/* Security byte */
#define FLASH_SECURITY_BYTE_ADDRESS 0x0000040Eu
#define FLASH_SECURITY_BYTE_UNSECURED 0xFEu
#define FLASH_SECURITY_WORD_ADDRESS 0x0000040Cu
#define FLASH_SECURITY_WORD_UNSECURED 0xFFFEFFFFu
/* Length in 16bit words of flash commands */
static const uint8_t cmdLen[] = {
4, 1, 2, 3, 6, 0, 6, 6, 1, 2, 2, 1, 5, 3, 3};
/* Flash routines */
static bool ke04_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]);
static int ke04_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int ke04_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static int ke04_flash_done(struct target_flash *f);
/* Target specific commands */
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[]);
static bool ke04_cmd_sector_erase(target *t, int argc, char *argv[]);
static bool ke04_cmd_mass_erase(target *t, int argc, char *argv[]);
static bool unsafe_enabled;
const struct command_s ke_cmd_list[] = {
{"unsafe", (cmd_handler)kinetis_cmd_unsafe, "Allow programming security byte (enable|disable)"},
{"sector_erase", (cmd_handler)ke04_cmd_sector_erase, "Erase sector containing given address"},
{"mass_erase", (cmd_handler)ke04_cmd_mass_erase, "Erase the whole flash"},
{NULL, NULL, NULL}
};
static bool ke04_cmd_sector_erase(target *t, int argc, char *argv[])
{
if (argc < 2)
tc_printf(t, "usage: monitor sector_erase <addr>\n");
char *eos;
struct target_flash *f = t->flash;
uint32_t addr = strtoul(argv[1], &eos, 0);
/* check that addr is a valid number and inside the flash range */
if ((*eos != 0) || (addr < f->start) || (addr >= f->start+f->length)) {
/* Address not in range */
tc_printf(t, "Invalid sector address\n");
return false;
}
/* Erase and verify the given sector */
ke04_command(t, CMD_ERASE_FLASH_SECTOR, addr, NULL);
/* Adjust security byte if needed */
ke04_flash_done(f);
return true;
}
static bool ke04_cmd_mass_erase(target *t, int argc, char *argv[])
{
(void)argc;
(void)argv;
/* Erase and verify the whole flash */
ke04_command(t, CMD_ERASE_ALL_BLOCKS, 0, NULL);
/* Adjust security byte if needed */
ke04_flash_done(t->flash);
return true;
}
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[])
{
if (argc == 1)
tc_printf(t, "Allow programming security byte: %s\n",
unsafe_enabled ? "enabled" : "disabled");
else
unsafe_enabled = argv[1][0] == 'e';
return true;
}
bool ke04_probe(target *t)
{
uint32_t ramsize;
uint32_t flashsize;
volatile uint32_t dummy;
/* Read the higher 16bits of System Reset Status and ID Register */
uint32_t srsid = target_mem_read32(t, SIM_SRSID) >> 16;
/* Is this a Kinetis KE04 family MCU? */
if ((srsid & SRSID_KE04_MASK) != SRSID_KE04_FAMILY)
return false;
/* KE04Z8 only comes in 16, 20, and 24 pins */
switch (srsid & SRSID_PIN_MASK) {
case SRSID_PIN_16:
case SRSID_PIN_20:
case SRSID_PIN_24:
/* We have a KE04Z8 */
t->driver = "Kinetis KE04Z8Vxxxx";
flashsize = 0x2000u; /* 8 kilobytes */
ramsize = 0x400u; /* 1 kilobyte */
break;
/* KE04Z64 and KE04Z128 only come in 44, 64, and 80 pins */
case SRSID_PIN_44:
case SRSID_PIN_64:
case SRSID_PIN_80:
/* We have either a KE04Z64 or 128 */
/* Try to read a flash address not available in a Z64 */
dummy = target_mem_read32(t, 0x00010000u);
(void)dummy;
if (target_check_error(t)) {
/* Read failed: we have a 64 */
t->driver = "Kinetis KE04Z64Vxxxx";
flashsize = 0x10000u; /* 64 kilobytes */
ramsize = 0x2000u; /* 8 kilobytes */
} else {
/* Read succeeded: we have a 128 */
t->driver = "Kinetis KE04Z128Vxxxx";
flashsize = 0x20000u; /* 128 kilobytes */
ramsize = 0x4000u; /* 16 kilobytes */
}
break;
/* Unknown number of pins, not a supported KE04 */
default:
return false;
}
/* Add low (1/4) and high (3/4) RAM */
ramsize /= 4; /* Amount before RAM_BASE_ADDR */
target_add_ram(t, RAM_BASE_ADDR - ramsize, ramsize); /* Lower RAM */
ramsize *= 3; /* Amount after RAM_BASE_ADDR */
target_add_ram(t, RAM_BASE_ADDR, ramsize); /* Higher RAM */
/* Add flash, all KE04 have same write and erase size */
struct target_flash *f = calloc(1, sizeof(*f));
f->start = FLASH_BASE_ADDR;
f->length = flashsize;
f->blocksize = KE04_SECTOR_SIZE;
f->erase = ke04_flash_erase;
f->write = ke04_flash_write;
f->done = ke04_flash_done;
f->erased = 0xFFu;
target_add_flash(t, f);
/* Add target specific commands */
unsafe_enabled = false;
target_add_commands(t, ke_cmd_list, t->driver);
return true;
}
static bool
ke04_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8])
{
uint8_t fstat;
/* Set FCLKDIV to 0x17 for 24MHz (default at reset) */
uint8_t fclkdiv = target_mem_read8(t, FTMRE_FCLKDIV);
if( (fclkdiv & 0x1Fu) != 0x17u ) {
/* Wait for CCIF to be high */
do {
fstat = target_mem_read8(t, FTMRE_FSTAT);
} while (!(fstat & FTMRE_FSTAT_CCIF));
/* Write correct value */
target_mem_write8(t, FTMRE_FCLKDIV, 0x17u);
}
/* clear errors unconditionally, so we can start a new operation */
target_mem_write8(t,FTMRE_FSTAT,(FTMRE_FSTAT_ACCERR | FTMRE_FSTAT_FPVIOL));
/* Wait for CCIF to be high */
do {
fstat = target_mem_read8(t, FTMRE_FSTAT);
} while (!(fstat & FTMRE_FSTAT_CCIF));
/* Write the flash command and the needed parameters */
uint8_t fccobix = 0;
/* Trim address, probably not needed */
addr &= 0x00FFFFFF;
uint8_t cmdL = cmdLen[cmd];
/* Special case: single 32bits word flashing */
if(cmd == CMD_PROGRAM_FLASH_32)
cmd = CMD_PROGRAM_FLASH;
uint16_t cmdV = (cmd << 8) | (addr >> 16);
/* Write command to FCCOB array */
target_mem_write8(t, FTMRE_FCCOBIX, fccobix++);
target_mem_write16(t, FTMRE_FCCOB, cmdV);
/* Write first argument (low partof address) */
if (cmdL >= 1) {
target_mem_write8(t, FTMRE_FCCOBIX, fccobix++);
target_mem_write16(t, FTMRE_FCCOB, addr & 0xFFFFu);
}
/* Write one or two 32 bit words of data */
uint8_t dataix = 0;
for ( ; fccobix < cmdL; fccobix++) {
target_mem_write8(t, FTMRE_FCCOBIX, fccobix);
target_mem_write16(t, FTMRE_FCCOB, *(uint16_t *)&data[dataix]);
dataix += 2;
}
/* Enable execution by clearing CCIF */
target_mem_write8(t, FTMRE_FSTAT, FTMRE_FSTAT_CCIF);
/* Wait for execution to complete */
do {
fstat = target_mem_read8(t, FTMRE_FSTAT);
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTMRE_FSTAT_ACCERR | FTMRE_FSTAT_FPVIOL)) {
return false;
}
} while (!(fstat & FTMRE_FSTAT_CCIF));
return true;
}
static int ke04_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
while (len) {
if (ke04_command(f->t, CMD_ERASE_FLASH_SECTOR, addr, NULL)) {
/* Different targets have different flash erase sizes */
len -= f->blocksize;
addr += f->blocksize;
} else {
return 1;
}
}
return 0;
}
static int ke04_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
{
/* Ensure we don't write something horrible over the security byte */
if (!unsafe_enabled &&
(dest <= FLASH_SECURITY_BYTE_ADDRESS) &&
((dest + len) > FLASH_SECURITY_BYTE_ADDRESS)) {
((uint8_t*)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] =
FLASH_SECURITY_BYTE_UNSECURED;
}
while (len) {
if (ke04_command(f->t, CMD_PROGRAM_FLASH, dest, src)) {
len -= KE04_WRITE_LEN;
dest += KE04_WRITE_LEN;
src += KE04_WRITE_LEN;
} else {
return 1;
}
}
return 0;
}
static int ke04_flash_done(struct target_flash *f)
{
if (unsafe_enabled)
return 0;
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) ==
FLASH_SECURITY_BYTE_UNSECURED)
return 0;
/* Load the security byte from its field */
/* Note: Cumulative programming is not allowed according to the RM */
uint32_t val = target_mem_read32(f->t, FLASH_SECURITY_WORD_ADDRESS);
val = (val & 0xff00ffff) | (FLASH_SECURITY_BYTE_UNSECURED << 16);
ke04_command(f->t, CMD_PROGRAM_FLASH_32,
FLASH_SECURITY_WORD_ADDRESS, (uint8_t *)&val);
return 0;
}

View File

@ -178,5 +178,5 @@ bool samd_probe(target *t);
bool kinetis_probe(target *t);
bool efm32_probe(target *t);
bool msp432_probe(target *t);
bool ke04_probe(target *t);
#endif