{ 4<<10, 4<<10, 4 }
};
+/* Addressess */
+#define FLEXRAM 0x14000000
+#define FTFx_FSTAT 0x40020000
+#define FTFx_FCNFG 0x40020001
+#define FTFx_FCCOB3 0x40020004
+#define FTFx_FPROT3 0x40020010
+#define SIM_SDID 0x40048024
+#define SIM_FCFG1 0x4004804c
+#define SIM_FCFG2 0x40048050
+
+/* Commands */
+#define FTFx_CMD_BLOCKSTAT 0x00
+#define FTFx_CMD_SECTSTAT 0x01
+#define FTFx_CMD_LWORDPROG 0x06
+#define FTFx_CMD_SECTERASE 0x09
+#define FTFx_CMD_SECTWRITE 0x0b
+#define FTFx_CMD_SETFLEXRAM 0x81
+
struct kinetis_flash_bank {
unsigned granularity;
unsigned bank_ordinal;
uint32_t fprot, psec;
int i, b;
- /* read protection register FTFx_FPROT */
- result = target_read_memory(bank->target, 0x40020010, 1, 4, buffer);
+ /* read protection register */
+ result = target_read_memory(bank->target, FTFx_FPROT3, 1, 4, buffer);
if (result != ERROR_OK)
return result;
return ERROR_OK;
}
-static int kinetis_ftfx_command(struct flash_bank *bank, uint32_t w0,
- uint32_t w1, uint32_t w2, uint8_t *ftfx_fstat)
+static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t faddr,
+ uint8_t fccob4, uint8_t fccob5, uint8_t fccob6, uint8_t fccob7,
+ uint8_t fccob8, uint8_t fccob9, uint8_t fccoba, uint8_t fccobb,
+ uint8_t *ftfx_fstat)
{
- uint8_t buffer[12];
+ uint8_t command[12] = {faddr & 0xff, (faddr >> 8) & 0xff, (faddr >> 16) & 0xff, fcmd,
+ fccob7, fccob6, fccob5, fccob4,
+ fccobb, fccoba, fccob9, fccob8};
int result, i;
+ uint8_t buffer;
/* wait for done */
for (i = 0; i < 50; i++) {
result =
- target_read_memory(bank->target, 0x40020000, 1, 1, buffer);
+ target_read_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer);
if (result != ERROR_OK)
return result;
- if (buffer[0] & 0x80)
+ if (buffer & 0x80)
break;
- buffer[0] = 0x00;
+ buffer = 0x00;
}
- if (buffer[0] != 0x80) {
+ if (buffer != 0x80) {
/* reset error flags */
- buffer[0] = 0x30;
+ buffer = 0x30;
result =
- target_write_memory(bank->target, 0x40020000, 1, 1, buffer);
+ target_write_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer);
if (result != ERROR_OK)
return result;
}
- target_buffer_set_u32(bank->target, buffer, w0);
- target_buffer_set_u32(bank->target, buffer + 4, w1);
- target_buffer_set_u32(bank->target, buffer + 8, w2);
-
- result = target_write_memory(bank->target, 0x40020004, 4, 3, buffer);
+ result = target_write_memory(bank->target, FTFx_FCCOB3, 4, 3, command);
if (result != ERROR_OK)
return result;
/* start command */
- buffer[0] = 0x80;
- result = target_write_memory(bank->target, 0x40020000, 1, 1, buffer);
+ buffer = 0x80;
+ result = target_write_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer);
if (result != ERROR_OK)
return result;
/* wait for done */
for (i = 0; i < 50; i++) {
result =
- target_read_memory(bank->target, 0x40020000, 1, 1, ftfx_fstat);
+ target_read_memory(bank->target, FTFx_FSTAT, 1, 1, ftfx_fstat);
if (result != ERROR_OK)
return result;
if ((*ftfx_fstat & 0xf0) != 0x80) {
LOG_ERROR
- ("ftfx command failed FSTAT: %02X W0: %08X W1: %08X W2: %08X",
- *ftfx_fstat, w0, w1, w2);
-
+ ("ftfx command failed FSTAT: %02X FCCOB: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
+ *ftfx_fstat, command[3], command[2], command[1], command[0],
+ command[7], command[6], command[5], command[4],
+ command[11], command[10], command[9], command[8]);
return ERROR_FLASH_OPERATION_FAILED;
}
static int kinetis_erase(struct flash_bank *bank, int first, int last)
{
int result, i;
- uint32_t w0 = 0, w1 = 0, w2 = 0;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
for (i = first; i <= last; i++) {
uint8_t ftfx_fstat;
/* set command and sector address */
- w0 = (0x09 << 24) | (bank->base + bank->sectors[i].offset);
-
- result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+ result = kinetis_ftfx_command(bank, FTFx_CMD_SECTERASE, bank->base + bank->sectors[i].offset,
+ 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat);
if (result != ERROR_OK) {
LOG_WARNING("erase sector %d failed", i);
{
unsigned int i, result, fallback = 0;
uint8_t buf[8];
- uint32_t wc, w0 = 0, w1 = 0, w2 = 0;
+ uint32_t wc;
struct kinetis_flash_bank *kinfo = bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
LOG_DEBUG("flash write into FlexNVM @%08X", offset);
/* make flex ram available */
- w0 = (0x81 << 24) | 0x00ff0000;
-
- result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+ result = kinetis_ftfx_command(bank, FTFx_CMD_SETFLEXRAM, 0x00ff0000, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat);
if (result != ERROR_OK)
return ERROR_FLASH_OPERATION_FAILED;
/* check if ram ready */
- result = target_read_memory(bank->target, 0x40020001, 1, 1, buf);
+ result = target_read_memory(bank->target, FTFx_FCNFG, 1, 1, buf);
if (result != ERROR_OK)
return result;
/* program section command */
if (fallback == 0) {
- unsigned prog_section_bytes = kinfo->sector_size >> 8;
- for (i = 0; i < count; i += kinfo->sector_size) {
- /*
- * The largest possible Kinetis "section" is
- * 16 bytes. A full Kinetis sector is always
- * 256 "section"s.
- */
+ /*
+ * Kinetis uses different terms for the granularity of
+ * sector writes, e.g. "phrase" or "128 bits". We use
+ * the generic term "chunk". The largest possible
+ * Kinetis "chunk" is 16 bytes (128 bits).
+ */
+ unsigned prog_section_chunk_bytes = kinfo->sector_size >> 8;
+ /* assume the NVM sector size is half the FlexRAM size */
+ unsigned prog_size_bytes = MIN(kinfo->sector_size,
+ kinetis_flash_params[kinfo->granularity].nvm_sector_size_bytes);
+ for (i = 0; i < count; i += prog_size_bytes) {
uint8_t residual_buffer[16];
uint8_t ftfx_fstat;
- uint32_t section_count = 256;
+ uint32_t section_count = prog_size_bytes / prog_section_chunk_bytes;
uint32_t residual_wc = 0;
/*
* Assume the word count covers an entire
* sector.
*/
- wc = kinfo->sector_size / 4;
+ wc = prog_size_bytes / 4;
/*
* If bytes to be programmed are less than the
* residual buffer so that a full "section"
* may always be programmed.
*/
- if ((count - i) < kinfo->sector_size) {
+ if ((count - i) < prog_size_bytes) {
/* number of bytes to program beyond full section */
- unsigned residual_bc = (count-i) % prog_section_bytes;
+ unsigned residual_bc = (count-i) % prog_section_chunk_bytes;
/* number of complete words to copy directly from buffer */
wc = (count - i) / 4;
/* number of total sections to write, including residual */
- section_count = DIV_ROUND_UP((count-i), prog_section_bytes);
+ section_count = DIV_ROUND_UP((count-i), prog_section_chunk_bytes);
/* any residual bytes delivers a whole residual section */
- residual_wc = (residual_bc ? prog_section_bytes : 0)/4;
+ residual_wc = (residual_bc ? prog_section_chunk_bytes : 0)/4;
/* clear residual buffer then populate residual bytes */
- (void) memset(residual_buffer, 0xff, prog_section_bytes);
+ (void) memset(residual_buffer, 0xff, prog_section_chunk_bytes);
(void) memcpy(residual_buffer, &buffer[i+4*wc], residual_bc);
}
LOG_DEBUG("write section @ %08X with length %d bytes",
- offset + i, (count - i));
+ offset + i, wc*4);
/* write data to flexram as whole-words */
- result = target_write_memory(bank->target, 0x14000000, 4, wc,
+ result = target_write_memory(bank->target, FLEXRAM, 4, wc,
buffer + i);
if (result != ERROR_OK) {
/* write the residual words to the flexram */
if (residual_wc) {
result = target_write_memory(bank->target,
- 0x14000000+4*wc,
+ FLEXRAM+4*wc,
4, residual_wc,
residual_buffer);
}
/* execute section-write command */
- w0 = (0x0b << 24) | (bank->base + offset + i);
- w1 = section_count << 16;
-
- result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+ result = kinetis_ftfx_command(bank, FTFx_CMD_SECTWRITE, bank->base + offset + i,
+ section_count>>8, section_count, 0, 0,
+ 0, 0, 0, 0, &ftfx_fstat);
if (result != ERROR_OK)
return ERROR_FLASH_OPERATION_FAILED;
LOG_DEBUG("write longword @ %08X", offset + i);
- w0 = (0x06 << 24) | (bank->base + offset + i);
- w1 = buf_get_u32(buffer + offset + i, 0, 32);
-
- result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+ uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
+ memcpy(padding, buffer + i, MIN(4, count-i));
+ result = kinetis_ftfx_command(bank, FTFx_CMD_LWORDPROG, bank->base + offset + i,
+ padding[3], padding[2], padding[1], padding[0],
+ 0, 0, 0, 0, &ftfx_fstat);
if (result != ERROR_OK)
return ERROR_FLASH_OPERATION_FAILED;
first_nvm_bank = 0, reassign = 0;
struct kinetis_flash_bank *kinfo = bank->driver_priv;
- result = target_read_memory(bank->target, 0x40048024, 1, 4, buf);
+ result = target_read_memory(bank->target, SIM_SDID, 1, 4, buf);
if (result != ERROR_OK)
return result;
kinfo->sim_sdid = target_buffer_get_u32(bank->target, buf);
granularity = (kinfo->sim_sdid >> 7) & 0x03;
- result = target_read_memory(bank->target, 0x4004804c, 1, 4, buf);
+
+ result = target_read_memory(bank->target, SIM_FCFG1, 1, 4, buf);
if (result != ERROR_OK)
return result;
kinfo->sim_fcfg1 = target_buffer_get_u32(bank->target, buf);
- result = target_read_memory(bank->target, 0x40048050, 1, 4, buf);
+
+ result = target_read_memory(bank->target, SIM_FCFG2, 1, 4, buf);
if (result != ERROR_OK)
return result;
kinfo->sim_fcfg2 = target_buffer_get_u32(bank->target, buf);
} else if (bank->size != ee_size) {
LOG_WARNING("FlexRAM size mismatch");
reassign = 1;
- } else if (bank->base != 0x14000000) {
+ } else if (bank->base != FLEXRAM) {
LOG_WARNING("FlexRAM address mismatch");
reassign = 1;
} else if (kinfo->sector_size !=
if (kinfo->flash_class == FC_PFLASH) {
int result;
- uint32_t w0 = 0, w1 = 0, w2 = 0;
uint8_t ftfx_fstat;
/* check if whole bank is blank */
- w0 = (0x00 << 24) | bank->base;
- w1 = 0; /* "normal margin" */
-
- result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+ result = kinetis_ftfx_command(bank, FTFx_CMD_BLOCKSTAT, bank->base, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat);
if (result != ERROR_OK)
return result;
/* the whole bank is not erased, check sector-by-sector */
int i;
for (i = 0; i < bank->num_sectors; i++) {
- w0 = (0x01 << 24) | (bank->base + bank->sectors[i].offset);
- w1 = (0x100 << 16) | 0; /* normal margin */
-
- result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+ /* normal margin */
+ result = kinetis_ftfx_command(bank, FTFx_CMD_SECTSTAT, bank->base + bank->sectors[i].offset,
+ 1, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat);
if (result == ERROR_OK) {
bank->sectors[i].is_erased = !(ftfx_fstat & 0x01);