aboutsummaryrefslogtreecommitdiff
path: root/src/flash/nor
diff options
context:
space:
mode:
Diffstat (limited to 'src/flash/nor')
-rw-r--r--src/flash/nor/Makefile.am4
-rw-r--r--src/flash/nor/aducm360.c2
-rw-r--r--src/flash/nor/ambiqmicro.c3
-rw-r--r--src/flash/nor/at91sam3.c9
-rw-r--r--src/flash/nor/at91sam4.c6
-rw-r--r--src/flash/nor/at91sam4l.c1
-rw-r--r--src/flash/nor/at91sam7.c7
-rw-r--r--src/flash/nor/at91samd.c17
-rw-r--r--src/flash/nor/atsamv.c3
-rw-r--r--src/flash/nor/avrf.c42
-rw-r--r--src/flash/nor/bluenrg-x.c518
-rw-r--r--src/flash/nor/bluenrg-x.h45
-rw-r--r--src/flash/nor/cc3220sf.c2
-rw-r--r--src/flash/nor/cfi.c351
-rw-r--r--src/flash/nor/cfi.h27
-rw-r--r--src/flash/nor/drivers.c4
-rw-r--r--src/flash/nor/dsp5680xx_flash.c2
-rw-r--r--src/flash/nor/efm32.c28
-rw-r--r--src/flash/nor/fespi.c2
-rw-r--r--src/flash/nor/fm4.c8
-rw-r--r--src/flash/nor/jtagspi.c25
-rw-r--r--src/flash/nor/kinetis.c71
-rw-r--r--src/flash/nor/kinetis_ke.c2
-rw-r--r--src/flash/nor/lpcspifi.c16
-rw-r--r--src/flash/nor/mrvlqspi.c10
-rw-r--r--src/flash/nor/msp432.c229
-rw-r--r--src/flash/nor/msp432.h7
-rw-r--r--src/flash/nor/nrf5.c922
-rw-r--r--src/flash/nor/numicro.c29
-rw-r--r--src/flash/nor/psoc6.c7
-rw-r--r--src/flash/nor/renesas_rpchf.c648
-rw-r--r--src/flash/nor/sh_qspi.c912
-rw-r--r--src/flash/nor/sim3x.c2
-rw-r--r--src/flash/nor/stm32f1x.c134
-rw-r--r--src/flash/nor/stm32f2x.c77
-rw-r--r--src/flash/nor/stm32h7x.c806
-rw-r--r--src/flash/nor/stm32l4x.c1079
-rw-r--r--src/flash/nor/stm32l4x.h82
-rw-r--r--src/flash/nor/stm32lx.c17
-rw-r--r--src/flash/nor/tcl.c117
-rw-r--r--src/flash/nor/tms470.c1
-rw-r--r--src/flash/nor/xcf.c1
42 files changed, 4317 insertions, 1958 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 34f91ce..b95b003 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -51,6 +51,8 @@ NOR_DRIVERS = \
%D%/psoc4.c \
%D%/psoc5lp.c \
%D%/psoc6.c \
+ %D%/renesas_rpchf.c \
+ %D%/sh_qspi.c \
%D%/sim3x.c \
%D%/spi.c \
%D%/stmsmi.c \
@@ -74,6 +76,7 @@ NOR_DRIVERS = \
NORHEADERS = \
%D%/core.h \
%D%/cc3220sf.h \
+ %D%/bluenrg-x.h \
%D%/cc26xx.h \
%D%/cfi.h \
%D%/driver.h \
@@ -81,4 +84,5 @@ NORHEADERS = \
%D%/non_cfi.h \
%D%/ocl.h \
%D%/spi.h \
+ %D%/stm32l4x.h \
%D%/msp432.h
diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c
index f468c89..7c5596d 100644
--- a/src/flash/nor/aducm360.c
+++ b/src/flash/nor/aducm360.c
@@ -434,10 +434,8 @@ static int aducm360_write_block(struct flash_bank *bank,
switch (choice) {
case 0:
return aducm360_write_block_sync(bank, buffer, offset, count);
- break;
case 1:
return aducm360_write_block_async(bank, buffer, offset, count);
- break;
default:
LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c
index b1e3e72..b41b15c 100644
--- a/src/flash/nor/ambiqmicro.c
+++ b/src/flash/nor/ambiqmicro.c
@@ -253,8 +253,7 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank)
}
- if (ambiqmicro_info->target_class <
- (sizeof(ambiqmicroParts)/sizeof(ambiqmicroParts[0])))
+ if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicroParts))
ambiqmicro_info->target_name =
ambiqmicroParts[ambiqmicro_info->target_class].partname;
else
diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c
index 2457c15..c9ffa65 100644
--- a/src/flash/nor/at91sam3.c
+++ b/src/flash/nor/at91sam3.c
@@ -3068,7 +3068,6 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
((unsigned int)(FLASH_BANK1_BASE_256K_AX)),
((unsigned int)(FLASH_BANK1_BASE_512K_AX)));
return ERROR_FAIL;
- break;
/* at91sam3s and at91sam3n series only has bank 0*/
/* at91sam3u and at91sam3ax series has the same address for bank 0*/
@@ -3621,10 +3620,8 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command)
switch (CMD_ARGC) {
default:
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
case 0:
goto showall;
- break;
case 1:
who = -1;
break;
@@ -3653,7 +3650,8 @@ showall:
}
if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
- command_print(CMD, "sam3-gpnvm%u: %u", who, v);
+ if (r == ERROR_OK)
+ command_print(CMD, "sam3-gpnvm%u: %u", who, v);
return r;
} else {
command_print(CMD, "sam3-gpnvm invalid GPNVM: %u", who);
@@ -3707,7 +3705,6 @@ COMMAND_HANDLER(sam3_handle_slowclk_command)
/* error */
command_print(CMD, "Too many parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
}
command_print(CMD, "Slowclk freq: %d.%03dkhz",
(int)(pChip->cfg.slow_freq / 1000),
@@ -3729,7 +3726,7 @@ static const struct command_registration at91sam3_exec_command_handlers[] = {
.name = "info",
.handler = sam3_handle_info_command,
.mode = COMMAND_EXEC,
- .help = "Print information about the current at91sam3 chip"
+ .help = "Print information about the current at91sam3 chip "
"and its flash configuration.",
.usage = "",
},
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index 621754c..5b56c42 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -2482,7 +2482,6 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command)
((unsigned int)(bank->base)),
((unsigned int)(FLASH_BANK_BASE_S)));
return ERROR_FAIL;
- break;
/* at91sam4s series only has bank 0*/
/* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/
@@ -3101,10 +3100,8 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command)
switch (CMD_ARGC) {
default:
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
case 0:
goto showall;
- break;
case 1:
who = -1;
break;
@@ -3188,7 +3185,6 @@ COMMAND_HANDLER(sam4_handle_slowclk_command)
/* error */
command_print(CMD, "Too many parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
}
command_print(CMD, "Slowclk freq: %d.%03dkhz",
(int)(pChip->cfg.slow_freq / 1000),
@@ -3210,7 +3206,7 @@ static const struct command_registration at91sam4_exec_command_handlers[] = {
.name = "info",
.handler = sam4_handle_info_command,
.mode = COMMAND_EXEC,
- .help = "Print information about the current at91sam4 chip"
+ .help = "Print information about the current at91sam4 chip "
"and its flash configuration.",
.usage = "",
},
diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c
index d356398..d4bfe53 100644
--- a/src/flash/nor/at91sam4l.c
+++ b/src/flash/nor/at91sam4l.c
@@ -601,6 +601,7 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer,
/* There's at least one aligned page to write out. */
if (count >= chip->page_size) {
+ assert(chip->page_size > 0);
int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0);
for (int i = 0; i < np; i++) {
diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c
index 232260b..039746c 100644
--- a/src/flash/nor/at91sam7.c
+++ b/src/flash/nor/at91sam7.c
@@ -711,8 +711,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
uint16_t page_size;
uint16_t num_nvmbits;
- char *target_name_t;
-
int bnk, sec;
at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
@@ -753,9 +751,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
return ERROR_OK;
}
- target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
- strcpy(target_name_t, CMD_ARGV[7]);
-
/* calculate bank size */
bank_size = num_sectors * pages_per_sector * page_size;
@@ -794,7 +789,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
at91sam7_info = t_bank->driver_priv;
- at91sam7_info->target_name = target_name_t;
+ at91sam7_info->target_name = strdup(CMD_ARGV[7]);
at91sam7_info->flashmode = 0;
at91sam7_info->ext_freq = ext_freq;
at91sam7_info->num_nvmbits = num_nvmbits;
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index b6cff9a..6e89099 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -181,6 +181,23 @@ static const struct samd_part samd21_parts[] = {
{ 0x26, "SAMD21E16B", 64, 8 },
{ 0x27, "SAMD21E15B", 32, 4 },
+ /* SAMD21 D and L Variants (from Errata)
+ http://ww1.microchip.com/downloads/en/DeviceDoc/
+ SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */
+ { 0x55, "SAMD21E16BU", 64, 8 },
+ { 0x56, "SAMD21E15BU", 32, 4 },
+ { 0x57, "SAMD21G16L", 64, 8 },
+ { 0x3E, "SAMD21E16L", 64, 8 },
+ { 0x3F, "SAMD21E15L", 32, 4 },
+ { 0x62, "SAMD21E16CU", 64, 8 },
+ { 0x63, "SAMD21E15CU", 32, 4 },
+ { 0x92, "SAMD21J17D", 128, 16 },
+ { 0x93, "SAMD21G17D", 128, 16 },
+ { 0x94, "SAMD21E17D", 128, 16 },
+ { 0x95, "SAMD21E17DU", 128, 16 },
+ { 0x96, "SAMD21G17L", 128, 16 },
+ { 0x97, "SAMD21E17L", 128, 16 },
+
/* Known SAMDA1 parts.
SAMD-A1 series uses the same series identifier like the SAMD21
taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */
diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c
index d6f1a0a..9a53369 100644
--- a/src/flash/nor/atsamv.c
+++ b/src/flash/nor/atsamv.c
@@ -375,7 +375,6 @@ static int samv_probe(struct flash_bank *bank)
default:
LOG_ERROR("unrecognized flash size code: %d", nvm_size_code);
return ERROR_FAIL;
- break;
}
struct samv_flash_bank *samv_info = bank->driver_priv;
@@ -645,7 +644,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command)
switch (CMD_ARGC) {
case 0:
goto showall;
- break;
case 1:
who = -1;
break;
@@ -660,7 +658,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command)
break;
default:
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
}
uint32_t v;
diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c
index 178567e..93f6872 100644
--- a/src/flash/nor/avrf.c
+++ b/src/flash/nor/avrf.c
@@ -58,7 +58,7 @@ struct avrf_type {
struct avrf_flash_bank {
int ppage_size;
- int probed;
+ bool probed;
};
static const struct avrf_type avft_chips_info[] = {
@@ -67,6 +67,7 @@ static const struct avrf_type avft_chips_info[] = {
*/
{"atmega128", 0x9702, 256, 512, 8, 512},
{"atmega128rfa1", 0xa701, 128, 512, 8, 512},
+ {"atmega256rfr2", 0xa802, 256, 1024, 8, 1024},
{"at90can128", 0x9781, 256, 512, 8, 512},
{"at90usb128", 0x9782, 256, 512, 8, 512},
{"atmega164p", 0x940a, 128, 128, 4, 128},
@@ -142,16 +143,24 @@ static int avr_jtagprg_chiperase(struct avr_common *avr)
}
static int avr_jtagprg_writeflashpage(struct avr_common *avr,
+ const bool ext_addressing,
const uint8_t *page_buf,
uint32_t buf_size,
uint32_t addr,
uint32_t page_size)
{
- uint32_t i, poll_value;
+ uint32_t poll_value;
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
+ /* load extended high byte */
+ if (ext_addressing)
+ avr_jtag_senddat(avr->jtag_info.tap,
+ NULL,
+ 0x0b00 | ((addr >> 17) & 0xFF),
+ AVR_JTAG_REG_ProgrammingCommand_Len);
+
/* load addr high byte */
avr_jtag_senddat(avr->jtag_info.tap,
NULL,
@@ -166,7 +175,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr,
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
- for (i = 0; i < page_size; i++) {
+ for (uint32_t i = 0; i < page_size; i++) {
if (i < buf_size)
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
else
@@ -204,7 +213,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
avrf_info = malloc(sizeof(struct avrf_flash_bank));
bank->driver_priv = avrf_info;
- avrf_info->probed = 0;
+ avrf_info->probed = false;
return ERROR_OK;
}
@@ -238,6 +247,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
uint32_t cur_size, cur_buffer_size, page_size;
+ bool ext_addressing;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -258,6 +268,11 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
return ERROR_FAIL;
+ if (bank->size > 0x20000)
+ ext_addressing = true;
+ else
+ ext_addressing = false;
+
cur_size = 0;
while (count > 0) {
if (count > page_size)
@@ -265,6 +280,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
else
cur_buffer_size = count;
avr_jtagprg_writeflashpage(avr,
+ ext_addressing,
buffer + cur_size,
cur_buffer_size,
offset + cur_size,
@@ -288,7 +304,6 @@ static int avrf_probe(struct flash_bank *bank)
struct avrf_flash_bank *avrf_info = bank->driver_priv;
struct avr_common *avr = target->arch_info;
const struct avrf_type *avr_info = NULL;
- int i;
uint32_t device_id;
if (bank->target->state != TARGET_HALTED) {
@@ -296,7 +311,7 @@ static int avrf_probe(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
- avrf_info->probed = 0;
+ avrf_info->probed = false;
avr_jtag_read_jtagid(avr, &device_id);
if (ERROR_OK != mcu_execute_queue())
@@ -308,7 +323,7 @@ static int avrf_probe(struct flash_bank *bank)
EXTRACT_MFG(device_id),
0x1F);
- for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) {
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
avr_info = &avft_chips_info[i];
LOG_INFO("target device is %s", avr_info->name);
@@ -328,20 +343,20 @@ static int avrf_probe(struct flash_bank *bank)
bank->num_sectors = avr_info->flash_page_num;
bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
- for (i = 0; i < avr_info->flash_page_num; i++) {
+ for (int i = 0; i < avr_info->flash_page_num; i++) {
bank->sectors[i].offset = i * avr_info->flash_page_size;
bank->sectors[i].size = avr_info->flash_page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
- avrf_info->probed = 1;
+ avrf_info->probed = true;
return ERROR_OK;
} else {
/* chip not supported */
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
- avrf_info->probed = 1;
+ avrf_info->probed = true;
return ERROR_FAIL;
}
}
@@ -359,7 +374,6 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
const struct avrf_type *avr_info = NULL;
- int i;
uint32_t device_id;
if (bank->target->state != TARGET_HALTED) {
@@ -377,7 +391,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
EXTRACT_MFG(device_id),
0x1F);
- for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) {
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
avr_info = &avft_chips_info[i];
LOG_INFO("target device is %s", avr_info->name);
@@ -418,8 +432,6 @@ static int avrf_mass_erase(struct flash_bank *bank)
COMMAND_HANDLER(avrf_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -430,7 +442,7 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command)
if (avrf_mass_erase(bank) == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "avr mass erase complete");
diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c
index f6a2492..fbce20d 100644
--- a/src/flash/nor/bluenrg-x.c
+++ b/src/flash/nor/bluenrg-x.c
@@ -24,35 +24,62 @@
#include <target/armv7m.h>
#include <target/cortex_m.h>
#include "imp.h"
+#include "bluenrg-x.h"
+
+#define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg)
+#define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg)
+
+#define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg)
+#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg)
+#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size)
+
+struct flash_ctrl_priv_data {
+ uint32_t die_id_reg;
+ uint32_t jtag_idcode_reg;
+ uint32_t flash_base;
+ uint32_t flash_regs_base;
+ uint32_t flash_page_size;
+ uint32_t jtag_idcode;
+ char *part_name;
+};
+
+const struct flash_ctrl_priv_data flash_priv_data_1 = {
+ .die_id_reg = 0x4090001C,
+ .jtag_idcode_reg = 0x40900028,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40100000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x00000000,
+ .part_name = "BLUENRG-1",
+};
-#define FLASH_SIZE_REG (0x40100014)
-#define DIE_ID_REG (0x4090001C)
-#define JTAG_IDCODE_REG (0x40900028)
-#define BLUENRG2_IDCODE (0x0200A041)
-#define FLASH_BASE (0x10040000)
-#define FLASH_PAGE_SIZE (2048)
-#define FLASH_REG_COMMAND (0x40100000)
-#define FLASH_REG_IRQRAW (0x40100010)
-#define FLASH_REG_ADDRESS (0x40100018)
-#define FLASH_REG_DATA (0x40100040)
-#define FLASH_CMD_ERASE_PAGE 0x11
-#define FLASH_CMD_MASSERASE 0x22
-#define FLASH_CMD_WRITE 0x33
-#define FLASH_CMD_BURSTWRITE 0xCC
-#define FLASH_INT_CMDDONE 0x01
-#define FLASH_WORD_LEN 4
+const struct flash_ctrl_priv_data flash_priv_data_2 = {
+ .die_id_reg = 0x4090001C,
+ .jtag_idcode_reg = 0x40900028,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40100000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x0200A041,
+ .part_name = "BLUENRG-2",
+};
+
+const struct flash_ctrl_priv_data flash_priv_data_lp = {
+ .die_id_reg = 0x40000000,
+ .jtag_idcode_reg = 0x40000004,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40001000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x0201E041,
+ .part_name = "BLUENRG-LP",
+};
struct bluenrgx_flash_bank {
- int probed;
- uint32_t idcode;
+ bool probed;
uint32_t die_id;
+ const struct flash_ctrl_priv_data *flash_ptr;
};
-static int bluenrgx_protect_check(struct flash_bank *bank)
-{
- /* Nothing to do. Protection is only handled in SW. */
- return ERROR_OK;
-}
+const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp};
/* flash_bank bluenrg-x 0 0 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
@@ -67,9 +94,12 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
return ERROR_FAIL;
}
+ bank->write_start_alignment = 16;
+ bank->write_end_alignment = 16;
+
bank->driver_priv = bluenrgx_info;
- bluenrgx_info->probed = 0;
+ bluenrgx_info->probed = false;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -77,6 +107,22 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
return ERROR_OK;
}
+static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
+{
+ struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+ return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset;
+}
+
+static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
+{
+ return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
+}
+
+static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
+}
+
static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
{
int retval = ERROR_OK;
@@ -87,7 +133,7 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
uint32_t address, command;
/* check preconditions */
- if (bluenrgx_info->probed == 0)
+ if (!bluenrgx_info->probed)
return ERROR_FLASH_BANK_NOT_PROBED;
if (bank->target->state != TARGET_HALTED) {
@@ -103,24 +149,25 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
if (mass_erase) {
command = FLASH_CMD_MASSERASE;
address = bank->base;
- if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
+ (address - bank->base) >> 2) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- for (int i = 0; i < 100; i++) {
+ for (unsigned int i = 0; i < 100; i++) {
uint32_t value;
- if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
+ if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
@@ -135,26 +182,28 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
} else {
command = FLASH_CMD_ERASE_PAGE;
for (int i = first; i <= last; i++) {
- address = bank->base+i*FLASH_PAGE_SIZE;
+ address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info);
+ LOG_DEBUG("address = %08x, index = %d", address, i);
- if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
+ (address - bank->base) >> 2) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
LOG_ERROR("Failed");
return ERROR_FAIL;
}
- for (int j = 0; j < 100; j++) {
+ for (unsigned int j = 0; j < 100; j++) {
uint32_t value;
- if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
+ if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
@@ -172,140 +221,10 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
}
-static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last)
-{
- /* Protection is only handled in software: no hardware write protection
- available in BlueNRG-x devices */
- int sector;
-
- for (sector = first; sector <= last; sector++)
- bank->sectors[sector].is_protected = set;
- return ERROR_OK;
-}
-static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count)
-{
- int retval = ERROR_OK;
-
- retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- for (uint32_t i = 0; i < count; i++) {
- uint32_t address = address_base + i * FLASH_WORD_LEN;
-
- retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- for (int j = 0; j < 100; j++) {
- uint32_t reg_value;
- retval = target_read_u32(target, FLASH_REG_IRQRAW, &reg_value);
-
- if (retval != ERROR_OK) {
- LOG_ERROR("Register read failed, error code: %d", retval);
- return retval;
- }
-
- if (reg_value & FLASH_INT_CMDDONE)
- break;
-
- if (j == 99) {
- LOG_ERROR("Write command failed (timeout)");
- return ERROR_FAIL;
- }
- }
- }
- return retval;
-}
-
-static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count)
-{
- int retval = ERROR_OK;
- uint8_t *new_buffer = NULL;
- uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address;
-
- if (count == 0) {
- /* Just return if there are no bytes to write */
- return retval;
- }
-
- if (address_base & 3) {
- pre_bytes = address_base & 3;
- pre_address = address_base - pre_bytes;
- }
-
- if ((count + pre_bytes) & 3) {
- post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes);
- post_address = (address_base + count) & ~3;
- }
-
- if (pre_bytes || post_bytes) {
- uint32_t old_count = count;
-
- count = old_count + pre_bytes + post_bytes;
-
- new_buffer = malloc(count);
-
- if (new_buffer == NULL) {
- LOG_ERROR("odd number of bytes to write and no memory "
- "for padding buffer");
- return ERROR_FAIL;
- }
-
- LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %"
- PRIu32 " ", old_count, count);
-
- if (pre_bytes) {
- if (target_read_u32(target, pre_address, &pre_word)) {
- LOG_ERROR("Memory read failed");
- free(new_buffer);
- return ERROR_FAIL;
- }
-
- }
-
- if (post_bytes) {
- if (target_read_u32(target, post_address, &post_word)) {
- LOG_ERROR("Memory read failed");
- free(new_buffer);
- return ERROR_FAIL;
- }
-
- }
-
- memcpy(new_buffer, &pre_word, pre_bytes);
- memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4);
- memcpy(new_buffer+pre_bytes, buffer, old_count);
- buffer = new_buffer;
- }
-
- retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4);
-
- if (new_buffer)
- free(new_buffer);
-
- return retval;
-}
-
static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
+ struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size = 16384 + 8;
struct working_area *write_algorithm;
@@ -313,10 +232,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
struct working_area *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[5];
+ struct mem_param mem_params[1];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
- uint32_t pre_size = 0, fast_size = 0, post_size = 0;
- uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0;
/* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and
* hints how to generate the data!
@@ -325,6 +243,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
};
+ /* check preconditions */
+ if (!bluenrgx_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
if ((offset + count) > bank->size) {
LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d",
(offset + count),
@@ -337,132 +259,105 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_TARGET_NOT_HALTED;
}
- /* We are good here and we need to compute pre_size, fast_size, post_size */
- pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset);
- pre_offset = offset;
- fast_size = 16*((count - pre_size) / 16);
- fast_offset = offset + pre_size;
- post_size = (count-pre_size-fast_size) % 16;
- post_offset = fast_offset + fast_size;
-
- LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset);
- LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset);
- LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset);
-
- /* Program initial chunk not 16 bytes aligned */
- retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size);
- if (retval) {
- LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
- return ERROR_FAIL;
+ if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
+ &write_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- /* Program chunk 16 bytes aligned in fast mode */
- if (fast_size) {
-
- if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
- &write_algorithm) != ERROR_OK) {
- LOG_WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
-
- retval = target_write_buffer(target, write_algorithm->address,
- sizeof(bluenrgx_flash_write_code),
- bluenrgx_flash_write_code);
- if (retval != ERROR_OK)
- return retval;
+ retval = target_write_buffer(target, write_algorithm->address,
+ sizeof(bluenrgx_flash_write_code),
+ bluenrgx_flash_write_code);
+ if (retval != ERROR_OK)
+ return retval;
- /* memory buffer */
- if (target_alloc_working_area(target, buffer_size, &source)) {
- LOG_WARNING("no large enough working area available");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ /* memory buffer */
+ if (target_alloc_working_area(target, buffer_size, &source)) {
+ LOG_WARNING("no large enough working area available");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
- /* Stack pointer area */
- if (target_alloc_working_area(target, 64,
- &write_algorithm_sp) != ERROR_OK) {
- LOG_DEBUG("no working area for write code stack pointer");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ /* Stack pointer area */
+ if (target_alloc_working_area(target, 128,
+ &write_algorithm_sp) != ERROR_OK) {
+ LOG_DEBUG("no working area for write code stack pointer");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
- armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
- armv7m_info.core_mode = ARM_MODE_THREAD;
-
- init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
- init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
- init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
-
- /* FIFO start address (first two words used for write and read pointers) */
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- /* FIFO end address (first two words used for write and read pointers) */
- buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
- /* Flash memory address */
- buf_set_u32(reg_params[2].value, 0, 32, address+pre_size);
- /* Number of bytes */
- buf_set_u32(reg_params[3].value, 0, 32, fast_size);
- /* Stack pointer for program working area */
- buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
-
- LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
- LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
- LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
- LOG_DEBUG("address = %08x", address+pre_size);
- LOG_DEBUG("count = %08x", count);
-
- retval = target_run_flash_async_algorithm(target,
- buffer+pre_size,
- fast_size/16,
- 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
- 0,
- NULL,
- 5,
- reg_params,
- source->address,
- source->size,
- write_algorithm->address,
- 0,
- &armv7m_info);
-
- if (retval == ERROR_FLASH_OPERATION_FAILED) {
- LOG_ERROR("error executing bluenrg-x flash write algorithm");
-
- uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
-
- if (error != 0)
- LOG_ERROR("flash write failed = %08" PRIx32, error);
- }
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ armv7m_info.core_mode = ARM_MODE_THREAD;
+
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+ init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
+ /* Put the parameter at the first available stack location */
+ init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT);
+
+ /* FIFO start address (first two words used for write and read pointers) */
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);
+ /* FIFO end address (first two words used for write and read pointers) */
+ buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
+ /* Flash memory address */
+ buf_set_u32(reg_params[2].value, 0, 32, address);
+ /* Number of bytes */
+ buf_set_u32(reg_params[3].value, 0, 32, count);
+ /* Stack pointer for program working area */
+ buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
+ /* Flash register base address */
+ buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base);
+
+ LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
+ LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
+ LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
+ LOG_DEBUG("address = %08x", address);
+ LOG_DEBUG("count = %08x", count);
+
+ retval = target_run_flash_async_algorithm(target,
+ buffer,
+ count/16,
+ 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
+ 1,
+ mem_params,
+ 5,
+ reg_params,
+ source->address,
+ source->size,
+ write_algorithm->address,
+ 0,
+ &armv7m_info);
+
+ if (retval == ERROR_FLASH_OPERATION_FAILED) {
+ LOG_ERROR("error executing bluenrg-x flash write algorithm");
+
+ uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
+
+ if (error != 0)
+ LOG_ERROR("flash write failed = %08" PRIx32, error);
+ }
+ if (retval == ERROR_OK) {
+ uint32_t rp;
+ /* Read back rp and check that is valid */
+ retval = target_read_u32(target, source->address+4, &rp);
if (retval == ERROR_OK) {
- uint32_t rp;
- /* Read back rp and check that is valid */
- retval = target_read_u32(target, source->address+4, &rp);
- if (retval == ERROR_OK) {
- if ((rp < source->address+8) || (rp > (source->address + source->size))) {
- LOG_ERROR("flash write failed = %08" PRIx32, rp);
- retval = ERROR_FLASH_OPERATION_FAILED;
- }
+ if ((rp < source->address+8) || (rp > (source->address + source->size))) {
+ LOG_ERROR("flash write failed = %08" PRIx32, rp);
+ retval = ERROR_FLASH_OPERATION_FAILED;
}
}
- target_free_working_area(target, source);
- target_free_working_area(target, write_algorithm);
- target_free_working_area(target, write_algorithm_sp);
-
- destroy_reg_param(&reg_params[0]);
- destroy_reg_param(&reg_params[1]);
- destroy_reg_param(&reg_params[2]);
- destroy_reg_param(&reg_params[3]);
- destroy_reg_param(&reg_params[4]);
- if (retval != ERROR_OK)
- return retval;
-
}
+ target_free_working_area(target, source);
+ target_free_working_area(target, write_algorithm);
+ target_free_working_area(target, write_algorithm_sp);
+
+ destroy_reg_param(&reg_params[0]);
+ destroy_reg_param(&reg_params[1]);
+ destroy_reg_param(&reg_params[2]);
+ destroy_reg_param(&reg_params[3]);
+ destroy_reg_param(&reg_params[4]);
+ destroy_mem_param(&mem_params[0]);
- /* Program chunk at end, not addressable by fast burst write algorithm */
- retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size);
- if (retval) {
- LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
- return ERROR_FAIL;
- }
return retval;
}
@@ -470,33 +365,50 @@ static int bluenrgx_probe(struct flash_bank *bank)
{
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
uint32_t idcode, size_info, die_id;
- int i;
- int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode);
+ int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode);
+
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info);
+
+ if (idcode != flash_priv_data_lp.jtag_idcode) {
+ retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* Default device is BlueNRG-1 */
+ bluenrgx_info->flash_ptr = &flash_priv_data_1;
+ bank->base = flash_priv_data_1.flash_base;
+
+ for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) {
+ if (idcode == (*flash_ctrl[i]).jtag_idcode) {
+ bluenrgx_info->flash_ptr = flash_ctrl[i];
+ bank->base = (*flash_ctrl[i]).flash_base;
+ break;
+ }
+ }
+ retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(bank->target, DIE_ID_REG, &die_id);
+ retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id);
if (retval != ERROR_OK)
return retval;
- bank->size = (size_info + 1) * 4;
- bank->base = FLASH_BASE;
- bank->num_sectors = bank->size/FLASH_PAGE_SIZE;
+ bank->size = (size_info + 1) * FLASH_WORD_LEN;
+ bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
- for (i = 0; i < bank->num_sectors; i++) {
- bank->sectors[i].offset = i * FLASH_PAGE_SIZE;
- bank->sectors[i].size = FLASH_PAGE_SIZE;
+ for (int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info);
+ bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
}
- bluenrgx_info->probed = 1;
+ bluenrgx_info->probed = true;
bluenrgx_info->die_id = die_id;
- bluenrgx_info->idcode = idcode;
+
return ERROR_OK;
}
@@ -515,7 +427,6 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
int mask_number, cut_number;
- char *part_name;
if (!bluenrgx_info->probed) {
int retval = bluenrgx_probe(bank);
@@ -526,16 +437,11 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
}
}
- if (bluenrgx_info->idcode == BLUENRG2_IDCODE)
- part_name = "BLUENRG-2";
- else
- part_name = "BLUENRG-1";
-
mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
cut_number = bluenrgx_info->die_id & 0xF;
snprintf(buf, buf_size,
- "%s - Rev: %d.%d", part_name, mask_number, cut_number);
+ "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number);
return ERROR_OK;
}
@@ -543,12 +449,12 @@ const struct flash_driver bluenrgx_flash = {
.name = "bluenrg-x",
.flash_bank_command = bluenrgx_flash_bank_command,
.erase = bluenrgx_erase,
- .protect = bluenrgx_protect,
+ .protect = NULL,
.write = bluenrgx_write,
.read = default_flash_read,
.probe = bluenrgx_probe,
.erase_check = default_flash_blank_check,
- .protect_check = bluenrgx_protect_check,
+ .protect_check = NULL,
.auto_probe = bluenrgx_auto_probe,
.info = bluenrgx_get_info,
};
diff --git a/src/flash/nor/bluenrg-x.h b/src/flash/nor/bluenrg-x.h
new file mode 100644
index 0000000..3b84b8b
--- /dev/null
+++ b/src/flash/nor/bluenrg-x.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2019 by STMicroelectronics. *
+ * *
+ * 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 2 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/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_BLUENRGX_H
+#define OPENOCD_FLASH_NOR_BLUENRGX_H
+
+/* Flash Controller registers offsets */
+#define FLASH_REG_COMMAND 0x00
+#define FLASH_REG_CONFIG 0x04
+#define FLASH_REG_IRQSTAT 0x08
+#define FLASH_REG_IRQMASK 0x0C
+#define FLASH_REG_IRQRAW 0x10
+#define FLASH_REG_ADDRESS 0x18
+#define FLASH_REG_UNLOCKM 0x1C
+#define FLASH_REG_UNLOCKL 0x20
+#define FLASH_REG_DATA0 0x40
+#define FLASH_REG_DATA1 0x44
+#define FLASH_REG_DATA2 0x48
+#define FLASH_REG_DATA3 0x4C
+#define FLASH_SIZE_REG 0x14
+
+/* Flash Controller commands */
+#define FLASH_CMD_ERASE_PAGE 0x11
+#define FLASH_CMD_MASSERASE 0x22
+#define FLASH_CMD_WRITE 0x33
+#define FLASH_CMD_BURSTWRITE 0xCC
+#define FLASH_INT_CMDDONE 0x01
+
+#define FLASH_WORD_LEN 4
+
+#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */
diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c
index afdb7f4..c8de7d0 100644
--- a/src/flash/nor/cc3220sf.c
+++ b/src/flash/nor/cc3220sf.c
@@ -363,6 +363,8 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_ERROR("cc3220sf: Flash operation failed");
break;
}
+
+ keep_alive();
}
/* Do one word write for any final bytes less than a full word */
diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c
index 04fa83b..50ab207 100644
--- a/src/flash/nor/cfi.c
+++ b/src/flash/nor/cfi.c
@@ -34,9 +34,6 @@
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
-#define CFI_MAX_BUS_WIDTH 4
-#define CFI_MAX_CHIP_WIDTH 4
-
/* defines internal maximum size for code fragment in cfi_intel_write_block() */
#define CFI_MAX_INTEL_CODESIZE 256
@@ -103,16 +100,15 @@ static const struct cfi_fixup cfi_0001_fixups[] = {
static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- const struct cfi_fixup *f;
- for (f = fixups; f->fixup; f++) {
+ for (const struct cfi_fixup *f = fixups; f->fixup; f++) {
if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) &&
((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id)))
f->fixup(bank, f->param);
}
}
-static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset)
+uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -131,32 +127,55 @@ static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32
}
}
+static int cfi_target_write_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, const uint8_t *buffer)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ if (cfi_info->write_mem) {
+ return cfi_info->write_mem(bank, addr, count, buffer);
+ } else {
+ return target_write_memory(bank->target, addr, bank->bus_width,
+ count, buffer);
+ }
+}
+
+int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ if (cfi_info->read_mem) {
+ return cfi_info->read_mem(bank, addr, count, buffer);
+ } else {
+ return target_read_memory(bank->target, addr, bank->bus_width,
+ count, buffer);
+ }
+}
+
static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
{
- int i;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
/* clear whole buffer, to ensure bits that exceed the bus_width
* are set to zero
*/
- for (i = 0; i < CFI_MAX_BUS_WIDTH; i++)
+ for (size_t i = 0; i < CFI_MAX_BUS_WIDTH; i++)
cmd_buf[i] = 0;
if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) {
- for (i = bank->bus_width; i > 0; i--)
+ for (int i = bank->bus_width; i > 0; i--)
*cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
} else {
- for (i = 1; i <= bank->bus_width; i++)
+ for (int i = 1; i <= bank->bus_width; i++)
*cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
}
}
-static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address)
+int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address)
{
uint8_t command[CFI_MAX_BUS_WIDTH];
cfi_command(bank, cmd, command);
- return target_write_memory(bank->target, address, bank->bus_width, 1, command);
+ return cfi_target_write_memory(bank, address, 1, command);
}
/* read unsigned 8-bit value from the bank
@@ -165,13 +184,12 @@ static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t addre
*/
static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH];
int retval;
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 1, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 1, data);
if (retval != ERROR_OK)
return retval;
@@ -189,25 +207,23 @@ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, ui
*/
static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH];
- int i;
int retval;
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 1, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 1, data);
if (retval != ERROR_OK)
return retval;
if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) {
- for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+ for (int i = 0; i < bank->bus_width / bank->chip_width; i++)
data[0] |= data[i];
*val = data[0];
} else {
uint8_t value = 0;
- for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+ for (int i = 0; i < bank->bus_width / bank->chip_width; i++)
value |= data[bank->bus_width - 1 - i];
*val = value;
@@ -217,22 +233,20 @@ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint
static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, uint16_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH * 2];
int retval;
if (cfi_info->x16_as_x8) {
- uint8_t i;
- for (i = 0; i < 2; i++) {
- retval = target_read_memory(target, flash_address(bank, sector, offset + i),
- bank->bus_width, 1, &data[i * bank->bus_width]);
+ for (uint8_t i = 0; i < 2; i++) {
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i),
+ 1, &data[i * bank->bus_width]);
if (retval != ERROR_OK)
return retval;
}
} else {
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 2, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 2, data);
if (retval != ERROR_OK)
return retval;
}
@@ -247,22 +261,20 @@ static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, u
static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, uint32_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH * 4];
int retval;
if (cfi_info->x16_as_x8) {
- uint8_t i;
- for (i = 0; i < 4; i++) {
- retval = target_read_memory(target, flash_address(bank, sector, offset + i),
- bank->bus_width, 1, &data[i * bank->bus_width]);
+ for (uint8_t i = 0; i < 4; i++) {
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i),
+ 1, &data[i * bank->bus_width]);
if (retval != ERROR_OK)
return retval;
}
} else {
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 4, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 4, data);
if (retval != ERROR_OK)
return retval;
}
@@ -278,16 +290,16 @@ static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, u
return ERROR_OK;
}
-static int cfi_reset(struct flash_bank *bank)
+int cfi_reset(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
int retval = ERROR_OK;
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -295,7 +307,7 @@ static int cfi_reset(struct flash_bank *bank)
(cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E)) {
/* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state
* so we send an extra 0xF0 reset to fix the bug */
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x00));
if (retval != ERROR_OK)
return retval;
}
@@ -305,7 +317,7 @@ static int cfi_reset(struct flash_bank *bank)
static void cfi_intel_clear_status_register(struct flash_bank *bank)
{
- cfi_send_command(bank, 0x50, flash_address(bank, 0, 0x0));
+ cfi_send_command(bank, 0x50, cfi_flash_address(bank, 0, 0x0));
}
static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint8_t *val)
@@ -359,7 +371,7 @@ static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint
return retval;
}
-static int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
+int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
{
uint8_t status, oldstatus;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -534,7 +546,7 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank)
pri_ext->_reversed_geometry = 0;
if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
LOG_ERROR("Could not read spansion bank information");
@@ -641,7 +653,7 @@ static int cfi_read_atmel_pri_ext(struct flash_bank *bank)
if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R')
|| (atmel_pri_ext.pri[2] != 'I')) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
LOG_ERROR("Could not read atmel bank information");
@@ -799,14 +811,12 @@ static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
-/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options]
- */
-FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
+int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv)
{
struct cfi_flash_bank *cfi_info;
int bus_swap = 0;
- if (CMD_ARGC < 6)
+ if (argc < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
/* both widths must:
@@ -826,7 +836,7 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
}
cfi_info = malloc(sizeof(struct cfi_flash_bank));
- cfi_info->probed = 0;
+ cfi_info->probed = false;
cfi_info->erase_region_info = NULL;
cfi_info->pri_ext = NULL;
bank->driver_priv = cfi_info;
@@ -836,14 +846,14 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
cfi_info->not_cfi = 0;
cfi_info->data_swap = 0;
- for (unsigned i = 6; i < CMD_ARGC; i++) {
- if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0)
+ for (unsigned i = 6; i < argc; i++) {
+ if (strcmp(argv[i], "x16_as_x8") == 0)
cfi_info->x16_as_x8 = 1;
- else if (strcmp(CMD_ARGV[i], "data_swap") == 0)
+ else if (strcmp(argv[i], "data_swap") == 0)
cfi_info->data_swap = 1;
- else if (strcmp(CMD_ARGV[i], "bus_swap") == 0)
+ else if (strcmp(argv[i], "bus_swap") == 0)
bus_swap = 1;
- else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0)
+ else if (strcmp(argv[i], "jedec_probe") == 0)
cfi_info->jedec_probe = 1;
}
@@ -860,20 +870,26 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
return ERROR_OK;
}
+/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options]
+ */
+FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
+{
+ return cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV);
+}
+
static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- int i;
cfi_intel_clear_status_register(bank);
- for (i = first; i <= last; i++) {
- retval = cfi_send_command(bank, 0x20, flash_address(bank, i, 0x0));
+ for (int i = first; i <= last; i++) {
+ retval = cfi_send_command(bank, 0x20, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -885,7 +901,7 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
if (status == 0x80)
bank->sectors[i].is_erased = 1;
else {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -895,45 +911,53 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
}
}
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
+int cfi_spansion_unlock_seq(struct flash_bank *bank)
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
- int i;
- for (i = first; i <= last; i++) {
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
+ retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, pri_ext->_unlock1));
+ if (retval != ERROR_OK)
+ return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
- if (retval != ERROR_OK)
- return retval;
+ retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, pri_ext->_unlock2));
+ if (retval != ERROR_OK)
+ return retval;
+
+ return ERROR_OK;
+}
- retval = cfi_send_command(bank, 0x80, flash_address(bank, 0, pri_ext->_unlock1));
+static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
+{
+ int retval;
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+ for (int i = first; i <= last; i++) {
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
+ retval = cfi_send_command(bank, 0x80, cfi_flash_address(bank, 0, pri_ext->_unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x30, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x30, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK)
bank->sectors[i].is_erased = 1;
else {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -943,10 +967,10 @@ static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
}
}
- return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_erase(struct flash_bank *bank, int first, int last)
+int cfi_erase(struct flash_bank *bank, int first, int last)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -965,10 +989,8 @@ static int cfi_erase(struct flash_bank *bank, int first, int last)
case 1:
case 3:
return cfi_intel_erase(bank, first, last);
- break;
case 2:
return cfi_spansion_erase(bank, first, last);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -983,7 +1005,6 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
int retry = 0;
- int i;
/* if the device supports neither legacy lock/unlock (bit 3) nor
* instant individual block locking (bit 5).
@@ -995,17 +1016,17 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
cfi_intel_clear_status_register(bank);
- for (i = first; i <= last; i++) {
- retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0));
+ for (int i = first; i <= last; i++) {
+ retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
if (set) {
- retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
bank->sectors[i].is_protected = 1;
} else {
- retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
bank->sectors[i].is_protected = 0;
@@ -1022,7 +1043,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
} else {
uint8_t block_status;
/* read block lock bit, to verify status */
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55));
if (retval != ERROR_OK)
return retval;
retval = cfi_get_u8(bank, i, 0x2, &block_status);
@@ -1033,7 +1054,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
LOG_ERROR(
"couldn't change block lock status (set = %i, block_status = 0x%2.2x)",
set, block_status);
- retval = cfi_send_command(bank, 0x70, flash_address(bank, 0, 0x55));
+ retval = cfi_send_command(bank, 0x70, cfi_flash_address(bank, 0, 0x55));
if (retval != ERROR_OK)
return retval;
uint8_t status;
@@ -1066,15 +1087,15 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
* 3. re-protect what should be protected.
*
*/
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
if (bank->sectors[i].is_protected == 1) {
cfi_intel_clear_status_register(bank);
- retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -1086,10 +1107,10 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
}
}
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
+int cfi_protect(struct flash_bank *bank, int set, int first, int last)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -1105,7 +1126,6 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
case 1:
case 3:
return cfi_intel_protect(bank, set, first, last);
- break;
default:
LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
return ERROR_OK;
@@ -1121,13 +1141,10 @@ static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd)
switch (bank->bus_width) {
case 1:
return buf[0];
- break;
case 2:
return target_buffer_get_u16(target, buf);
- break;
case 4:
return target_buffer_get_u32(target, buf);
- break;
default:
LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes",
bank->bus_width);
@@ -1558,9 +1575,9 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0));
buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80));
- buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
+ buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1));
buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa);
- buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
+ buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2));
buf_set_u32(reg_params[9].value, 0, 32, 0x55555555);
retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
@@ -1937,9 +1954,9 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0));
buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80));
- buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
+ buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1));
buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa);
- buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
+ buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2));
buf_set_u32(reg_params[9].value, 0, 32, 0x55555555);
retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
@@ -1981,14 +1998,13 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
cfi_intel_clear_status_register(bank);
retval = cfi_send_command(bank, 0x40, address);
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, 1, word);
+ retval = cfi_target_write_memory(bank, address, 1, word);
if (retval != ERROR_OK)
return retval;
@@ -1997,7 +2013,7 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t
if (retval != ERROR_OK)
return retval;
if (status != 0x80) {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2015,7 +2031,6 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
/* Calculate buffer size and boundary mask
* buffersize is (buffer size per chip) * (number of chips)
@@ -2052,7 +2067,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
if (retval != ERROR_OK)
return retval;
if (status != 0x80) {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2069,7 +2084,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word);
+ retval = cfi_target_write_memory(bank, address, bufferwsize, word);
if (retval != ERROR_OK)
return retval;
@@ -2083,7 +2098,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
return retval;
if (status != 0x80) {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2100,26 +2115,21 @@ static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint3
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
- struct target *target = bank->target;
-
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xa0, flash_address(bank, 0, pri_ext->_unlock1));
+ retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1));
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, 1, word);
+ retval = cfi_target_write_memory(bank, address, 1, word);
if (retval != ERROR_OK)
return retval;
if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2136,8 +2146,6 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
- struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
/* Calculate buffer size and boundary mask
* buffersize is (buffer size per chip) * (number of chips)
@@ -2163,11 +2171,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
}
/* Unlock */
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
-
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
@@ -2181,7 +2185,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word);
+ retval = cfi_target_write_memory(bank, address, bufferwsize, word);
if (retval != ERROR_OK)
return retval;
@@ -2191,7 +2195,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
return retval;
if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2204,7 +2208,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
return ERROR_OK;
}
-static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
+int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -2212,10 +2216,8 @@ static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t addre
case 1:
case 3:
return cfi_intel_write_word(bank, word, address);
- break;
case 2:
return cfi_spansion_write_word(bank, word, address);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -2239,10 +2241,8 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word,
case 1:
case 3:
return cfi_intel_write_words(bank, word, wordcount, address);
- break;
case 2:
return cfi_spansion_write_words(bank, word, wordcount, address);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -2254,12 +2254,10 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word,
static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
uint32_t address = bank->base + offset;
uint32_t read_p;
int align; /* number of unaligned bytes */
uint8_t current_word[CFI_MAX_BUS_WIDTH];
- int i;
int retval;
LOG_DEBUG("reading buffer of %i byte at 0x%8.8x",
@@ -2283,12 +2281,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
LOG_INFO("Fixup %d unaligned read head bytes", align);
/* read a complete word from flash */
- retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, read_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* take only bytes we need */
- for (i = align; (i < bank->bus_width) && (count > 0); i++, count--)
+ for (int i = align; (i < bank->bus_width) && (count > 0); i++, count--)
*buffer++ = current_word[i];
read_p += bank->bus_width;
@@ -2296,7 +2294,7 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
align = count / bank->bus_width;
if (align) {
- retval = target_read_memory(target, read_p, bank->bus_width, align, buffer);
+ retval = cfi_target_read_memory(bank, read_p, align, buffer);
if (retval != ERROR_OK)
return retval;
@@ -2309,12 +2307,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
LOG_INFO("Fixup %" PRIu32 " unaligned read tail bytes", count);
/* read a complete word from flash */
- retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, read_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* take only bytes we need */
- for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
+ for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
*buffer++ = current_word[i];
}
@@ -2324,7 +2322,6 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
uint32_t address = bank->base + offset; /* address of first byte to be programmed */
uint32_t write_p;
int align; /* number of unaligned bytes */
@@ -2333,7 +2330,6 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
*programmed */
uint8_t *swapped_buffer = NULL;
const uint8_t *real_buffer = NULL;
- int i;
int retval;
if (bank->target->state != TARGET_HALTED) {
@@ -2354,12 +2350,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
LOG_INFO("Fixup %d unaligned head bytes", align);
/* read a complete word from flash */
- retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* replace only bytes that must be written */
- for (i = align;
+ for (int i = align;
(i < bank->bus_width) && (count > 0);
i++, count--)
if (cfi_info->data_swap)
@@ -2425,12 +2421,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
/* fall back to memory writes */
while (count >= (uint32_t)bank->bus_width) {
- int fallback;
+ bool fallback;
if ((write_p & 0xff) == 0) {
LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08"
PRIx32 " bytes remaining", write_p, count);
}
- fallback = 1;
+ fallback = true;
if ((bufferwsize > 0) && (count >= buffersize) &&
!(write_p & buffermask)) {
retval = cfi_write_words(bank, buffer, bufferwsize, write_p);
@@ -2438,13 +2434,13 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
buffer += buffersize;
write_p += buffersize;
count -= buffersize;
- fallback = 0;
+ fallback = false;
} else if (retval != ERROR_FLASH_OPER_UNSUPPORTED)
return retval;
}
/* try the slow way? */
if (fallback) {
- for (i = 0; i < bank->bus_width; i++)
+ for (int i = 0; i < bank->bus_width; i++)
current_word[i] = *buffer++;
retval = cfi_write_word(bank, current_word, write_p);
@@ -2474,12 +2470,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
/* read a complete word from flash */
- retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* replace only bytes that must be written */
- for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
+ for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
if (cfi_info->data_swap)
/* data bytes are swapped (reverse endianness) */
current_word[bank->bus_width - i] = *buffer++;
@@ -2506,7 +2502,6 @@ static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void
static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param)
{
- int i;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
(void) param;
@@ -2514,7 +2509,7 @@ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *pa
if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) {
LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device");
- for (i = 0; i < cfi_info->num_erase_regions / 2; i++) {
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions / 2; i++) {
int j = (cfi_info->num_erase_regions - 1) - i;
uint32_t swap;
@@ -2549,7 +2544,7 @@ static int cfi_query_string(struct flash_bank *bank, int address)
struct cfi_flash_bank *cfi_info = bank->driver_priv;
int retval;
- retval = cfi_send_command(bank, 0x98, flash_address(bank, 0, address));
+ retval = cfi_send_command(bank, 0x98, cfi_flash_address(bank, 0, address));
if (retval != ERROR_OK)
return retval;
@@ -2577,12 +2572,11 @@ static int cfi_query_string(struct flash_bank *bank, int address)
return ERROR_OK;
}
-static int cfi_probe(struct flash_bank *bank)
+int cfi_probe(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct target *target = bank->target;
int num_sectors = 0;
- int i;
int sector = 0;
uint32_t unlock1 = 0x555;
uint32_t unlock2 = 0x2aa;
@@ -2594,7 +2588,7 @@ static int cfi_probe(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
- cfi_info->probed = 0;
+ cfi_info->probed = false;
cfi_info->num_erase_regions = 0;
if (bank->sectors) {
free(bank->sectors);
@@ -2614,22 +2608,22 @@ static int cfi_probe(struct flash_bank *bank)
}
/* switch to read identifier codes mode ("AUTOSELECT") */
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, unlock1));
+ retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, unlock2));
+ retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, unlock2));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, unlock1));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, unlock1));
if (retval != ERROR_OK)
return retval;
- retval = target_read_memory(target, flash_address(bank, 0, 0x00),
- bank->bus_width, 1, value_buf0);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x00),
+ 1, value_buf0);
if (retval != ERROR_OK)
return retval;
- retval = target_read_memory(target, flash_address(bank, 0, 0x01),
- bank->bus_width, 1, value_buf1);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x01),
+ 1, value_buf1);
if (retval != ERROR_OK)
return retval;
switch (bank->chip_width) {
@@ -2766,7 +2760,7 @@ static int cfi_probe(struct flash_bank *bank)
if (cfi_info->num_erase_regions) {
cfi_info->erase_region_info = malloc(sizeof(*cfi_info->erase_region_info)
* cfi_info->num_erase_regions);
- for (i = 0; i < cfi_info->num_erase_regions; i++) {
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) {
retval = cfi_query_u32(bank,
0,
0x2d + (4 * i),
@@ -2881,15 +2875,14 @@ static int cfi_probe(struct flash_bank *bank)
} else {
uint32_t offset = 0;
- for (i = 0; i < cfi_info->num_erase_regions; i++)
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++)
num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
bank->num_sectors = num_sectors;
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
- for (i = 0; i < cfi_info->num_erase_regions; i++) {
- uint32_t j;
- for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) {
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) {
+ for (uint32_t j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) {
bank->sectors[sector].offset = offset;
bank->sectors[sector].size =
((cfi_info->erase_region_info[i] >> 16) * 256)
@@ -2902,18 +2895,18 @@ static int cfi_probe(struct flash_bank *bank)
}
if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) {
LOG_WARNING(
- "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \
+ "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "",
(cfi_info->dev_size * bank->bus_width / bank->chip_width),
offset);
}
}
- cfi_info->probed = 1;
+ cfi_info->probed = true;
return ERROR_OK;
}
-static int cfi_auto_probe(struct flash_bank *bank)
+int cfi_auto_probe(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
if (cfi_info->probed)
@@ -2926,17 +2919,16 @@ static int cfi_intel_protect_check(struct flash_bank *bank)
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
- int i;
/* check if block lock bits are supported on this device */
if (!(pri_ext->blk_status_reg_mask & 0x1))
return ERROR_FLASH_OPERATION_FAILED;
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55));
if (retval != ERROR_OK)
return retval;
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
uint8_t block_status;
retval = cfi_get_u8(bank, i, 0x2, &block_status);
if (retval != ERROR_OK)
@@ -2948,7 +2940,7 @@ static int cfi_intel_protect_check(struct flash_bank *bank)
bank->sectors[i].is_protected = 0;
}
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
}
static int cfi_spansion_protect_check(struct flash_bank *bank)
@@ -2956,21 +2948,16 @@ static int cfi_spansion_protect_check(struct flash_bank *bank)
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
- int i;
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, pri_ext->_unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
-
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
uint8_t block_status;
retval = cfi_get_u8(bank, i, 0x2, &block_status);
if (retval != ERROR_OK)
@@ -2982,10 +2969,10 @@ static int cfi_spansion_protect_check(struct flash_bank *bank)
bank->sectors[i].is_protected = 0;
}
- return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_protect_check(struct flash_bank *bank)
+int cfi_protect_check(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -3001,10 +2988,8 @@ static int cfi_protect_check(struct flash_bank *bank)
case 1:
case 3:
return cfi_intel_protect_check(bank);
- break;
case 2:
return cfi_spansion_protect_check(bank);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -3013,7 +2998,7 @@ static int cfi_protect_check(struct flash_bank *bank)
return ERROR_OK;
}
-static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size)
+int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
int printed;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -3124,6 +3109,6 @@ const struct flash_driver cfi_flash = {
/* FIXME: access flash at bus_width size */
.erase_check = default_flash_blank_check,
.protect_check = cfi_protect_check,
- .info = get_cfi_info,
+ .info = cfi_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h
index ed858a9..aef7a04 100644
--- a/src/flash/nor/cfi.h
+++ b/src/flash/nor/cfi.h
@@ -73,6 +73,12 @@ struct cfi_flash_bank {
unsigned buf_write_timeout;
unsigned block_erase_timeout;
unsigned chip_erase_timeout;
+
+ /* memory accessors */
+ int (*write_mem)(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, const uint8_t *buffer);
+ int (*read_mem)(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer);
};
/* Intel primary extended query table
@@ -148,6 +154,24 @@ struct cfi_fixup {
const void *param;
};
+int cfi_erase(struct flash_bank *bank, int first, int last);
+int cfi_protect(struct flash_bank *bank, int set, int first, int last);
+int cfi_probe(struct flash_bank *bank);
+int cfi_auto_probe(struct flash_bank *bank);
+int cfi_protect_check(struct flash_bank *bank);
+int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size);
+int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv);
+
+uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset);
+int cfi_spansion_unlock_seq(struct flash_bank *bank);
+int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address);
+int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address);
+int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout);
+int cfi_reset(struct flash_bank *bank);
+
+int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer);
+
#define CFI_MFR_AMD 0x0001
#define CFI_MFR_FUJITSU 0x0004
#define CFI_MFR_ATMEL 0x001F
@@ -160,4 +184,7 @@ struct cfi_fixup {
#define CFI_MFR_ANY 0xffff
#define CFI_ID_ANY 0xffff
+#define CFI_MAX_BUS_WIDTH 4
+#define CFI_MAX_CHIP_WIDTH 4
+
#endif /* OPENOCD_FLASH_NOR_CFI_H */
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 551f389..d52e072 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -66,6 +66,8 @@ extern const struct flash_driver psoc5lp_flash;
extern const struct flash_driver psoc5lp_eeprom_flash;
extern const struct flash_driver psoc5lp_nvl_flash;
extern const struct flash_driver psoc6_flash;
+extern const struct flash_driver renesas_rpchf_flash;
+extern const struct flash_driver sh_qspi_flash;
extern const struct flash_driver sim3x_flash;
extern const struct flash_driver stellaris_flash;
extern const struct flash_driver stm32f1x_flash;
@@ -136,6 +138,8 @@ static const struct flash_driver * const flash_drivers[] = {
&psoc5lp_eeprom_flash,
&psoc5lp_nvl_flash,
&psoc6_flash,
+ &renesas_rpchf_flash,
+ &sh_qspi_flash,
&sim3x_flash,
&stellaris_flash,
&stm32f1x_flash,
diff --git a/src/flash/nor/dsp5680xx_flash.c b/src/flash/nor/dsp5680xx_flash.c
index 37b60f0..da67585 100644
--- a/src/flash/nor/dsp5680xx_flash.c
+++ b/src/flash/nor/dsp5680xx_flash.c
@@ -154,7 +154,7 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
*
* @return
*/
-static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t* buffer,
+static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
int retval;
diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c
index 83d133f..fe4ddd4 100644
--- a/src/flash/nor/efm32.c
+++ b/src/flash/nor/efm32.c
@@ -99,7 +99,7 @@ struct efm32_family_data {
};
struct efm32x_flash_bank {
- int probed;
+ bool probed;
uint32_t lb_page[LOCKBITS_PAGE_SZ/4];
uint32_t reg_base;
uint32_t reg_lock;
@@ -140,6 +140,7 @@ static const struct efm32_family_data efm32_families[] = {
{ 43, "EFR32BG13P Blue", .series = 1 },
{ 44, "EFR32BG13B Blue", .series = 1 },
{ 45, "EFR32BG13V Blue", .series = 1 },
+ { 46, "EFR32ZG13P Zen", .series = 1 },
{ 49, "EFR32FG13P Flex", .series = 1 },
{ 50, "EFR32FG13B Flex", .series = 1 },
{ 51, "EFR32FG13V Flex", .series = 1 },
@@ -149,6 +150,7 @@ static const struct efm32_family_data efm32_families[] = {
{ 55, "EFR32BG14P Blue", .series = 1 },
{ 56, "EFR32BG14B Blue", .series = 1 },
{ 57, "EFR32BG14V Blue", .series = 1 },
+ { 58, "EFR32ZG14P Zen", .series = 1 },
{ 61, "EFR32FG14P Flex", .series = 1 },
{ 62, "EFR32FG14B Flex", .series = 1 },
{ 63, "EFR32FG14V Flex", .series = 1 },
@@ -166,7 +168,8 @@ static const struct efm32_family_data efm32_families[] = {
{ 89, "EFM32PG13B Pearl", .series = 1 },
{ 91, "EFM32JG13B Jade", .series = 1 },
{ 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 },
- { 103, "EFM32TG11B Tiny", .series = 1 },
+ { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 },
+ { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 },
{ 120, "EZR32WG Wonder", .series = 0 },
{ 121, "EZR32LG Leopard", .series = 0 },
{ 122, "EZR32HG Happy", .series = 0, .page_size = 1024 },
@@ -348,7 +351,7 @@ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command)
efm32x_info = malloc(sizeof(struct efm32x_flash_bank));
bank->driver_priv = efm32x_info;
- efm32x_info->probed = 0;
+ efm32x_info->probed = false;
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
return ERROR_OK;
@@ -467,7 +470,6 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
static int efm32x_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
- int i = 0;
int ret = 0;
if (TARGET_HALTED != target->state) {
@@ -482,7 +484,7 @@ static int efm32x_erase(struct flash_bank *bank, int first, int last)
return ret;
}
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
ret = efm32x_erase_page(bank, bank->sectors[i].offset);
if (ERROR_OK != ret)
LOG_ERROR("Failed to erase page %d", i);
@@ -498,7 +500,6 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
{
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
struct target *target = bank->target;
- int i = 0;
int data_size = 0;
uint32_t *ptr = NULL;
int ret = 0;
@@ -510,7 +511,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
ptr = efm32x_info->lb_page;
- for (i = 0; i < data_size; i++, ptr++) {
+ for (int i = 0; i < data_size; i++, ptr++) {
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to read PLW %d", i);
@@ -616,7 +617,6 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set)
static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
- int i = 0;
int ret = 0;
if (!set) {
@@ -629,7 +629,7 @@ static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_TARGET_NOT_HALTED;
}
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
ret = efm32x_set_page_lock(bank, i, set);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to set lock on page %d", i);
@@ -960,11 +960,10 @@ static int efm32x_probe(struct flash_bank *bank)
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
struct efm32_info efm32_mcu_info;
int ret;
- int i;
uint32_t base_address = 0x00000000;
char buf[256];
- efm32x_info->probed = 0;
+ efm32x_info->probed = false;
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
ret = efm32x_read_info(bank, &efm32_mcu_info);
@@ -1003,14 +1002,14 @@ static int efm32x_probe(struct flash_bank *bank)
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
- for (i = 0; i < num_pages; i++) {
+ for (int i = 0; i < num_pages; i++) {
bank->sectors[i].offset = i * efm32_mcu_info.page_size;
bank->sectors[i].size = efm32_mcu_info.page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
- efm32x_info->probed = 1;
+ efm32x_info->probed = true;
return ERROR_OK;
}
@@ -1027,7 +1026,6 @@ static int efm32x_protect_check(struct flash_bank *bank)
{
struct target *target = bank->target;
int ret = 0;
- int i = 0;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -1042,7 +1040,7 @@ static int efm32x_protect_check(struct flash_bank *bank)
assert(NULL != bank->sectors);
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i);
return ERROR_OK;
diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c
index 6b05332..bc192b6 100644
--- a/src/flash/nor/fespi.c
+++ b/src/flash/nor/fespi.c
@@ -183,7 +183,7 @@ static int fespi_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_
}
static int fespi_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value)
-{ \
+{
struct target *target = bank->target;
struct fespi_flash_bank *fespi_info = bank->driver_priv;
diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c
index a8877b4..7e3a1c5 100644
--- a/src/flash/nor/fm4.c
+++ b/src/flash/nor/fm4.c
@@ -207,7 +207,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
uint32_t result;
unsigned i;
- int retval;
+ int retval, retval2 = ERROR_OK;
const uint8_t write_block_code[] = {
#include "../../../contrib/loaders/flash/fm4/write.inc"
};
@@ -327,7 +327,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
err_run_ret:
err_run:
err_write_data:
- retval = fm4_enter_flash_cpu_rom_mode(target);
+ retval2 = fm4_enter_flash_cpu_rom_mode(target);
err_flash_mode:
for (i = 0; i < ARRAY_SIZE(reg_params); i++)
@@ -338,7 +338,9 @@ err_alloc_data:
err_write_code:
target_free_working_area(target, code_workarea);
- return retval;
+ if (retval != ERROR_OK)
+ return retval;
+ return retval2;
}
static int mb9bf_probe(struct flash_bank *bank)
diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c
index a9f2dd4..d841579 100644
--- a/src/flash/nor/jtagspi.c
+++ b/src/flash/nor/jtagspi.c
@@ -59,7 +59,7 @@ static void jtagspi_set_ir(struct flash_bank *bank)
{
struct jtagspi_flash_bank *info = bank->driver_priv;
struct scan_field field;
- uint8_t buf[4];
+ uint8_t buf[4] = { 0 };
LOG_DEBUG("loading jtagspi ir");
buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
@@ -153,12 +153,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
jtagspi_set_ir(bank);
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
- jtag_execute_queue();
+ int retval = jtag_execute_queue();
if (is_read)
flip_u8(data_buf, data, lenb);
free(data_buf);
- return ERROR_OK;
+ return retval;
}
static int jtagspi_probe(struct flash_bank *bank)
@@ -228,13 +228,16 @@ static int jtagspi_probe(struct flash_bank *bank)
return ERROR_OK;
}
-static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
+static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
{
uint8_t buf;
- if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) {
+ int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8);
+ if (err == ERROR_OK) {
*status = buf;
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
}
+
+ return err;
}
static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
@@ -245,7 +248,11 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
do {
dt = timeval_ms() - t0;
- jtagspi_read_status(bank, &status);
+
+ int retval = jtagspi_read_status(bank, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
if ((status & SPIFLASH_BSY_BIT) == 0) {
LOG_DEBUG("waited %" PRId64 " ms", dt);
return ERROR_OK;
@@ -262,7 +269,11 @@ static int jtagspi_write_enable(struct flash_bank *bank)
uint32_t status;
jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0);
- jtagspi_read_status(bank, &status);
+
+ int retval = jtagspi_read_status(bank, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
if ((status & SPIFLASH_WE_BIT) == 0) {
LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
return ERROR_FAIL;
diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c
index 687a337..084e009 100644
--- a/src/flash/nor/kinetis.c
+++ b/src/flash/nor/kinetis.c
@@ -787,9 +787,8 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) {
uint32_t stats[32];
- int i;
- for (i = 0; i < 32; i++) {
+ for (unsigned int i = 0; i < 32; i++) {
stats[i] = MDM_STAT_FREADY;
dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]);
}
@@ -798,7 +797,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
LOG_DEBUG("MDM: dap_run failed when validating secured state");
return ERROR_OK;
}
- for (i = 0; i < 32; i++) {
+ for (unsigned int i = 0; i < 32; i++) {
if (stats[i] & MDM_STAT_SYSSEC)
secured_score++;
if (!(stats[i] & MDM_STAT_FREADY))
@@ -860,8 +859,7 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target)
static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[])
{
- int i;
- for (i = 0; i < argc; i++) {
+ for (int 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);
@@ -933,7 +931,6 @@ static void kinetis_free_driver_priv(struct flash_bank *bank)
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;
@@ -968,7 +965,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
*p = '\0';
}
- for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) {
+ for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) {
k_bank = &(k_chip->banks[bank_idx]);
bank = k_bank->bank;
@@ -1219,11 +1216,11 @@ static int kinetis_ftfx_clear_error(struct target *target)
static int kinetis_ftfx_prepare(struct target *target)
{
- int result, i;
+ int result;
uint8_t fstat;
/* wait until busy */
- for (i = 0; i < 50; i++) {
+ for (unsigned int i = 0; i < 50; i++) {
result = target_read_u8(target, FTFx_FSTAT, &fstat);
if (result != ERROR_OK)
return result;
@@ -1343,8 +1340,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
static int kinetis_protect(struct flash_bank *bank, int set, int first, int last)
{
- int i;
-
if (allow_fcf_writes) {
LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!");
return ERROR_FAIL;
@@ -1355,7 +1350,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last
return ERROR_FLASH_BANK_INVALID;
}
- for (i = first; i < bank->num_prot_blocks && i <= last; i++)
+ for (int i = first; i < bank->num_prot_blocks && i <= last; i++)
bank->prot_blocks[i].is_protected = set;
LOG_INFO("Protection bits will be written at the next FCF sector erase or write.");
@@ -1369,7 +1364,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
{
struct kinetis_flash_bank *k_bank = bank->driver_priv;
int result;
- int i, b;
+ int b;
uint32_t fprot;
if (k_bank->flash_class == FC_PFLASH) {
@@ -1397,7 +1392,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
}
b = k_bank->protection_block;
- for (i = 0; i < bank->num_prot_blocks; i++) {
+ for (int i = 0; i < bank->num_prot_blocks; i++) {
if ((fprot >> b) & 1)
bank->prot_blocks[i].is_protected = 0;
else
@@ -1415,8 +1410,6 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
uint32_t fprot = 0xffffffff;
uint8_t fsec = 0xfe; /* set MCU unsecure */
uint8_t fdprot = 0xff;
- int i;
- unsigned bank_idx;
unsigned num_blocks;
uint32_t pflash_bit;
uint8_t dflash_bit;
@@ -1432,7 +1425,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
/* iterate over all kinetis banks */
/* current bank is bank 0, it contains FCF */
num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks;
- for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) {
+ for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) {
k_bank = &(k_chip->banks[bank_idx]);
bank_iter = k_bank->bank;
@@ -1443,8 +1436,10 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
kinetis_auto_probe(bank_iter);
+ assert(bank_iter->prot_blocks);
+
if (k_bank->flash_class == FC_PFLASH) {
- for (i = 0; i < bank_iter->num_prot_blocks; i++) {
+ for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
if (bank_iter->prot_blocks[i].is_protected == 1)
fprot &= ~pflash_bit;
@@ -1452,7 +1447,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
}
} else if (k_bank->flash_class == FC_FLEX_NVM) {
- for (i = 0; i < bank_iter->num_prot_blocks; i++) {
+ for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
if (bank_iter->prot_blocks[i].is_protected == 1)
fdprot &= ~dflash_bit;
@@ -1540,7 +1535,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat)
static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
{
- int result, i;
+ int result;
uint8_t pmstat;
struct target *target;
@@ -1578,7 +1573,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
if (result != ERROR_OK)
return result;
- for (i = 100; i; i--) {
+ for (unsigned int i = 100; i > 0; i--) {
result = kinetis_read_pmstat(k_chip, &pmstat);
if (result != ERROR_OK)
return result;
@@ -1623,7 +1618,7 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip)
static int kinetis_erase(struct flash_bank *bank, int first, int last)
{
- int result, i;
+ int result;
struct kinetis_flash_bank *k_bank = bank->driver_priv;
struct kinetis_chip *k_chip = k_bank->k_chip;
@@ -1644,7 +1639,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
* requested erase is PFlash or NVM and encompasses the entire
* block. Should be quicker.
*/
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
/* set command and sector address */
result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset,
0, 0, 0, 0, 0, 0, 0, 0, NULL);
@@ -1798,6 +1793,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
buffer += size;
offset += size;
count -= size;
+
+ keep_alive();
}
free(buffer_aligned);
@@ -1808,25 +1805,26 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
- int result, fallback = 0;
+ int result;
+ bool fallback = false;
struct kinetis_flash_bank *k_bank = bank->driver_priv;
struct kinetis_chip *k_chip = k_bank->k_chip;
if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) {
/* fallback to longword write */
- fallback = 1;
+ fallback = true;
LOG_INFO("This device supports Program Longword execution only.");
} else {
result = kinetis_make_ram_ready(bank->target);
if (result != ERROR_OK) {
- fallback = 1;
+ fallback = true;
LOG_WARNING("FlexRAM not ready, fallback to slow longword write.");
}
}
LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset);
- if (fallback == 0) {
+ if (!fallback) {
/* program section command */
kinetis_write_sections(bank, buffer, offset, count);
} else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) {
@@ -1889,6 +1887,8 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
buffer += 4;
offset += 4;
words_remaining--;
+
+ keep_alive();
}
}
free(new_buffer);
@@ -2018,7 +2018,6 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
unsigned familyid = 0, subfamid = 0;
unsigned cpu_mhz = 120;
- unsigned idx;
bool use_nvm_marking = false;
char flash_marking[12], nvm_marking[2];
char name[40];
@@ -2113,7 +2112,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
LOG_ERROR("Unsupported K-family FAMID");
}
- for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) {
+ for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) {
if (kinetis_types_old[idx].sdid == mcu_type) {
strcpy(name, kinetis_types_old[idx].name);
use_nvm_marking = true;
@@ -2619,12 +2618,15 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
static int kinetis_probe(struct flash_bank *bank)
{
- int result, i;
+ int result;
uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1;
unsigned num_blocks, first_nvm_bank;
uint32_t size_k;
struct kinetis_flash_bank *k_bank = bank->driver_priv;
- struct kinetis_chip *k_chip = k_bank->k_chip;
+ struct kinetis_chip *k_chip;
+
+ assert(k_bank);
+ k_chip = k_bank->k_chip;
k_bank->probed = false;
@@ -2668,6 +2670,7 @@ static int kinetis_probe(struct flash_bank *bank)
if (k_chip->dflash_size == 0) {
k_bank->protection_size = 0;
} else {
+ int i;
for (i = k_chip->dflash_size; ~i & 1; i >>= 1)
;
if (i == 1)
@@ -2824,8 +2827,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
if (block_dirty) {
/* the whole bank is not erased, check sector-by-sector */
- int i;
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
/* normal margin */
result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT,
k_bank->prog_base + bank->sectors[i].offset,
@@ -2841,8 +2843,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
}
} else {
/* the whole bank is erased, update all sectors */
- int i;
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
}
} else {
diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c
index 27b6d3a..cfc0492 100644
--- a/src/flash/nor/kinetis_ke.c
+++ b/src/flash/nor/kinetis_ke.c
@@ -814,7 +814,7 @@ static int kinetis_ke_protect_check(struct flash_bank *bank)
kinfo->protection_size = 0;
} else {
- LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", \
+ LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i",
fpopen ? 1 : 0, fpldis ? 1 : 0, fphdis ? 1 : 0, fpls, fphs);
/* Retrieve which region is protected and how much */
diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c
index 19d754b..04ac3bb 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -177,8 +177,8 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
retval = target_alloc_working_area(target, sizeof(spifi_init_code)
+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
if (retval != ERROR_OK) {
- LOG_ERROR("Insufficient working area to initialize SPIFI "\
- "module. You must allocate at least %zdB of working "\
+ LOG_ERROR("Insufficient working area to initialize SPIFI "
+ "module. You must allocate at least %zdB of working "
"area in order to use this driver.",
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
);
@@ -452,7 +452,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
* it, use a bulk erase instead of going sector-by-sector. */
if (first == 0 && last == (bank->num_sectors - 1)
&& lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) {
- LOG_DEBUG("Chip supports the bulk erase command."\
+ LOG_DEBUG("Chip supports the bulk erase command."
" Will use bulk erase instead of sector-by-sector erase.");
retval = lpcspifi_bulk_erase(bank);
@@ -525,7 +525,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code),
&erase_algorithm);
if (retval != ERROR_OK) {
- LOG_ERROR("Insufficient working area. You must configure a working"\
+ LOG_ERROR("Insufficient working area. You must configure a working"
" area of at least %zdB in order to erase SPIFI flash.",
sizeof(lpcspifi_flash_erase_code));
return retval;
@@ -685,7 +685,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
&write_algorithm) != ERROR_OK) {
- LOG_ERROR("Insufficient working area. You must configure"\
+ LOG_ERROR("Insufficient working area. You must configure"
" a working area > %zdB in order to write to SPIFI flash.",
sizeof(lpcspifi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -707,15 +707,15 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
* space, free the algorithm */
target_free_working_area(target, write_algorithm);
- LOG_ERROR("Insufficient working area. Please allocate at least"\
+ LOG_ERROR("Insufficient working area. Please allocate at least"
" %zdB of working area to enable flash writes.",
sizeof(lpcspifi_flash_write_code) + 1
);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} else if (fifo_size < page_size)
- LOG_WARNING("Working area size is limited; flash writes may be"\
- " slow. Increase working area size to at least %zdB"\
+ LOG_WARNING("Working area size is limited; flash writes may be"
+ " slow. Increase working area size to at least %zdB"
" to reduce write times.",
(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
);
diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c
index 803e84a..7a06b3d 100644
--- a/src/flash/nor/mrvlqspi.c
+++ b/src/flash/nor/mrvlqspi.c
@@ -563,7 +563,7 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last)
if (first == 0 && last == (bank->num_sectors - 1)
&& mrvlqspi_info->dev->chip_erase_cmd !=
mrvlqspi_info->dev->erase_cmd) {
- LOG_DEBUG("Chip supports the bulk erase command."\
+ LOG_DEBUG("Chip supports the bulk erase command."
" Will use bulk erase instead of sector-by-sector erase.");
retval = mrvlqspi_bulk_erase(bank);
if (retval == ERROR_OK) {
@@ -681,7 +681,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code),
&write_algorithm) != ERROR_OK) {
- LOG_ERROR("Insufficient working area. You must configure"\
+ LOG_ERROR("Insufficient working area. You must configure"
" a working area > %zdB in order to write to SPIFI flash.",
sizeof(mrvlqspi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -703,15 +703,15 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
* space, free the algorithm */
target_free_working_area(target, write_algorithm);
- LOG_ERROR("Insufficient working area. Please allocate at least"\
+ LOG_ERROR("Insufficient working area. Please allocate at least"
" %zdB of working area to enable flash writes.",
sizeof(mrvlqspi_flash_write_code) + 1
);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} else if (fifo_size < page_size)
- LOG_WARNING("Working area size is limited; flash writes may be"\
- " slow. Increase working area size to at least %zdB"\
+ LOG_WARNING("Working area size is limited; flash writes may be"
+ " slow. Increase working area size to at least %zdB"
" to reduce write times.",
(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
);
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
index e9e4be3..95c99b9 100644
--- a/src/flash/nor/msp432.c
+++ b/src/flash/nor/msp432.c
@@ -49,7 +49,8 @@ struct msp432_bank {
int family_type;
int device_type;
uint32_t sector_length;
- bool probed[2];
+ bool probed_main;
+ bool probed_info;
bool unlock_bsl;
struct working_area *working_area;
struct armv7m_algorithm armv7m_info;
@@ -194,8 +195,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params
return retval;
/* Write out command to target memory */
- retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR,
- sizeof(command), (uint8_t *)&command);
+ retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command);
return retval;
}
@@ -210,8 +210,7 @@ static int msp432_wait_return_code(struct target *target)
start_ms = timeval_ms();
while ((0 == return_code) || (FLASH_BUSY == return_code)) {
- retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR,
- sizeof(return_code), (uint8_t *)&return_code);
+ retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code);
if (ERROR_OK != retval)
return retval;
@@ -253,8 +252,7 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer)
start_ms = timeval_ms();
while (BUFFER_INACTIVE != status_code) {
- retval = target_read_buffer(target, status_addr, sizeof(status_code),
- (uint8_t *)&status_code);
+ retval = target_read_u32(target, status_addr, &status_code);
if (ERROR_OK != retval)
return retval;
@@ -477,15 +475,23 @@ COMMAND_HANDLER(msp432_mass_erase_command)
struct flash_bank *bank;
struct msp432_bank *msp432_bank;
bool all;
+
int retval;
- if (0 == CMD_ARGC) {
+ if (1 > CMD_ARGC)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (1 == CMD_ARGC) {
all = false;
- } else if (1 == CMD_ARGC) {
+ } else if (2 == CMD_ARGC) {
/* Check argument for how much to erase */
- if (0 == strcmp(CMD_ARGV[0], "main"))
+ if (0 == strcmp(CMD_ARGV[1], "main"))
all = false;
- else if (0 == strcmp(CMD_ARGV[0], "all"))
+ else if (0 == strcmp(CMD_ARGV[1], "all"))
all = true;
else
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -493,10 +499,6 @@ COMMAND_HANDLER(msp432_mass_erase_command)
return ERROR_COMMAND_SYNTAX_ERROR;
}
- retval = get_flash_bank_by_num(0, &bank);
- if (ERROR_OK != retval)
- return retval;
-
msp432_bank = bank->driver_priv;
if (MSP432E4 == msp432_bank->family_type) {
@@ -513,7 +515,7 @@ COMMAND_HANDLER(msp432_mass_erase_command)
LOG_INFO("msp432: Mass erase of flash is complete");
} else {
LOG_INFO("msp432: Mass erase of %s is complete",
- all ? "main + info flash" : "main flash");
+ all ? "main + information flash" : "main flash");
}
return ERROR_OK;
@@ -523,13 +525,14 @@ COMMAND_HANDLER(msp432_bsl_command)
{
struct flash_bank *bank;
struct msp432_bank *msp432_bank;
+
int retval;
- if (1 < CMD_ARGC)
+ if (1 > CMD_ARGC)
return ERROR_COMMAND_SYNTAX_ERROR;
- retval = get_flash_bank_by_num(0, &bank);
- if (ERROR_OK != retval)
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
return retval;
msp432_bank = bank->driver_priv;
@@ -539,13 +542,16 @@ COMMAND_HANDLER(msp432_bsl_command)
return ERROR_OK;
}
- if (1 == CMD_ARGC) {
- if (0 == strcmp(CMD_ARGV[0], "lock"))
+ if (2 == CMD_ARGC) {
+ if (0 == strcmp(CMD_ARGV[1], "lock"))
msp432_bank->unlock_bsl = false;
- else if (0 == strcmp(CMD_ARGV[0], "unlock"))
+ else if (0 == strcmp(CMD_ARGV[1], "unlock"))
msp432_bank->unlock_bsl = true;
else
return ERROR_COMMAND_SYNTAX_ERROR;
+ } else if (1 != CMD_ARGC) {
+ /* Extra, unknown argument passed in */
+ return ERROR_COMMAND_SYNTAX_ERROR;
}
LOG_INFO("msp432: BSL flash region is currently %slocked",
@@ -561,6 +567,7 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
+ /* Create shared private struct for flash banks */
msp432_bank = malloc(sizeof(struct msp432_bank));
if (NULL == msp432_bank)
return ERROR_FAIL;
@@ -571,14 +578,14 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
msp432_bank->family_type = MSP432_NO_FAMILY;
msp432_bank->device_type = MSP432_NO_TYPE;
msp432_bank->sector_length = 0x1000;
- msp432_bank->probed[0] = false;
- msp432_bank->probed[1] = false;
+ msp432_bank->probed_main = false;
+ msp432_bank->probed_info = false;
msp432_bank->unlock_bsl = false;
msp432_bank->working_area = NULL;
- /* Finish initialization of bank 0 (main flash) */
+ /* Finish up initial settings here */
bank->driver_priv = msp432_bank;
- bank->next = NULL;
+ bank->base = FLASH_BASE;
return ERROR_OK;
}
@@ -589,6 +596,9 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
struct msp432_bank *msp432_bank = bank->driver_priv;
struct msp432_algo_params algo_params;
+ bool is_main = FLASH_BASE == bank->base;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
+
int retval;
if (TARGET_HALTED != target->state) {
@@ -597,8 +607,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
}
/* Do a mass erase if user requested all sectors of main flash */
- if ((0 == bank->bank_number) && (first == 0) &&
- (last == (bank->num_sectors - 1))) {
+ if (is_main && (first == 0) && (last == (bank->num_sectors - 1))) {
/* Request mass erase of main flash */
return msp432_mass_erase(bank, false);
}
@@ -611,7 +620,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
msp432_init_params(&algo_params);
/* Adjust params if this is the info bank */
- if (1 == bank->bank_number) {
+ if (is_info) {
buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO);
/* And flag if BSL is unlocked */
if (msp432_bank->unlock_bsl)
@@ -622,11 +631,11 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
for (int i = first; i <= last; i++) {
/* Skip TVL (read-only) sector of the info bank */
- if (1 == bank->bank_number && 1 == i)
+ if (is_info && 1 == i)
continue;
/* Skip BSL sectors of info bank if locked */
- if (1 == bank->bank_number && (2 == i || 3 == i) &&
+ if (is_info && (2 == i || 3 == i) &&
!msp432_bank->unlock_bsl)
continue;
@@ -666,6 +675,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
long long start_ms;
long long elapsed_ms;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
+
int retval;
if (TARGET_HALTED != target->state) {
@@ -679,7 +690,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
* The BSL region in sectors 2 and 3 of the info flash may be unlocked
* The helper algorithm will hang on attempts to write to TVL
*/
- if (1 == bank->bank_number) {
+ if (is_info) {
/* Set read-only start to TVL sector */
uint32_t start = 0x1000;
/* Set read-only end after BSL region if locked */
@@ -722,7 +733,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
buf_set_u32(algo_params.length, 0, 32, count);
/* Check if this is the info bank */
- if (1 == bank->bank_number) {
+ if (is_info) {
/* And flag if BSL is unlocked */
if (msp432_bank->unlock_bsl)
buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
@@ -753,8 +764,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* Signal the flash helper algorithm that data is ready to flash */
- retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR,
- sizeof(data_ready), (uint8_t *)&data_ready);
+ retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR,
+ data_ready);
if (ERROR_OK != retval) {
(void)msp432_quit(bank);
return ERROR_FLASH_OPERATION_FAILED;
@@ -793,20 +804,23 @@ static int msp432_probe(struct flash_bank *bank)
struct target *target = bank->target;
struct msp432_bank *msp432_bank = bank->driver_priv;
- char *name;
-
uint32_t device_id;
uint32_t hardware_rev;
- uint32_t base;
uint32_t sector_length;
uint32_t size;
int num_sectors;
- int bank_id;
+
+ bool is_main = FLASH_BASE == bank->base;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
int retval;
- bank_id = bank->bank_number;
+ /* Check if this bank has already been successfully probed */
+ if (is_main && msp432_bank->probed_main)
+ return ERROR_OK;
+ if (is_info && msp432_bank->probed_info)
+ return ERROR_OK;
/* Read the flash size register to determine this is a P4 or not */
/* MSP432P4s will return the size of flash. MSP432E4s will return zero */
@@ -849,63 +863,16 @@ static int msp432_probe(struct flash_bank *bank)
msp432_bank->device_type = msp432_device_type(msp432_bank->family_type,
msp432_bank->device_id, msp432_bank->hardware_rev);
- /* If not already allocated, create the info bank for MSP432P4 */
- /* We could not determine it was needed until device was probed */
- if (MSP432P4 == msp432_bank->family_type) {
- /* If we've been given bank 1, then this was already done */
- if (0 == bank_id) {
- /* And only allocate it if it doesn't exist yet */
- if (NULL == bank->next) {
- struct flash_bank *info_bank;
- info_bank = malloc(sizeof(struct flash_bank));
- if (NULL == info_bank)
- return ERROR_FAIL;
-
- name = malloc(strlen(bank->name)+1);
- if (NULL == name) {
- free(info_bank);
- return ERROR_FAIL;
- }
- strcpy(name, bank->name);
-
- /* Initialize bank 1 (info region) */
- info_bank->name = name;
- info_bank->target = bank->target;
- info_bank->driver = bank->driver;
- info_bank->driver_priv = bank->driver_priv;
- info_bank->bank_number = 1;
- info_bank->base = 0x00200000;
- info_bank->size = 0;
- info_bank->chip_width = 0;
- info_bank->bus_width = 0;
- info_bank->erased_value = 0xff;
- info_bank->default_padded_value = 0xff;
- info_bank->write_start_alignment = 0;
- info_bank->write_end_alignment = 0;
- info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
- info_bank->num_sectors = 0;
- info_bank->sectors = NULL;
- info_bank->num_prot_blocks = 0;
- info_bank->prot_blocks = NULL;
- info_bank->next = NULL;
-
- /* Enable the new bank */
- bank->next = info_bank;
- }
- }
- }
-
if (MSP432P4 == msp432_bank->family_type) {
/* Set up MSP432P4 specific flash parameters */
- if (0 == bank_id) {
+ if (is_main) {
retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
if (ERROR_OK != retval)
return retval;
- base = P4_FLASH_MAIN_BASE;
sector_length = P4_SECTOR_LENGTH;
num_sectors = size / sector_length;
- } else if (1 == bank_id) {
+ } else if (is_info) {
if (msp432_bank->device_type == MSP432P411X ||
msp432_bank->device_type == MSP432P411X_GUESS) {
/* MSP432P411x has an info size register, use that for size */
@@ -916,19 +883,22 @@ static int msp432_probe(struct flash_bank *bank)
/* All other MSP432P401x devices have fixed info region size */
size = 0x4000; /* 16 KB info region */
}
- base = P4_FLASH_INFO_BASE;
sector_length = P4_SECTOR_LENGTH;
num_sectors = size / sector_length;
} else {
- /* Invalid bank number somehow */
+ /* Invalid bank somehow */
return ERROR_FAIL;
}
} else {
/* Set up MSP432E4 specific flash parameters */
- base = E4_FLASH_BASE;
- size = E4_FLASH_SIZE;
- sector_length = E4_SECTOR_LENGTH;
- num_sectors = size / sector_length;
+ if (is_main) {
+ size = E4_FLASH_SIZE;
+ sector_length = E4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ } else {
+ /* Invalid bank somehow */
+ return ERROR_FAIL;
+ }
}
if (NULL != bank->sectors) {
@@ -936,11 +906,12 @@ static int msp432_probe(struct flash_bank *bank)
bank->sectors = NULL;
}
- bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
- if (NULL == bank->sectors)
- return ERROR_FAIL;
+ if (num_sectors > 0) {
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+ if (NULL == bank->sectors)
+ return ERROR_FAIL;
+ }
- bank->base = base;
bank->size = size;
bank->write_start_alignment = 0;
bank->write_end_alignment = 0;
@@ -955,7 +926,31 @@ static int msp432_probe(struct flash_bank *bank)
}
/* We've successfully determined the stats on this flash bank */
- msp432_bank->probed[bank_id] = true;
+ if (is_main)
+ msp432_bank->probed_main = true;
+ if (is_info)
+ msp432_bank->probed_info = true;
+
+ if (is_main && MSP432P4 == msp432_bank->family_type) {
+ /* Create the info flash bank needed by MSP432P4 variants */
+ struct flash_bank *info = calloc(sizeof(struct flash_bank), 1);
+ if (NULL == info)
+ return ERROR_FAIL;
+
+ /* Create a name for the info bank, append "_1" to main name */
+ char *name = malloc(strlen(bank->name) + 3);
+ strcpy(name, bank->name);
+ strcat(name, "_1");
+
+ /* Initialize info bank */
+ info->name = name;
+ info->target = bank->target;
+ info->driver = bank->driver;
+ info->driver_priv = msp432_bank;
+ info->base = P4_FLASH_INFO_BASE;
+
+ flash_bank_add(info);
+ }
/* If we fall through to here, then all went well */
@@ -966,15 +961,17 @@ static int msp432_auto_probe(struct flash_bank *bank)
{
struct msp432_bank *msp432_bank = bank->driver_priv;
- int retval = ERROR_OK;
+ bool is_main = FLASH_BASE == bank->base;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
- if (bank->bank_number < 0 || bank->bank_number > 1) {
- /* Invalid bank number somehow */
- return ERROR_FAIL;
- }
+ int retval = ERROR_OK;
- if (!msp432_bank->probed[bank->bank_number])
- retval = msp432_probe(bank);
+ if (is_main)
+ if (!msp432_bank->probed_main)
+ retval = msp432_probe(bank);
+ if (is_info)
+ if (!msp432_bank->probed_info)
+ retval = msp432_probe(bank);
return retval;
}
@@ -1036,12 +1033,21 @@ static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
+static int msp432_protect_check(struct flash_bank *bank)
+{
+ /* Added to suppress warning, not needed for MSP432 flash */
+ return ERROR_OK;
+}
+
static void msp432_flash_free_driver_priv(struct flash_bank *bank)
{
+ bool is_main = FLASH_BASE == bank->base;
+
/* A single private struct is shared between main and info banks */
- /* Only free it on the call for main bank (#0) */
- if ((0 == bank->bank_number) && (NULL != bank->driver_priv))
+ /* Only free it on the call for main bank */
+ if (is_main && (NULL != bank->driver_priv))
free(bank->driver_priv);
+
/* Forget about the private struct on both main and info banks */
bank->driver_priv = NULL;
}
@@ -1052,14 +1058,14 @@ static const struct command_registration msp432_exec_command_handlers[] = {
.handler = msp432_mass_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase entire flash memory on device.",
- .usage = "['main' | 'all']",
+ .usage = "bank_id ['main' | 'all']",
},
{
.name = "bsl",
.handler = msp432_bsl_command,
.mode = COMMAND_EXEC,
.help = "Allow BSL to be erased or written by flash commands.",
- .usage = "['unlock' | 'lock']",
+ .usage = "bank_id ['unlock' | 'lock']",
},
COMMAND_REGISTRATION_DONE
};
@@ -1085,6 +1091,7 @@ const struct flash_driver msp432_flash = {
.probe = msp432_probe,
.auto_probe = msp432_auto_probe,
.erase_check = default_flash_blank_check,
+ .protect_check = msp432_protect_check,
.info = msp432_info,
.free_driver_priv = msp432_flash_free_driver_priv,
};
diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h
index ffefa8f..663393b 100644
--- a/src/flash/nor/msp432.h
+++ b/src/flash/nor/msp432.h
@@ -34,14 +34,17 @@
#define MSP432E411Y 7 /* MSP432E401Y device */
#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */
+/* Common MSP432 flash parameters */
+#define FLASH_BASE 0x00000000
+
/* MSP432P4 flash parameters */
-#define P4_FLASH_MAIN_BASE 0x00000000
+#define P4_FLASH_MAIN_BASE FLASH_BASE
#define P4_FLASH_INFO_BASE 0x00200000
#define P4_SECTOR_LENGTH 0x1000
#define P4_ALGO_ENTRY_ADDR 0x01000110
/* MSP432E4 flash paramters */
-#define E4_FLASH_BASE 0x00000000
+#define E4_FLASH_BASE FLASH_BASE
#define E4_FLASH_SIZE 0x100000
#define E4_SECTOR_LENGTH 0x4000
#define E4_ALGO_ENTRY_ADDR 0x20000110
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 4041bfb..9a68b5f 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -28,6 +28,10 @@
#include <helper/types.h>
#include <helper/time_support.h>
+/* Both those values are constant across the current spectrum ofr nRF5 devices */
+#define WATCHDOG_REFRESH_REGISTER 0x40010600
+#define WATCHDOG_REFRESH_VALUE 0x6e524635
+
enum {
NRF5_FLASH_BASE = 0x00000000,
};
@@ -39,13 +43,15 @@ enum nrf5_ficr_registers {
NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010),
NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014),
- NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028),
- NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C),
- NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034),
- NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038),
- NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
- NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
- NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
+
+ NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028),
+ NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C),
+ NRF51_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034),
+ NRF51_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038),
+ NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
+ NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
+ NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
+
NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C),
NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060),
NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064),
@@ -60,36 +66,42 @@ enum nrf5_ficr_registers {
NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0),
NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4),
NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8),
- NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC),
- NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0),
- NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4),
- NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8),
- NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC),
- NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0),
- NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC),
- NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0),
- NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4),
- NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8),
- NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC),
+
+ NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC),
+ NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0),
+ NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4),
+ NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8),
+ NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC),
+ NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0),
+ NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC),
+ NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0),
+ NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4),
+ NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8),
+ NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC),
+
+ /* Following registers are available on nRF52 and on nRF51 since rev 3 */
+ NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100),
+ NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104),
+ NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108),
+ NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C),
+ NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110),
};
enum nrf5_uicr_registers {
NRF5_UICR_BASE = 0x10001000, /* User Information
* Configuration Regsters */
- NRF5_UICR_SIZE = 0x100,
-
#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
- NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000),
- NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004),
- NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008),
- NRF5_UICR_FWID = NRF5_UICR_REG(0x010),
+ NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000),
+ NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004),
+ NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008),
+ NRF51_UICR_FWID = NRF5_UICR_REG(0x010),
};
enum nrf5_nvmc_registers {
NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory
- * Controller Regsters */
+ * Controller Registers */
#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset)
@@ -98,6 +110,8 @@ enum nrf5_nvmc_registers {
NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508),
NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C),
NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514),
+
+ NRF5_BPROT_BASE = 0x40000000,
};
enum nrf5_nvmc_config_bits {
@@ -107,17 +121,19 @@ enum nrf5_nvmc_config_bits {
};
-struct nrf5_info {
- uint32_t code_page_size;
- uint32_t refcount;
+struct nrf52_ficr_info {
+ uint32_t part;
+ uint32_t variant;
+ uint32_t package;
+ uint32_t ram;
+ uint32_t flash;
+};
- struct {
- bool probed;
- int (*write) (struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count);
- } bank[2];
- struct target *target;
+enum nrf5_features {
+ NRF5_FEATURE_SERIES_51 = 1 << 0,
+ NRF5_FEATURE_SERIES_52 = 1 << 1,
+ NRF5_FEATURE_BPROT = 1 << 2,
+ NRF5_FEATURE_ACL_PROT = 1 << 3,
};
struct nrf5_device_spec {
@@ -126,22 +142,58 @@ struct nrf5_device_spec {
const char *variant;
const char *build_code;
unsigned int flash_size_kb;
+ enum nrf5_features features;
};
-#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \
+struct nrf5_info {
+ uint32_t refcount;
+
+ struct nrf5_bank {
+ struct nrf5_info *chip;
+ bool probed;
+ } bank[2];
+ struct target *target;
+
+ /* chip identification stored in nrf5_probe() for use in nrf5_info() */
+ bool ficr_info_valid;
+ struct nrf52_ficr_info ficr_info;
+ const struct nrf5_device_spec *spec;
+ uint32_t hwid;
+ enum nrf5_features features;
+ unsigned int flash_size_kb;
+ unsigned int ram_size_kb;
+};
+
+#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \
{ \
.hwid = (id), \
.part = pt, \
.variant = var, \
.build_code = bcode, \
.flash_size_kb = (fsize), \
+.features = NRF5_FEATURE_SERIES_51, \
}
-/* The known devices table below is derived from the "nRF51 Series
- * Compatibility Matrix" document, which can be found by searching for
- * ATTN-51 on the Nordic Semi website:
+#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \
+{ \
+.hwid = (id), \
+.part = pt, \
+.variant = var, \
+.build_code = bcode, \
+.flash_size_kb = (fsize), \
+.features = features, \
+}
+
+/* The known devices table below is derived from the "nRF5x series
+ * compatibility matrix" documents, which can be found in the "DocLib" of
+ * nordic:
*
- * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview
*
* Up to date with Matrix v2.0, plus some additional HWIDs.
*
@@ -151,79 +203,99 @@ struct nrf5_device_spec {
*/
static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF51822 Devices (IC rev 1). */
- NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256),
- NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128),
- NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128),
- NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
- NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
+ NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256),
+ NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128),
+ NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128),
+ NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
+ NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
/* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
with built-in jlink seem to use engineering samples not listed
in the nRF51 Series Compatibility Matrix V1.0. */
- NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
+ NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
/* nRF51822 Devices (IC rev 2). */
- NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
- NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
- NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256),
- NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256),
- NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256),
- NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128),
- NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256),
- NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256),
- NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256),
+ NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
+ NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
+ NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256),
+ NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256),
+ NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256),
+ NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128),
+ NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256),
+ NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256),
+ NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256),
/* nRF51822 Devices (IC rev 3). */
- NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
- NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
- NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
- NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
- NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
- NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
- NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
- NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
- NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
+ NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
+ NRF51_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
+ NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
+ NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
+ NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
+ NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
+ NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
/* nRF51422 Devices (IC rev 1). */
- NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
- NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256),
- NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256),
+ NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
+ NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256),
+ NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256),
/* nRF51422 Devices (IC rev 2). */
- NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256),
- NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256),
- NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128),
- NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256),
+ NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256),
+ NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256),
+ NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128),
+ NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256),
/* nRF51422 Devices (IC rev 3). */
- NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256),
- NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128),
- NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256),
- NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256),
- NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128),
- NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
- NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
-
+ NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256),
+ NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128),
+ NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256),
+ NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128),
+ NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
+ NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
+
+ /* The driver fully autodects nRF52 series devices by FICR INFO,
+ * no need for nRF52xxx HWIDs in this table */
+#if 0
/* nRF52810 Devices */
- NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192),
- NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192),
+ NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
+ NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
/* nRF52832 Devices */
- NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
- NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
- NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
+ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
+ NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
+ NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
/* nRF52840 Devices */
- NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
+ NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT),
+#endif
+};
+
+struct nrf5_device_package {
+ uint32_t package;
+ const char *code;
};
+/* Newer devices have FICR INFO.PACKAGE.
+ * This table converts its value to two character code */
+static const struct nrf5_device_package nrf5_packages_table[] = {
+ { 0x2000, "QF" },
+ { 0x2001, "CH" },
+ { 0x2002, "CI" },
+ { 0x2005, "CK" },
+};
+
+const struct flash_driver nrf5_flash, nrf51_flash;
+
static int nrf5_bank_is_probed(struct flash_bank *bank)
{
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
- assert(chip != NULL);
+ assert(nbank != NULL);
- return chip->bank[bank->bank_number].probed;
+ return nbank->probed;
}
static int nrf5_probe(struct flash_bank *bank);
@@ -234,7 +306,8 @@ static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_i
return ERROR_TARGET_NOT_HALTED;
}
- *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ *chip = nbank->chip;
int probed = nrf5_bank_is_probed(bank);
if (probed < 0)
@@ -367,6 +440,33 @@ error:
return ERROR_FAIL;
}
+static int nrf5_protect_check_bprot(struct flash_bank *bank)
+{
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+
+ assert(chip != NULL);
+
+ static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 };
+ uint32_t bprot_reg = 0;
+ int res;
+
+ for (int i = 0; i < bank->num_sectors; i++) {
+ unsigned int bit = i % 32;
+ if (bit == 0) {
+ unsigned int n_reg = i / 32;
+ if (n_reg >= ARRAY_SIZE(nrf5_bprot_offsets))
+ break;
+
+ res = target_read_u32(chip->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg);
+ if (res != ERROR_OK)
+ return res;
+ }
+ bank->sectors[i].is_protected = (bprot_reg & (1 << bit)) ? 1 : 0;
+ }
+ return ERROR_OK;
+}
+
static int nrf5_protect_check(struct flash_bank *bank)
{
int res;
@@ -376,11 +476,20 @@ static int nrf5_protect_check(struct flash_bank *bank)
if (bank->base == NRF5_UICR_BASE)
return ERROR_OK;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
assert(chip != NULL);
- res = target_read_u32(chip->target, NRF5_FICR_CLENR0,
+ if (chip->features & NRF5_FEATURE_BPROT)
+ return nrf5_protect_check_bprot(bank);
+
+ if (!(chip->features & NRF5_FEATURE_SERIES_51)) {
+ LOG_WARNING("Flash protection of this nRF device is not supported");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
+ res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[FICR]");
@@ -388,7 +497,7 @@ static int nrf5_protect_check(struct flash_bank *bank)
}
if (clenr0 == 0xFFFFFFFF) {
- res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
+ res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
@@ -417,12 +526,17 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
if (res != ERROR_OK)
return res;
+ if (!(chip->features & NRF5_FEATURE_SERIES_51)) {
+ LOG_ERROR("Flash protection setting of this nRF device is not supported");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
if (first != 0) {
LOG_ERROR("Code region 0 must start at the begining of the bank");
return ERROR_FAIL;
}
- res = target_read_u32(chip->target, NRF5_FICR_PPFC,
+ res = target_read_u32(chip->target, NRF51_FICR_PPFC,
&ppfc);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read PPFC register");
@@ -434,7 +548,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_FAIL;
}
- res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
+ res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
@@ -442,7 +556,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
}
if (clenr0 == 0xFFFFFFFF) {
- res = target_write_u32(chip->target, NRF5_UICR_CLENR0,
+ res = target_write_u32(chip->target, NRF51_UICR_CLENR0,
clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't write code region 0 size[UICR]");
@@ -458,93 +572,265 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_OK;
}
+static bool nrf5_info_variant_to_str(uint32_t variant, char *bf)
+{
+ uint8_t b[4];
+
+ h_u32_to_be(b, variant);
+ if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) {
+ memcpy(bf, b, 4);
+ bf[4] = 0;
+ return true;
+ }
+
+ strcpy(bf, "xxxx");
+ return false;
+}
+
+static const char *nrf5_decode_info_package(uint32_t package)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) {
+ if (nrf5_packages_table[i].package == package)
+ return nrf5_packages_table[i].code;
+ }
+ return "xx";
+}
+
+static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+ int res;
+
+ if (chip->spec) {
+ res = snprintf(buf, buf_size,
+ "nRF%s-%s(build code: %s)",
+ chip->spec->part, chip->spec->variant, chip->spec->build_code);
+
+ } else if (chip->ficr_info_valid) {
+ char variant[5];
+ nrf5_info_variant_to_str(chip->ficr_info.variant, variant);
+ res = snprintf(buf, buf_size,
+ "nRF%" PRIx32 "-%s%.2s(build code: %s)",
+ chip->ficr_info.part,
+ nrf5_decode_info_package(chip->ficr_info.package),
+ variant, &variant[2]);
+
+ } else {
+ res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")",
+ chip->hwid);
+ }
+ if (res <= 0)
+ return ERROR_FAIL;
+
+ snprintf(buf + res, buf_size - res, " %ukB Flash, %ukB RAM",
+ chip->flash_size_kb, chip->ram_size_kb);
+ return ERROR_OK;
+}
+
+static int nrf5_read_ficr_info(struct nrf5_info *chip)
+{
+ int res;
+ struct target *target = chip->target;
+
+ chip->ficr_info_valid = false;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part);
+ if (res != ERROR_OK) {
+ LOG_DEBUG("Couldn't read FICR INFO.PART register");
+ return res;
+ }
+
+ uint32_t series = chip->ficr_info.part & 0xfffff000;
+ switch (series) {
+ case 0x51000:
+ chip->features = NRF5_FEATURE_SERIES_51;
+ break;
+
+ case 0x52000:
+ chip->features = NRF5_FEATURE_SERIES_52;
+
+ switch (chip->ficr_info.part) {
+ case 0x52810:
+ case 0x52832:
+ chip->features |= NRF5_FEATURE_BPROT;
+ break;
+
+ case 0x52840:
+ chip->features |= NRF5_FEATURE_ACL_PROT;
+ break;
+ }
+ break;
+
+ default:
+ LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08"
+ PRIx32, chip->ficr_info.part);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ /* Now we know the device has FICR INFO filled by something relevant:
+ * Although it is not documented, the tested nRF51 rev 3 devices
+ * have FICR INFO.PART, RAM and FLASH of the same format as nRF52.
+ * VARIANT and PACKAGE coding is unknown for a nRF51 device.
+ * nRF52 devices have FICR INFO documented and always filled. */
+
+ res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant);
+ if (res != ERROR_OK)
+ return res;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package);
+ if (res != ERROR_OK)
+ return res;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram);
+ if (res != ERROR_OK)
+ return res;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash);
+ if (res != ERROR_OK)
+ return res;
+
+ chip->ficr_info_valid = true;
+ return ERROR_OK;
+}
+
+static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size)
+{
+ int res;
+
+ *ram_size = 0;
+
+ uint32_t numramblock;
+ res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock);
+ if (res != ERROR_OK) {
+ LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register");
+ return res;
+ }
+
+ if (numramblock < 1 || numramblock > 4) {
+ LOG_DEBUG("FICR NUMRAMBLOCK strange value %" PRIx32, numramblock);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ for (unsigned int i = 0; i < numramblock; i++) {
+ uint32_t sizeramblock;
+ res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock);
+ if (res != ERROR_OK) {
+ LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register");
+ return res;
+ }
+ if (sizeramblock < 1024 || sizeramblock > 65536)
+ LOG_DEBUG("FICR SIZERAMBLOCK strange value %" PRIx32, sizeramblock);
+ else
+ *ram_size += sizeramblock;
+ }
+ return res;
+}
+
static int nrf5_probe(struct flash_bank *bank)
{
- uint32_t hwid;
int res;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+ struct target *target = chip->target;
- res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid);
+ res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read CONFIGID register");
return res;
}
- hwid &= 0xFFFF; /* HWID is stored in the lower two
+ chip->hwid &= 0xFFFF; /* HWID is stored in the lower two
* bytes of the CONFIGID register */
- const struct nrf5_device_spec *spec = NULL;
+ /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
+ chip->features = NRF5_FEATURE_SERIES_51;
+
+ /* Don't bail out on error for the case that some old engineering
+ * sample has FICR INFO registers unreadable. We can proceed anyway. */
+ (void)nrf5_read_ficr_info(chip);
+
+ chip->spec = NULL;
for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) {
- if (hwid == nrf5_known_devices_table[i].hwid) {
- spec = &nrf5_known_devices_table[i];
+ if (chip->hwid == nrf5_known_devices_table[i].hwid) {
+ chip->spec = &nrf5_known_devices_table[i];
+ chip->features = chip->spec->features;
break;
}
}
+ if (chip->spec && chip->ficr_info_valid) {
+ /* check if HWID table gives the same part as FICR INFO */
+ if (chip->ficr_info.part != strtoul(chip->spec->part, NULL, 16))
+ LOG_WARNING("HWID 0x%04" PRIx32 " mismatch: FICR INFO.PART %"
+ PRIx32, chip->hwid, chip->ficr_info.part);
+ }
+
+ if (chip->ficr_info_valid) {
+ chip->ram_size_kb = chip->ficr_info.ram;
+ } else {
+ uint32_t ram_size;
+ nrf5_get_ram_size(target, &ram_size);
+ chip->ram_size_kb = ram_size / 1024;
+ }
+
+ /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
+ uint32_t flash_page_size;
+ res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
+ &flash_page_size);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read code page size");
+ return res;
+ }
+
+ /* Note the register name is misleading,
+ * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
+ uint32_t num_sectors;
+ res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read code memory size");
+ return res;
+ }
+
+ chip->flash_size_kb = num_sectors * flash_page_size / 1024;
+
if (!chip->bank[0].probed && !chip->bank[1].probed) {
- if (spec)
- LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash",
- spec->part, spec->variant, spec->build_code,
- spec->flash_size_kb);
+ char buf[80];
+ nrf5_info(bank, buf, sizeof(buf));
+ if (!chip->spec && !chip->ficr_info_valid)
+ LOG_INFO("Unknown device: %s", buf);
else
- LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid);
+ LOG_INFO("%s", buf);
}
- if (bank->base == NRF5_FLASH_BASE) {
- /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
- res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
- &chip->code_page_size);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read code page size");
- return res;
- }
+ free(bank->sectors);
- /* Note the register name is misleading,
- * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
- uint32_t num_sectors;
- res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read code memory size");
- return res;
- }
+ if (bank->base == NRF5_FLASH_BASE) {
+ /* Sanity check */
+ if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb)
+ LOG_WARNING("Chip's reported Flash capacity does not match expected one");
+ if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash)
+ LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH");
bank->num_sectors = num_sectors;
- bank->size = num_sectors * chip->code_page_size;
-
- if (spec && bank->size / 1024 != spec->flash_size_kb)
- LOG_WARNING("Chip's reported Flash capacity does not match expected one");
+ bank->size = num_sectors * flash_page_size;
- bank->sectors = calloc(bank->num_sectors,
- sizeof((bank->sectors)[0]));
+ bank->sectors = alloc_block_array(0, flash_page_size, num_sectors);
if (!bank->sectors)
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- /* Fill out the sector information: all NRF5 sectors are the same size and
- * there is always a fixed number of them. */
- for (int i = 0; i < bank->num_sectors; i++) {
- bank->sectors[i].size = chip->code_page_size;
- bank->sectors[i].offset = i * chip->code_page_size;
-
- /* mark as unknown */
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = -1;
- }
+ return ERROR_FAIL;
nrf5_protect_check(bank);
chip->bank[0].probed = true;
+
} else {
- bank->size = NRF5_UICR_SIZE;
bank->num_sectors = 1;
- bank->sectors = calloc(bank->num_sectors,
- sizeof((bank->sectors)[0]));
- if (!bank->sectors)
- return ERROR_FLASH_BANK_NOT_PROBED;
+ bank->size = flash_page_size;
- bank->sectors[0].size = bank->size;
- bank->sectors[0].offset = 0;
+ bank->sectors = alloc_block_array(0, flash_page_size, num_sectors);
+ if (!bank->sectors)
+ return ERROR_FAIL;
- bank->sectors[0].is_erased = 0;
bank->sectors[0].is_protected = 0;
chip->bank[1].probed = true;
@@ -580,29 +866,27 @@ static int nrf5_erase_page(struct flash_bank *bank,
int res;
LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
- if (sector->is_protected) {
- LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
- return ERROR_FAIL;
- }
if (bank->base == NRF5_UICR_BASE) {
- uint32_t ppfc;
- res = target_read_u32(chip->target, NRF5_FICR_PPFC,
+ if (chip->features & NRF5_FEATURE_SERIES_51) {
+ uint32_t ppfc;
+ res = target_read_u32(chip->target, NRF51_FICR_PPFC,
&ppfc);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read PPFC register");
- return res;
- }
-
- if ((ppfc & 0xFF) == 0xFF) {
- /* We can't erase the UICR. Double-check to
- see if it's already erased before complaining. */
- default_flash_blank_check(bank);
- if (sector->is_erased == 1)
- return ERROR_OK;
-
- LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
- return ERROR_FAIL;
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read PPFC register");
+ return res;
+ }
+
+ if ((ppfc & 0xFF) == 0xFF) {
+ /* We can't erase the UICR. Double-check to
+ see if it's already erased before complaining. */
+ default_flash_blank_check(bank);
+ if (sector->is_erased == 1)
+ return ERROR_OK;
+
+ LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
+ return ERROR_FAIL;
+ }
}
res = nrf5_nvmc_generic_erase(chip,
@@ -619,44 +903,22 @@ static int nrf5_erase_page(struct flash_bank *bank,
return res;
}
-static const uint8_t nrf5_flash_write_code[] = {
- /* See contrib/loaders/flash/cortex-m0.S */
-/* <wait_fifo>: */
- 0x0d, 0x68, /* ldr r5, [r1, #0] */
- 0x00, 0x2d, /* cmp r5, #0 */
- 0x0b, 0xd0, /* beq.n 1e <exit> */
- 0x4c, 0x68, /* ldr r4, [r1, #4] */
- 0xac, 0x42, /* cmp r4, r5 */
- 0xf9, 0xd0, /* beq.n 0 <wait_fifo> */
- 0x20, 0xcc, /* ldmia r4!, {r5} */
- 0x20, 0xc3, /* stmia r3!, {r5} */
- 0x94, 0x42, /* cmp r4, r2 */
- 0x01, 0xd3, /* bcc.n 18 <no_wrap> */
- 0x0c, 0x46, /* mov r4, r1 */
- 0x08, 0x34, /* adds r4, #8 */
-/* <no_wrap>: */
- 0x4c, 0x60, /* str r4, [r1, #4] */
- 0x04, 0x38, /* subs r0, #4 */
- 0xf0, 0xd1, /* bne.n 0 <wait_fifo> */
-/* <exit>: */
- 0x00, 0xbe /* bkpt 0x0000 */
-};
-
-
/* Start a low level flash write for the specified region */
-static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
+static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes)
{
struct target *target = chip->target;
uint32_t buffer_size = 8192;
struct working_area *write_algorithm;
struct working_area *source;
- uint32_t address = NRF5_FLASH_BASE + offset;
- struct reg_param reg_params[4];
+ struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
+ static const uint8_t nrf5_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/nrf5/nrf5.inc"
+ };
- LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
+ LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes);
assert(bytes % 4 == 0);
/* allocate working area with flash programming code */
@@ -665,7 +927,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
LOG_WARNING("no working area available, falling back to slow memory writes");
for (; bytes > 0; bytes -= 4) {
- retval = target_write_memory(chip->target, offset, 4, 1, buffer);
+ retval = target_write_memory(target, address, 4, 1, buffer);
if (retval != ERROR_OK)
return retval;
@@ -673,17 +935,13 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
if (retval != ERROR_OK)
return retval;
- offset += 4;
+ address += 4;
buffer += 4;
}
return ERROR_OK;
}
- LOG_WARNING("using fast async flash loader. This is currently supported");
- LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
- LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it");
-
retval = target_write_buffer(target, write_algorithm->address,
sizeof(nrf5_flash_write_code),
nrf5_flash_write_code);
@@ -710,15 +968,19 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer start */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* buffer end */
init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT); /* target address */
+ init_reg_param(&reg_params[4], "r6", 32, PARAM_OUT); /* watchdog refresh value */
+ init_reg_param(&reg_params[5], "r7", 32, PARAM_OUT); /* watchdog refresh register address */
buf_set_u32(reg_params[0].value, 0, 32, bytes);
buf_set_u32(reg_params[1].value, 0, 32, source->address);
buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[3].value, 0, 32, address);
+ buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE);
+ buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER);
retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
0, NULL,
- 4, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
@@ -730,26 +992,29 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
+ destroy_reg_param(&reg_params[4]);
+ destroy_reg_param(&reg_params[5]);
return retval;
}
-/* Check and erase flash sectors in specified range then start a low level page write.
- start/end must be sector aligned.
-*/
-static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
+static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
{
- int res = ERROR_FAIL;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_info *chip;
- assert(start % chip->code_page_size == 0);
- assert(end % chip->code_page_size == 0);
+ int res = nrf5_get_probed_chip_if_halted(bank, &chip);
+ if (res != ERROR_OK)
+ return res;
+
+ assert(offset % 4 == 0);
+ assert(count % 4 == 0);
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
- res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
+ res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count);
if (res != ERROR_OK)
goto error;
@@ -777,139 +1042,57 @@ static int nrf5_erase(struct flash_bank *bank, int first, int last)
return res;
}
-static int nrf5_code_flash_write(struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-
- int res;
- /* Need to perform reads to fill any gaps we need to preserve in the first page,
- before the start of buffer, or in the last page, after the end of buffer */
- uint32_t first_page = offset/chip->code_page_size;
- uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
-
- uint32_t first_page_offset = first_page * chip->code_page_size;
- uint32_t last_page_offset = last_page * chip->code_page_size;
-
- LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
- offset, offset+count, first_page_offset, last_page_offset);
-
- uint32_t page_cnt = last_page - first_page;
- uint8_t buffer_to_flash[page_cnt*chip->code_page_size];
-
- /* Fill in any space between start of first page and start of buffer */
- uint32_t pre = offset - first_page_offset;
- if (pre > 0) {
- res = target_read_memory(bank->target,
- first_page_offset,
- 1,
- pre,
- buffer_to_flash);
- if (res != ERROR_OK)
- return res;
- }
-
- /* Fill in main contents of buffer */
- memcpy(buffer_to_flash+pre, buffer, count);
-
- /* Fill in any space between end of buffer and end of last page */
- uint32_t post = last_page_offset - (offset+count);
- if (post > 0) {
- /* Retrieve the full row contents from Flash */
- res = target_read_memory(bank->target,
- offset + count,
- 1,
- post,
- buffer_to_flash+pre+count);
- if (res != ERROR_OK)
- return res;
- }
-
- return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
-}
-
-static int nrf5_uicr_flash_write(struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count)
+static void nrf5_free_driver_priv(struct flash_bank *bank)
{
- int res;
- uint8_t uicr[NRF5_UICR_SIZE];
- struct flash_sector *sector = &bank->sectors[0];
-
- if ((offset + count) > NRF5_UICR_SIZE)
- return ERROR_FAIL;
-
- res = target_read_memory(bank->target,
- NRF5_UICR_BASE,
- 1,
- NRF5_UICR_SIZE,
- uicr);
-
- if (res != ERROR_OK)
- return res;
-
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK)
- return res;
-
- res = nrf5_nvmc_write_enable(chip);
- if (res != ERROR_OK)
- return res;
-
- memcpy(&uicr[offset], buffer, count);
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+ if (chip == NULL)
+ return;
- res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE);
- if (res != ERROR_OK) {
- nrf5_nvmc_read_only(chip);
- return res;
+ chip->refcount--;
+ if (chip->refcount == 0) {
+ free(chip);
+ bank->driver_priv = NULL;
}
-
- return nrf5_nvmc_read_only(chip);
}
-
-static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+static struct nrf5_info *nrf5_get_chip(struct target *target)
{
- int res;
- struct nrf5_info *chip;
+ struct flash_bank *bank_iter;
- res = nrf5_get_probed_chip_if_halted(bank, &chip);
- if (res != ERROR_OK)
- return res;
+ /* iterate over nrf5 banks of same target */
+ for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) {
+ if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash)
+ continue;
- return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
-}
+ if (bank_iter->target != target)
+ continue;
-static void nrf5_free_driver_priv(struct flash_bank *bank)
-{
- struct nrf5_info *chip = bank->driver_priv;
- if (chip == NULL)
- return;
+ struct nrf5_bank *nbank = bank_iter->driver_priv;
+ if (!nbank)
+ continue;
- chip->refcount--;
- if (chip->refcount == 0) {
- free(chip);
- bank->driver_priv = NULL;
+ if (nbank->chip)
+ return nbank->chip;
}
+ return NULL;
}
FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
{
- static struct nrf5_info *chip;
+ struct nrf5_info *chip;
+ struct nrf5_bank *nbank = NULL;
switch (bank->base) {
case NRF5_FLASH_BASE:
- bank->bank_number = 0;
- break;
case NRF5_UICR_BASE:
- bank->bank_number = 1;
break;
default:
LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
return ERROR_FAIL;
}
+ chip = nrf5_get_chip(bank->target);
if (!chip) {
/* Create a new chip */
chip = calloc(1, sizeof(*chip));
@@ -921,16 +1104,19 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
switch (bank->base) {
case NRF5_FLASH_BASE:
- chip->bank[bank->bank_number].write = nrf5_code_flash_write;
+ nbank = &chip->bank[0];
break;
case NRF5_UICR_BASE:
- chip->bank[bank->bank_number].write = nrf5_uicr_flash_write;
+ nbank = &chip->bank[1];
break;
}
+ assert(nbank != NULL);
chip->refcount++;
- chip->bank[bank->bank_number].probed = false;
- bank->driver_priv = chip;
+ nbank->chip = chip;
+ nbank->probed = false;
+ bank->driver_priv = nbank;
+ bank->write_start_alignment = bank->write_end_alignment = 4;
return ERROR_OK;
}
@@ -953,19 +1139,20 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
if (res != ERROR_OK)
return res;
- uint32_t ppfc;
-
- res = target_read_u32(target, NRF5_FICR_PPFC,
+ if (chip->features & NRF5_FEATURE_SERIES_51) {
+ uint32_t ppfc;
+ res = target_read_u32(target, NRF51_FICR_PPFC,
&ppfc);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read PPFC register");
- return res;
- }
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read PPFC register");
+ return res;
+ }
- if ((ppfc & 0xFF) == 0x00) {
- LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
- "mass erase command won't work.");
- return ERROR_FAIL;
+ if ((ppfc & 0xFF) == 0x00) {
+ LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
+ "mass erase command won't work.");
+ return ERROR_FAIL;
+ }
}
res = nrf5_erase_all(chip);
@@ -988,9 +1175,17 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
return ERROR_OK;
}
-static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
+COMMAND_HANDLER(nrf5_handle_info_command)
{
int res;
+ struct flash_bank *bank = NULL;
+ struct target *target = get_current_target(CMD_CTX);
+
+ res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank);
+ if (res != ERROR_OK)
+ return res;
+
+ assert(bank != NULL);
struct nrf5_info *chip;
@@ -1004,13 +1199,13 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
} ficr[] = {
{ .address = NRF5_FICR_CODEPAGESIZE },
{ .address = NRF5_FICR_CODESIZE },
- { .address = NRF5_FICR_CLENR0 },
- { .address = NRF5_FICR_PPFC },
- { .address = NRF5_FICR_NUMRAMBLOCK },
- { .address = NRF5_FICR_SIZERAMBLOCK0 },
- { .address = NRF5_FICR_SIZERAMBLOCK1 },
- { .address = NRF5_FICR_SIZERAMBLOCK2 },
- { .address = NRF5_FICR_SIZERAMBLOCK3 },
+ { .address = NRF51_FICR_CLENR0 },
+ { .address = NRF51_FICR_PPFC },
+ { .address = NRF51_FICR_NUMRAMBLOCK },
+ { .address = NRF51_FICR_SIZERAMBLOCK0 },
+ { .address = NRF51_FICR_SIZERAMBLOCK1 },
+ { .address = NRF51_FICR_SIZERAMBLOCK2 },
+ { .address = NRF51_FICR_SIZERAMBLOCK3 },
{ .address = NRF5_FICR_CONFIGID },
{ .address = NRF5_FICR_DEVICEID0 },
{ .address = NRF5_FICR_DEVICEID1 },
@@ -1025,22 +1220,22 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
{ .address = NRF5_FICR_DEVICEADDRTYPE },
{ .address = NRF5_FICR_DEVICEADDR0 },
{ .address = NRF5_FICR_DEVICEADDR1 },
- { .address = NRF5_FICR_OVERRIDEN },
- { .address = NRF5_FICR_NRF_1MBIT0 },
- { .address = NRF5_FICR_NRF_1MBIT1 },
- { .address = NRF5_FICR_NRF_1MBIT2 },
- { .address = NRF5_FICR_NRF_1MBIT3 },
- { .address = NRF5_FICR_NRF_1MBIT4 },
- { .address = NRF5_FICR_BLE_1MBIT0 },
- { .address = NRF5_FICR_BLE_1MBIT1 },
- { .address = NRF5_FICR_BLE_1MBIT2 },
- { .address = NRF5_FICR_BLE_1MBIT3 },
- { .address = NRF5_FICR_BLE_1MBIT4 },
+ { .address = NRF51_FICR_OVERRIDEN },
+ { .address = NRF51_FICR_NRF_1MBIT0 },
+ { .address = NRF51_FICR_NRF_1MBIT1 },
+ { .address = NRF51_FICR_NRF_1MBIT2 },
+ { .address = NRF51_FICR_NRF_1MBIT3 },
+ { .address = NRF51_FICR_NRF_1MBIT4 },
+ { .address = NRF51_FICR_BLE_1MBIT0 },
+ { .address = NRF51_FICR_BLE_1MBIT1 },
+ { .address = NRF51_FICR_BLE_1MBIT2 },
+ { .address = NRF51_FICR_BLE_1MBIT3 },
+ { .address = NRF51_FICR_BLE_1MBIT4 },
}, uicr[] = {
- { .address = NRF5_UICR_CLENR0, },
- { .address = NRF5_UICR_RBPCONF },
- { .address = NRF5_UICR_XTALFREQ },
- { .address = NRF5_UICR_FWID },
+ { .address = NRF51_UICR_CLENR0, },
+ { .address = NRF51_UICR_RBPCONF },
+ { .address = NRF51_UICR_XTALFREQ },
+ { .address = NRF51_UICR_FWID },
};
for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) {
@@ -1061,7 +1256,7 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
}
}
- snprintf(buf, buf_size,
+ command_print(CMD,
"\n[factory information control block]\n\n"
"code page size: %"PRIu32"B\n"
"code memory size: %"PRIu32"kB\n"
@@ -1120,6 +1315,13 @@ static const struct command_registration nrf5_exec_command_handlers[] = {
.help = "Erase all flash contents of the chip.",
.usage = "",
},
+ {
+ .name = "info",
+ .handler = nrf5_handle_info_command,
+ .mode = COMMAND_EXEC,
+ .help = "Show FICR and UICR info.",
+ .usage = "",
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c
index c62af04..a485282 100644
--- a/src/flash/nor/numicro.c
+++ b/src/flash/nor/numicro.c
@@ -1216,7 +1216,7 @@ static int numicro_init_isp(struct target *target)
return ERROR_OK;
}
-static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t* rdata)
+static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata)
{
uint32_t timeout, status;
int retval = ERROR_OK;
@@ -1548,7 +1548,6 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
{
struct target *target = bank->target;
uint32_t timeout, status;
- uint8_t *new_buffer = NULL;
int retval = ERROR_OK;
if (target->state != TARGET_HALTED) {
@@ -1566,20 +1565,8 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
return retval;
- if (count & 0x3) {
- uint32_t old_count = count;
- count = (old_count | 3) + 1;
- new_buffer = malloc(count);
- if (new_buffer == NULL) {
- LOG_ERROR("odd number of bytes to write and no memory "
- "for padding buffer");
- return ERROR_FAIL;
- }
- LOG_INFO("odd number of bytes to write (%d), extending to %d "
- "and padding with 0xff", old_count, count);
- memset(new_buffer, 0xff, count);
- buffer = memcpy(new_buffer, buffer, old_count);
- }
+ assert(offset % 4 == 0);
+ assert(count % 4 == 0);
uint32_t words_remaining = count / 4;
@@ -1597,13 +1584,10 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_DEBUG("write longword @ %08X", offset + i);
- uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
- memcpy(padding, buffer + i, MIN(4, count-i));
-
retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i);
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, padding);
+ retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
@@ -1649,7 +1633,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_OK;
}
-static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type** cpu)
+static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu)
{
uint32_t part_id;
int retval = ERROR_OK;
@@ -1663,7 +1647,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_
LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id);
/* search part numbers */
- for (size_t i = 0; i < sizeof(NuMicroParts)/sizeof(NuMicroParts[0]); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) {
if (part_id == NuMicroParts[i].partid) {
*cpu = &NuMicroParts[i];
LOG_INFO("Device Name: %s", (*cpu)->partname);
@@ -1754,6 +1738,7 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command)
memset(bank_info, 0, sizeof(struct numicro_flash_bank));
bank->driver_priv = bank_info;
+ bank->write_start_alignment = bank->write_end_alignment = 4;
return ERROR_OK;
diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c
index 386075e..a8f8d3f 100644
--- a/src/flash/nor/psoc6.c
+++ b/src/flash/nor/psoc6.c
@@ -108,7 +108,7 @@ static const struct row_region safe_sflash_regions[] = {
{0x16007C00, 0x400}, /* SFLASH: TOC2 */
};
-#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0]))
+#define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
static struct working_area *g_stack_area;
static struct armv7m_algorithm g_armv7m_info;
@@ -481,20 +481,15 @@ static const char *protection_to_str(uint8_t protection)
switch (protection) {
case PROTECTION_VIRGIN:
return "VIRGIN";
- break;
case PROTECTION_NORMAL:
return "NORMAL";
- break;
case PROTECTION_SECURE:
return "SECURE";
- break;
case PROTECTION_DEAD:
return "DEAD";
- break;
case PROTECTION_UNKNOWN:
default:
return "UNKNOWN";
- break;
}
}
diff --git a/src/flash/nor/renesas_rpchf.c b/src/flash/nor/renesas_rpchf.c
new file mode 100644
index 0000000..3f03f92
--- /dev/null
+++ b/src/flash/nor/renesas_rpchf.c
@@ -0,0 +1,648 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Renesas RCar Gen3 RPC Hyperflash driver
+ * Based on U-Boot RPC Hyperflash driver
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016 Cogent Embedded, Inc.
+ * Copyright (C) 2017-2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "cfi.h"
+#include "non_cfi.h"
+#include <helper/binarybuffer.h>
+#include <helper/bits.h>
+#include <helper/time_support.h>
+
+#define RPC_CMNCR 0x0000 /* R/W */
+#define RPC_CMNCR_MD BIT(31)
+#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
+#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
+#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
+#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
+#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
+#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
+#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
+#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+ RPC_CMNCR_IO3FV(3))
+#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+
+#define RPC_SSLDR 0x0004 /* R/W */
+#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+
+#define RPC_DRCR 0x000C /* R/W */
+#define RPC_DRCR_SSLN BIT(24)
+#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+#define RPC_DRCR_RCF BIT(9)
+#define RPC_DRCR_RBE BIT(8)
+#define RPC_DRCR_SSLE BIT(0)
+
+#define RPC_DRCMR 0x0010 /* R/W */
+#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_DREAR 0x0014 /* R/W */
+#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
+#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
+
+#define RPC_DROPR 0x0018 /* R/W */
+#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
+#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
+
+#define RPC_DRENR 0x001C /* R/W */
+#define RPC_DRENR_CDB(o) (uint32_t)((((o) & 0x3) << 30))
+#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_DRENR_DME BIT(15)
+#define RPC_DRENR_CDE BIT(14)
+#define RPC_DRENR_OCDE BIT(12)
+#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
+
+#define RPC_SMCR 0x0020 /* R/W */
+#define RPC_SMCR_SSLKP BIT(8)
+#define RPC_SMCR_SPIRE BIT(2)
+#define RPC_SMCR_SPIWE BIT(1)
+#define RPC_SMCR_SPIE BIT(0)
+
+#define RPC_SMCMR 0x0024 /* R/W */
+#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_SMADR 0x0028 /* R/W */
+#define RPC_SMOPR 0x002C /* R/W */
+#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
+#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
+
+#define RPC_SMENR 0x0030 /* R/W */
+#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
+#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_SMENR_DME BIT(15)
+#define RPC_SMENR_CDE BIT(14)
+#define RPC_SMENR_OCDE BIT(12)
+#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
+#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
+
+#define RPC_SMRDR0 0x0038 /* R */
+#define RPC_SMRDR1 0x003C /* R */
+#define RPC_SMWDR0 0x0040 /* R/W */
+#define RPC_SMWDR1 0x0044 /* R/W */
+#define RPC_CMNSR 0x0048 /* R */
+#define RPC_CMNSR_SSLF BIT(1)
+#define RPC_CMNSR_TEND BIT(0)
+
+#define RPC_DRDMCR 0x0058 /* R/W */
+#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_DRDRENR 0x005C /* R/W */
+#define RPC_DRDRENR_HYPE (0x5 << 12)
+#define RPC_DRDRENR_ADDRE BIT(8)
+#define RPC_DRDRENR_OPDRE BIT(4)
+#define RPC_DRDRENR_DRDRE BIT(0)
+
+#define RPC_SMDMCR 0x0060 /* R/W */
+#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_SMDRENR 0x0064 /* R/W */
+#define RPC_SMDRENR_HYPE (0x5 << 12)
+#define RPC_SMDRENR_ADDRE BIT(8)
+#define RPC_SMDRENR_OPDRE BIT(4)
+#define RPC_SMDRENR_SPIDRE BIT(0)
+
+#define RPC_PHYCNT 0x007C /* R/W */
+#define RPC_PHYCNT_CAL BIT(31)
+#define PRC_PHYCNT_OCTA_AA BIT(22)
+#define PRC_PHYCNT_OCTA_SA BIT(23)
+#define PRC_PHYCNT_EXDS BIT(21)
+#define RPC_PHYCNT_OCT BIT(20)
+#define RPC_PHYCNT_WBUF2 BIT(4)
+#define RPC_PHYCNT_WBUF BIT(2)
+#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
+
+#define RPC_PHYINT 0x0088 /* R/W */
+#define RPC_PHYINT_RSTEN BIT(18)
+#define RPC_PHYINT_WPEN BIT(17)
+#define RPC_PHYINT_INTEN BIT(16)
+#define RPC_PHYINT_RST BIT(2)
+#define RPC_PHYINT_WP BIT(1)
+#define RPC_PHYINT_INT BIT(0)
+
+#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
+#define RPC_WBUF_SIZE 0x100
+
+static uint32_t rpc_base = 0xee200000;
+static uint32_t mem_base = 0x08000000;
+
+enum rpc_hf_size {
+ RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8),
+ RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC),
+ RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF),
+};
+
+static int rpc_hf_wait_tend(struct target *target)
+{
+ uint32_t reg = rpc_base + RPC_CMNSR;
+ uint32_t val;
+ unsigned long timeout = 1000;
+ long long endtime;
+ int ret;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ ret = target_read_u32(target, reg, &val);
+ if (ret != ERROR_OK)
+ return ERROR_FAIL;
+
+ if (val & RPC_CMNSR_TEND)
+ return ERROR_OK;
+
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static int clrsetbits_u32(struct target *target, uint32_t reg,
+ uint32_t clr, uint32_t set)
+{
+ uint32_t val;
+ int ret;
+
+ ret = target_read_u32(target, reg, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~clr;
+ val |= set;
+
+ return target_write_u32(target, reg, val);
+}
+
+static int rpc_hf_mode(struct target *target, bool manual)
+{
+ uint32_t val;
+ int ret;
+
+ ret = rpc_hf_wait_tend(target);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Mode TEND timeout");
+ return ret;
+ }
+
+ ret = clrsetbits_u32(target, rpc_base + RPC_PHYCNT,
+ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
+ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
+ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR,
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+ (manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1));
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (manual)
+ return ERROR_OK;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRCR,
+ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF |
+ RPC_DRCR_RBE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRCMR,
+ RPC_DRCMR_CMD(0xA0));
+ if (ret != ERROR_OK)
+ return ret;
+ ret = target_write_u32(target, rpc_base + RPC_DRENR,
+ RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) |
+ RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) |
+ RPC_DRENR_CDE | RPC_DRENR_OCDE |
+ RPC_DRENR_ADE(4));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRDMCR,
+ RPC_DRDMCR_DMCYC(0xE));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRDRENR,
+ RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE |
+ RPC_DRDRENR_DRDRE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Dummy read */
+ return target_read_u32(target, rpc_base + RPC_DRCR, &val);
+}
+
+static int rpc_hf_xfer(struct target *target, target_addr_t addr,
+ uint32_t wdata, uint32_t *rdata, enum rpc_hf_size size,
+ bool write, const uint8_t *wbuf, unsigned int wbuf_size)
+{
+ int ret;
+ uint32_t val;
+
+ if (wbuf_size != 0) {
+ ret = rpc_hf_wait_tend(target);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Xfer TEND timeout");
+ return ret;
+ }
+
+ /* Write calibration magic */
+ ret = target_write_u32(target, rpc_base + RPC_DRCR, 0x01FF0301);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_PHYCNT, 0x80030277);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_memory(target, rpc_base | RPC_WBUF, 4,
+ wbuf_size / 4, wbuf);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR,
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(1));
+ if (ret != ERROR_OK)
+ return ret;
+ } else {
+ ret = rpc_hf_mode(target, 1);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ /* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */
+ ret = target_write_u32(target, rpc_base + RPC_SMCMR,
+ write ? 0 : RPC_SMCMR_CMD(0x80));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMADR,
+ addr >> 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMOPR, 0x0);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMDRENR,
+ RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE |
+ RPC_SMDRENR_SPIDRE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
+ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
+ (wbuf_size ? RPC_SMENR_OPDB(2) : 0) |
+ RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size;
+
+ if (write) {
+ ret = target_write_u32(target, rpc_base + RPC_SMENR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (wbuf_size == 0) {
+ buf_bswap32((uint8_t *)&wdata, (uint8_t *)&wdata, 4);
+ ret = target_write_u32(target, rpc_base + RPC_SMWDR0,
+ wdata);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ ret = target_write_u32(target, rpc_base + RPC_SMCR,
+ RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
+ if (ret != ERROR_OK)
+ return ret;
+ } else {
+ val |= RPC_SMENR_DME;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMDMCR,
+ RPC_SMDMCR_DMCYC(0xE));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMENR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMCR,
+ RPC_SMCR_SPIRE | RPC_SMCR_SPIE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = rpc_hf_wait_tend(target);
+ if (ret != ERROR_OK)
+ return ret;
+
+ uint32_t val32;
+ ret = target_read_u32(target, rpc_base + RPC_SMRDR0, &val32);
+ if (ret != ERROR_OK)
+ return ret;
+ buf_bswap32((uint8_t *)&val32, (uint8_t *)&val32, 4);
+ *rdata = val32;
+ }
+
+ ret = rpc_hf_mode(target, 0);
+ if (ret != ERROR_OK)
+ LOG_ERROR("Xfer done TEND timeout");
+ return ret;
+}
+
+static int rpchf_target_write_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, const uint8_t *buffer)
+{
+ struct target *target = bank->target;
+ uint32_t wdata;
+
+ if (count != 2)
+ return ERROR_FAIL;
+
+ wdata = buffer[0] | (buffer[1] << 8);
+
+ return rpc_hf_xfer(target, addr, wdata, NULL, RPC_HF_SIZE_16BIT,
+ true, NULL, 0);
+}
+
+static int rpchf_target_read_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer)
+{
+ struct target *target = bank->target;
+ uint32_t i, rdata;
+ int ret;
+
+ for (i = 0; i < count; i++) {
+ ret = rpc_hf_xfer(target, addr + (2 * i), 0, &rdata,
+ RPC_HF_SIZE_16BIT, false, NULL, 0);
+ if (ret != ERROR_OK)
+ return ret;
+ buffer[(2 * i) + 0] = rdata & 0xff;
+ buffer[(2 * i) + 1] = (rdata >> 8) & 0xff;
+ }
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(rpchf_flash_bank_command)
+{
+ struct cfi_flash_bank *cfi_info;
+ int ret;
+
+ ret = cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV);
+ if (ret != ERROR_OK)
+ return ret;
+
+ cfi_info = bank->driver_priv;
+ cfi_info->read_mem = rpchf_target_read_memory;
+ cfi_info->write_mem = rpchf_target_write_memory;
+
+ return ERROR_OK;
+}
+
+static int rpchf_spansion_write_words(struct flash_bank *bank, const uint8_t *word,
+ uint32_t wordcount, uint32_t address)
+{
+ int retval;
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+ /* Calculate buffer size and boundary mask
+ * buffersize is (buffer size per chip) * (number of chips)
+ * bufferwsize is buffersize in words */
+ uint32_t buffersize = RPC_WBUF_SIZE;
+ uint32_t buffermask = buffersize - 1;
+ uint32_t bufferwsize = buffersize / 2;
+
+ /* Check for valid range */
+ if (address & buffermask) {
+ LOG_ERROR("Write address at base " TARGET_ADDR_FMT
+ ", address 0x%" PRIx32 " not aligned to 2^%d boundary",
+ bank->base, address, cfi_info->max_buf_write_size);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Check for valid size */
+ if (wordcount > bufferwsize) {
+ LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %"
+ PRId32, wordcount, buffersize);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Unlock */
+ retval = cfi_spansion_unlock_seq(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1));
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = rpc_hf_xfer(bank->target, address, 0, NULL, RPC_HF_SIZE_64BIT, true, word, wordcount * 2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) {
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT
+ ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address,
+ bufferwsize);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static int rpchf_write_words(struct flash_bank *bank, const uint8_t *word,
+ uint32_t wordcount, uint32_t address)
+{
+ return rpchf_spansion_write_words(bank, word, wordcount, address);
+}
+
+static int rpchf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ uint32_t address = bank->base + offset; /* address of first byte to be programmed */
+ uint32_t write_p;
+ int align; /* number of unaligned bytes */
+ uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being
+ *programmed */
+ int i;
+ int retval;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* start at the first byte of the first word (bus_width size) */
+ write_p = address & ~(bank->bus_width - 1);
+ align = address - write_p;
+ if (align != 0) {
+ LOG_INFO("Fixup %d unaligned head bytes", align);
+
+ /* read a complete word from flash */
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* replace only bytes that must be written */
+ for (i = align;
+ (i < bank->bus_width) && (count > 0);
+ i++, count--)
+ if (cfi_info->data_swap)
+ /* data bytes are swapped (reverse endianness) */
+ current_word[bank->bus_width - i] = *buffer++;
+ else
+ current_word[i] = *buffer++;
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ write_p += bank->bus_width;
+ }
+
+ /* Calculate buffer size and boundary mask
+ * buffersize is (buffer size per chip) * (number of chips)
+ * bufferwsize is buffersize in words */
+ uint32_t buffersize = RPC_WBUF_SIZE;
+ uint32_t buffermask = buffersize-1;
+ uint32_t bufferwsize = buffersize / bank->bus_width;
+
+ /* fall back to memory writes */
+ while (count >= (uint32_t)bank->bus_width) {
+ int fallback;
+ if ((write_p & 0xff) == 0) {
+ LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08"
+ PRIx32 " bytes remaining", write_p, count);
+ }
+ fallback = 1;
+ if ((bufferwsize > 0) && (count >= buffersize) &&
+ !(write_p & buffermask)) {
+ retval = rpchf_write_words(bank, buffer, bufferwsize, write_p);
+ if (retval == ERROR_OK) {
+ buffer += buffersize;
+ write_p += buffersize;
+ count -= buffersize;
+ fallback = 0;
+ } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED)
+ return retval;
+ }
+ /* try the slow way? */
+ if (fallback) {
+ for (i = 0; i < bank->bus_width; i++)
+ current_word[i] = *buffer++;
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+
+ write_p += bank->bus_width;
+ count -= bank->bus_width;
+ }
+ }
+
+ /* return to read array mode, so we can read from flash again for padding */
+ retval = cfi_reset(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* handle unaligned tail bytes */
+ if (count > 0) {
+ LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
+
+ /* read a complete word from flash */
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* replace only bytes that must be written */
+ for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
+ if (cfi_info->data_swap)
+ /* data bytes are swapped (reverse endianness) */
+ current_word[bank->bus_width - i] = *buffer++;
+ else
+ current_word[i] = *buffer++;
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* return to read array mode */
+ return cfi_reset(bank);
+}
+
+static int rpchf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ LOG_DEBUG("reading buffer of %" PRIi32 " byte at 0x%8.8" PRIx32,
+ count, offset);
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ return target_read_memory(target, offset | mem_base,
+ 4, count / 4, buffer);
+}
+
+const struct flash_driver renesas_rpchf_flash = {
+ .name = "rpchf",
+ .flash_bank_command = rpchf_flash_bank_command,
+ .erase = cfi_erase,
+ .protect = cfi_protect,
+ .write = rpchf_write,
+ .read = rpchf_read,
+ .probe = cfi_probe,
+ .auto_probe = cfi_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = cfi_protect_check,
+ .info = cfi_get_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c
new file mode 100644
index 0000000..862e43a
--- /dev/null
+++ b/src/flash/nor/sh_qspi.c
@@ -0,0 +1,912 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SH QSPI (Quad SPI) driver
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on U-Boot SH QSPI driver
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "spi.h"
+#include <helper/binarybuffer.h>
+#include <helper/bits.h>
+#include <helper/time_support.h>
+#include <helper/types.h>
+#include <jtag/jtag.h>
+#include <target/algorithm.h>
+#include <target/arm.h>
+#include <target/arm_opcodes.h>
+#include <target/target.h>
+
+/* SH QSPI register bit masks <REG>_<BIT> */
+#define SPCR_MSTR 0x08
+#define SPCR_SPE 0x40
+#define SPSR_SPRFF 0x80
+#define SPSR_SPTEF 0x20
+#define SPPCR_IO3FV 0x04
+#define SPPCR_IO2FV 0x02
+#define SPPCR_IO1FV 0x01
+#define SPBDCR_RXBC0 BIT(0)
+#define SPCMD_SCKDEN BIT(15)
+#define SPCMD_SLNDEN BIT(14)
+#define SPCMD_SPNDEN BIT(13)
+#define SPCMD_SSLKP BIT(7)
+#define SPCMD_BRDV0 BIT(2)
+#define SPCMD_INIT1 (SPCMD_SCKDEN | SPCMD_SLNDEN | \
+ SPCMD_SPNDEN | SPCMD_SSLKP | \
+ SPCMD_BRDV0)
+#define SPCMD_INIT2 (SPCMD_SPNDEN | SPCMD_SSLKP | \
+ SPCMD_BRDV0)
+#define SPBFCR_TXRST BIT(7)
+#define SPBFCR_RXRST BIT(6)
+#define SPBFCR_TXTRG 0x30
+#define SPBFCR_RXTRG 0x07
+
+/* SH QSPI register set */
+#define SH_QSPI_SPCR 0x00
+#define SH_QSPI_SSLP 0x01
+#define SH_QSPI_SPPCR 0x02
+#define SH_QSPI_SPSR 0x03
+#define SH_QSPI_SPDR 0x04
+#define SH_QSPI_SPSCR 0x08
+#define SH_QSPI_SPSSR 0x09
+#define SH_QSPI_SPBR 0x0a
+#define SH_QSPI_SPDCR 0x0b
+#define SH_QSPI_SPCKD 0x0c
+#define SH_QSPI_SSLND 0x0d
+#define SH_QSPI_SPND 0x0e
+#define SH_QSPI_DUMMY0 0x0f
+#define SH_QSPI_SPCMD0 0x10
+#define SH_QSPI_SPCMD1 0x12
+#define SH_QSPI_SPCMD2 0x14
+#define SH_QSPI_SPCMD3 0x16
+#define SH_QSPI_SPBFCR 0x18
+#define SH_QSPI_DUMMY1 0x19
+#define SH_QSPI_SPBDCR 0x1a
+#define SH_QSPI_SPBMUL0 0x1c
+#define SH_QSPI_SPBMUL1 0x20
+#define SH_QSPI_SPBMUL2 0x24
+#define SH_QSPI_SPBMUL3 0x28
+
+struct sh_qspi_flash_bank {
+ const struct flash_device *dev;
+ uint32_t io_base;
+ int probed;
+ struct working_area *io_algorithm;
+ struct working_area *source;
+ unsigned int buffer_size;
+};
+
+struct sh_qspi_target {
+ char *name;
+ uint32_t tap_idcode;
+ uint32_t io_base;
+};
+
+static const struct sh_qspi_target target_devices[] = {
+ /* name, tap_idcode, io_base */
+ { "SH QSPI", 0x4ba00477, 0xe6b10000 },
+ { NULL, 0, 0 }
+};
+
+static int sh_qspi_init(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t val;
+ int ret;
+
+ /* QSPI initialize */
+ /* Set master mode only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set SSL signal level */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set MOSI signal value when transfer is in idle state */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR,
+ SPPCR_IO3FV | SPPCR_IO2FV);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Disable Dummy Data Transmission */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set clock delay value */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set SSL negation delay value */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set next-access delay value */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set equence command */
+ ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
+ SPCMD_INIT2);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Reset transfer and receive Buffer */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPBFCR_TXRST | SPBFCR_RXRST;
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Clear transfer and receive Buffer control bit */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set equence control method. Use equence0 only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Enable SPI function */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPCR_SPE;
+
+ return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+}
+
+static int sh_qspi_cs_activate(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t val;
+ int ret;
+
+ /* Set master mode only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set command */
+ ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
+ SPCMD_INIT1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Reset transfer and receive Buffer */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPBFCR_TXRST | SPBFCR_RXRST;
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Clear transfer and receive Buffer control bit */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set equence control method. Use equence0 only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Enable SPI function */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPCR_SPE;
+
+ return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+}
+
+static int sh_qspi_cs_deactivate(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t val;
+ int ret;
+
+ /* Disable SPI Function */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~SPCR_SPE;
+
+ return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+}
+
+static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg,
+ uint32_t mask, bool set,
+ unsigned long timeout)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ long long endtime;
+ uint8_t val;
+ int ret;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ ret = target_read_u8(target, info->io_base + reg, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (!set)
+ val = ~val;
+
+ if ((val & mask) == mask)
+ return ERROR_OK;
+
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static int sh_qspi_xfer_common(struct flash_bank *bank,
+ const uint8_t *dout, unsigned int outlen,
+ uint8_t *din, unsigned int inlen,
+ bool xfer_start, bool xfer_end)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t tdata, rdata;
+ uint8_t val;
+ unsigned int nbyte = outlen + inlen;
+ int ret = 0;
+
+ if (xfer_start) {
+ ret = sh_qspi_cs_activate(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0,
+ nbyte);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR,
+ &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG);
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR,
+ val);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ while (nbyte > 0) {
+ ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF,
+ true, 1000);
+ if (ret != ERROR_OK)
+ return ret;
+
+ tdata = outlen ? *dout++ : 0;
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR,
+ tdata);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF,
+ true, 1000);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR,
+ &rdata);
+ if (ret != ERROR_OK)
+ return ret;
+ if (!outlen && inlen) {
+ *din++ = rdata;
+ inlen--;
+ }
+
+ if (outlen)
+ outlen--;
+
+ nbyte--;
+ }
+
+ if (xfer_end)
+ return sh_qspi_cs_deactivate(bank);
+ else
+ return ERROR_OK;
+}
+
+/* Send "write enable" command to SPI flash chip. */
+static int sh_qspi_write_enable(struct flash_bank *bank)
+{
+ uint8_t dout = SPIFLASH_WRITE_ENABLE;
+
+ return sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1);
+}
+
+/* Read the status register of the external SPI flash chip. */
+static int read_status_reg(struct flash_bank *bank, uint32_t *status)
+{
+ uint8_t dout = SPIFLASH_READ_STATUS;
+ uint8_t din;
+ int ret;
+
+ ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ *status = din & 0xff;
+
+ return ERROR_OK;
+}
+
+/* check for WIP (write in progress) bit in status register */
+/* timeout in ms */
+static int wait_till_ready(struct flash_bank *bank, int timeout)
+{
+ long long endtime;
+ uint32_t status;
+ int ret;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ /* read flash status register */
+ ret = read_status_reg(bank, &status);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if ((status & SPIFLASH_BSY_BIT) == 0)
+ return ERROR_OK;
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static int sh_qspi_erase_sector(struct flash_bank *bank, int sector)
+{
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ bool addr4b = info->dev->size_in_bytes > (1UL << 24);
+ uint32_t address = (sector * info->dev->sectorsize) <<
+ (addr4b ? 0 : 8);
+ uint8_t dout[5] = {
+ info->dev->erase_cmd,
+ (address >> 24) & 0xff, (address >> 16) & 0xff,
+ (address >> 8) & 0xff, (address >> 0) & 0xff
+ };
+ unsigned int doutlen = addr4b ? 5 : 4;
+ int ret;
+
+ /* Write Enable */
+ ret = sh_qspi_write_enable(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Erase */
+ ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Poll status register */
+ return wait_till_ready(bank, 3000);
+}
+
+static int sh_qspi_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ int retval = ERROR_OK;
+ int sector;
+
+ LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
+ LOG_ERROR("Flash sector invalid");
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ if (!info->probed) {
+ LOG_ERROR("Flash bank not probed");
+ return ERROR_FLASH_BANK_NOT_PROBED;
+ }
+
+ if (info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
+ for (sector = first; sector <= last; sector++) {
+ if (bank->sectors[sector].is_protected) {
+ LOG_ERROR("Flash sector %d protected", sector);
+ return ERROR_FAIL;
+ }
+ }
+
+ for (sector = first; sector <= last; sector++) {
+ retval = sh_qspi_erase_sector(bank, sector);
+ if (retval != ERROR_OK)
+ break;
+ keep_alive();
+ }
+
+ return retval;
+}
+
+static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ struct reg_param reg_params[4];
+ struct arm_algorithm arm_algo;
+ uint32_t io_base = (uint32_t)(info->io_base);
+ uint32_t src_base = (uint32_t)(info->source->address);
+ uint32_t chunk;
+ bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
+ int ret = ERROR_OK;
+ int sector;
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size) {
+ LOG_WARNING("Write pasts end of flash. Extra data discarded.");
+ count = bank->size - offset;
+ }
+
+ if (offset & 0xff) {
+ LOG_ERROR("sh_qspi_write_page: unaligned write address: %08x",
+ offset);
+ return ERROR_FAIL;
+ }
+
+ /* Check sector protection */
+ for (sector = 0; sector < bank->num_sectors; sector++) {
+ /* Start offset in or before this sector? */
+ /* End offset in or behind this sector? */
+ struct flash_sector *bs = &bank->sectors[sector];
+
+ if ((offset < (bs->offset + bs->size)) &&
+ ((offset + count - 1) >= bs->offset) &&
+ bs->is_protected) {
+ LOG_ERROR("Flash sector %d protected", sector);
+ return ERROR_FAIL;
+ }
+ }
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size) {
+ LOG_WARNING("Reads past end of flash. Extra data discarded.");
+ count = bank->size - offset;
+ }
+
+ arm_algo.common_magic = ARM_COMMON_MAGIC;
+ arm_algo.core_mode = ARM_MODE_SVC;
+ arm_algo.core_state = ARM_STATE_ARM;
+
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+
+ while (count > 0) {
+ chunk = (count > info->buffer_size) ?
+ info->buffer_size : count;
+
+ target_write_buffer(target, info->source->address,
+ chunk, buffer);
+
+ buf_set_u32(reg_params[0].value, 0, 32, io_base);
+ buf_set_u32(reg_params[1].value, 0, 32, src_base);
+ buf_set_u32(reg_params[2].value, 0, 32,
+ (1 << 31) | (addr4b << 30) |
+ (info->dev->pprog_cmd << 20) | chunk);
+ buf_set_u32(reg_params[3].value, 0, 32, offset);
+
+ ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ info->io_algorithm->address,
+ 0, 10000, &arm_algo);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("error executing SH QSPI flash IO algorithm");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+
+ buffer += chunk;
+ offset += chunk;
+ count -= chunk;
+ }
+
+ destroy_reg_param(&reg_params[0]);
+ destroy_reg_param(&reg_params[1]);
+ destroy_reg_param(&reg_params[2]);
+ destroy_reg_param(&reg_params[3]);
+
+ return ret;
+}
+
+static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ struct reg_param reg_params[4];
+ struct arm_algorithm arm_algo;
+ uint32_t io_base = (uint32_t)(info->io_base);
+ uint32_t src_base = (uint32_t)(info->source->address);
+ uint32_t chunk;
+ bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
+ int ret = ERROR_OK;
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size) {
+ LOG_WARNING("Reads past end of flash. Extra data discarded.");
+ count = bank->size - offset;
+ }
+
+ arm_algo.common_magic = ARM_COMMON_MAGIC;
+ arm_algo.core_mode = ARM_MODE_SVC;
+ arm_algo.core_state = ARM_STATE_ARM;
+
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+
+ while (count > 0) {
+ chunk = (count > info->buffer_size) ?
+ info->buffer_size : count;
+
+ buf_set_u32(reg_params[0].value, 0, 32, io_base);
+ buf_set_u32(reg_params[1].value, 0, 32, src_base);
+ buf_set_u32(reg_params[2].value, 0, 32,
+ (addr4b << 30) | (info->dev->read_cmd << 20) |
+ chunk);
+ buf_set_u32(reg_params[3].value, 0, 32, offset);
+
+ ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ info->io_algorithm->address,
+ 0, 10000, &arm_algo);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("error executing SH QSPI flash IO algorithm");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+
+ target_read_buffer(target, info->source->address,
+ chunk, buffer);
+
+ buffer += chunk;
+ offset += chunk;
+ count -= chunk;
+ }
+
+ destroy_reg_param(&reg_params[0]);
+ destroy_reg_param(&reg_params[1]);
+ destroy_reg_param(&reg_params[2]);
+ destroy_reg_param(&reg_params[3]);
+
+ return ret;
+}
+
+/* Return ID of flash device */
+static int read_flash_id(struct flash_bank *bank, uint32_t *id)
+{
+ struct target *target = bank->target;
+ uint8_t dout = SPIFLASH_READ_ID;
+ uint8_t din[3] = { 0, 0, 0 };
+ int ret;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ *id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16);
+
+ if (*id == 0xffffff) {
+ LOG_ERROR("No SPI flash found");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int sh_qspi_protect(struct flash_bank *bank, int set,
+ int first, int last)
+{
+ int sector;
+
+ for (sector = first; sector <= last; sector++)
+ bank->sectors[sector].is_protected = set;
+
+ return ERROR_OK;
+}
+
+static int sh_qspi_upload_helper(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+ /* see contrib/loaders/flash/sh_qspi.s for src */
+ static const uint8_t sh_qspi_io_code[] = {
+#include "../../../contrib/loaders/flash/sh_qspi/sh_qspi.inc"
+ };
+ int ret;
+
+ if (info->source)
+ target_free_working_area(target, info->source);
+ if (info->io_algorithm)
+ target_free_working_area(target, info->io_algorithm);
+
+ /* flash write code */
+ if (target_alloc_working_area(target, sizeof(sh_qspi_io_code),
+ &info->io_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ target_write_buffer(target, info->io_algorithm->address,
+ sizeof(sh_qspi_io_code), sh_qspi_io_code);
+
+ /*
+ * Try to allocate as big work area buffer as possible, start
+ * with 32 kiB and count down. If there is less than 256 Bytes
+ * of work area available, abort.
+ */
+ info->buffer_size = 32768;
+ while (true) {
+ ret = target_alloc_working_area_try(target, info->buffer_size,
+ &info->source);
+ if (ret == ERROR_OK)
+ return ret;
+
+ info->buffer_size /= 2;
+ if (info->buffer_size <= 256) {
+ target_free_working_area(target, info->io_algorithm);
+
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int sh_qspi_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ struct flash_sector *sectors;
+ uint32_t id = 0; /* silence uninitialized warning */
+ uint32_t sectorsize;
+ const struct sh_qspi_target *target_device;
+ int ret;
+
+ if (info->probed)
+ free(bank->sectors);
+
+ info->probed = 0;
+
+ for (target_device = target_devices; target_device->name;
+ ++target_device)
+ if (target_device->tap_idcode == target->tap->idcode)
+ break;
+ if (!target_device->name) {
+ LOG_ERROR("Device ID 0x%" PRIx32 " is not known",
+ target->tap->idcode);
+ return ERROR_FAIL;
+ }
+
+ info->io_base = target_device->io_base;
+
+ LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT,
+ target_device->name, bank->base);
+
+ ret = sh_qspi_upload_helper(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = sh_qspi_init(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = read_flash_id(bank, &id);
+ if (ret != ERROR_OK)
+ return ret;
+
+ info->dev = NULL;
+ for (const struct flash_device *p = flash_devices; p->name; p++)
+ if (p->device_id == id) {
+ info->dev = p;
+ break;
+ }
+
+ if (!info->dev) {
+ LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
+ info->dev->name, info->dev->device_id);
+
+ /* Set correct size value */
+ bank->size = info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = info->dev->sectorsize ?
+ info->dev->sectorsize :
+ info->dev->size_in_bytes;
+
+ /* create and fill sectors array */
+ bank->num_sectors = info->dev->size_in_bytes / sectorsize;
+ sectors = calloc(1, sizeof(*sectors) * bank->num_sectors);
+ if (!sectors) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ for (int sector = 0; sector < bank->num_sectors; sector++) {
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
+ sectors[sector].is_erased = 0;
+ sectors[sector].is_protected = 0;
+ }
+
+ bank->sectors = sectors;
+ info->probed = 1;
+ return ERROR_OK;
+}
+
+static int sh_qspi_auto_probe(struct flash_bank *bank)
+{
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+ if (info->probed)
+ return ERROR_OK;
+
+ return sh_qspi_probe(bank);
+}
+
+static int sh_qspi_flash_blank_check(struct flash_bank *bank)
+{
+ /* Not implemented */
+ return ERROR_OK;
+}
+
+static int sh_qspi_protect_check(struct flash_bank *bank)
+{
+ /* Not implemented */
+ return ERROR_OK;
+}
+
+static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+ if (!info->probed) {
+ snprintf(buf, buf_size,
+ "\nSH QSPI flash bank not probed yet\n");
+ return ERROR_OK;
+ }
+
+ snprintf(buf, buf_size, "\nSH QSPI flash information:\n"
+ " Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+ info->dev->name, info->dev->device_id);
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command)
+{
+ struct sh_qspi_flash_bank *info;
+
+ LOG_DEBUG("%s", __func__);
+
+ if (CMD_ARGC < 6 || CMD_ARGC > 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) {
+ LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ info = calloc(1, sizeof(struct sh_qspi_flash_bank));
+ if (!info) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ bank->driver_priv = info;
+
+ return ERROR_OK;
+}
+
+const struct flash_driver sh_qspi_flash = {
+ .name = "sh_qspi",
+ .flash_bank_command = sh_qspi_flash_bank_command,
+ .erase = sh_qspi_erase,
+ .protect = sh_qspi_protect,
+ .write = sh_qspi_write,
+ .read = sh_qspi_read,
+ .probe = sh_qspi_probe,
+ .auto_probe = sh_qspi_auto_probe,
+ .erase_check = sh_qspi_flash_blank_check,
+ .protect_check = sh_qspi_protect_check,
+ .info = sh_qspi_get_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c
index 7ccf56b..4e39705 100644
--- a/src/flash/nor/sim3x.c
+++ b/src/flash/nor/sim3x.c
@@ -471,7 +471,7 @@ static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf,
return ret;
}
-static int sim3x_flash_write(struct flash_bank *bank, const uint8_t * buffer, uint32_t offset, uint32_t count)
+static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int ret;
struct target *target;
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index cf10e37..990b48a 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -116,7 +116,7 @@ struct stm32x_options {
struct stm32x_flash_bank {
struct stm32x_options option_bytes;
int ppage_size;
- int probed;
+ bool probed;
bool has_dual_banks;
/* used to access dual flash bank stm32xl */
@@ -145,7 +145,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
bank->driver_priv = stm32x_info;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->has_dual_banks = false;
stm32x_info->can_load_options = false;
stm32x_info->register_base = FLASH_REG_BASE_B0;
@@ -229,34 +229,20 @@ static int stm32x_read_options(struct flash_bank *bank)
uint32_t option_bytes;
int retval;
- /* read user and read protection option bytes */
- retval = target_read_u32(target, STM32_OB_RDP, &option_bytes);
+ /* read user and read protection option bytes, user data option bytes */
+ retval = target_read_u32(target, STM32_FLASH_OBR_B0, &option_bytes);
if (retval != ERROR_OK)
return retval;
- stm32x_info->option_bytes.rdp = option_bytes & 0xFF;
- stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF;
-
- /* read user data option bytes */
- retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes);
- if (retval != ERROR_OK)
- return retval;
-
- stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
+ stm32x_info->option_bytes.rdp = (option_bytes & (1 << OPT_READOUT)) ? 0 : stm32x_info->default_rdp;
+ stm32x_info->option_bytes.user = (option_bytes >> stm32x_info->option_offset >> 2) & 0xff;
+ stm32x_info->option_bytes.data = (option_bytes >> stm32x_info->user_data_offset) & 0xffff;
/* read write protection option bytes */
- retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes);
+ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &stm32x_info->option_bytes.protection);
if (retval != ERROR_OK)
return retval;
- stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
-
- retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes);
- if (retval != ERROR_OK)
- return retval;
-
- stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16;
-
return ERROR_OK;
}
@@ -382,7 +368,6 @@ static int stm32x_protect_check(struct flash_bank *bank)
static int stm32x_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
- int i;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -400,7 +385,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
if (retval != ERROR_OK)
return retval;
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER);
if (retval != ERROR_OK)
return retval;
@@ -711,7 +696,7 @@ static int stm32x_probe(struct flash_bank *bank)
int page_size;
uint32_t base_address = 0x08000000;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->register_base = FLASH_REG_BASE_B0;
stm32x_info->user_data_offset = 10;
stm32x_info->option_offset = 0;
@@ -728,31 +713,79 @@ static int stm32x_probe(struct flash_bank *bank)
/* set page size, protection granularity and max flash size depending on family */
switch (device_id & 0xfff) {
- case 0x410: /* medium density */
+ case 0x440: /* stm32f05x */
+ page_size = 1024;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 64;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x444: /* stm32f03x */
+ case 0x445: /* stm32f04x */
+ page_size = 1024;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 32;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x448: /* stm32f07x */
+ page_size = 2048;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 128;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x442: /* stm32f09x */
+ page_size = 2048;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 256;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x410: /* stm32f1x medium-density */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 128;
break;
- case 0x412: /* low density */
+ case 0x412: /* stm32f1x low-density */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 32;
break;
- case 0x414: /* high density */
+ case 0x414: /* stm32f1x high-density */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 512;
break;
- case 0x418: /* connectivity line density */
+ case 0x418: /* stm32f1x connectivity */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 256;
break;
- case 0x420: /* value line density */
+ case 0x430: /* stm32f1 XL-density (dual flash banks) */
+ page_size = 2048;
+ stm32x_info->ppage_size = 2;
+ max_flash_size_in_kb = 1024;
+ stm32x_info->has_dual_banks = true;
+ break;
+ case 0x420: /* stm32f100xx low- and medium-density value line */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 128;
break;
+ case 0x428: /* stm32f100xx high-density value line */
+ page_size = 2048;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 512;
+ break;
case 0x422: /* stm32f302/3xb/c */
page_size = 2048;
stm32x_info->ppage_size = 2;
@@ -771,17 +804,6 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->default_rdp = 0xAA;
stm32x_info->can_load_options = true;
break;
- case 0x428: /* value line High density */
- page_size = 2048;
- stm32x_info->ppage_size = 4;
- max_flash_size_in_kb = 128;
- break;
- case 0x430: /* xl line density (dual flash banks) */
- page_size = 2048;
- stm32x_info->ppage_size = 2;
- max_flash_size_in_kb = 1024;
- stm32x_info->has_dual_banks = true;
- break;
case 0x432: /* stm32f37x */
page_size = 2048;
stm32x_info->ppage_size = 2;
@@ -801,27 +823,6 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->default_rdp = 0xAA;
stm32x_info->can_load_options = true;
break;
- case 0x440: /* stm32f05x */
- case 0x444: /* stm32f03x */
- case 0x445: /* stm32f04x */
- page_size = 1024;
- stm32x_info->ppage_size = 4;
- max_flash_size_in_kb = 64;
- stm32x_info->user_data_offset = 16;
- stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0xAA;
- stm32x_info->can_load_options = true;
- break;
- case 0x448: /* stm32f07x */
- case 0x442: /* stm32f09x */
- page_size = 2048;
- stm32x_info->ppage_size = 4;
- max_flash_size_in_kb = 256;
- stm32x_info->user_data_offset = 16;
- stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0xAA;
- stm32x_info->can_load_options = true;
- break;
default:
LOG_WARNING("Cannot identify target as a STM32 family.");
return ERROR_FAIL;
@@ -900,7 +901,7 @@ static int stm32x_probe(struct flash_bank *bank)
if (num_prot_blocks == 32)
bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size;
- stm32x_info->probed = 1;
+ stm32x_info->probed = true;
return ERROR_OK;
}
@@ -1368,8 +1369,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt);
CMD_ARGC--;
CMD_ARGV++;
- }
- else if (stm32x_info->has_dual_banks) {
+ } else if (stm32x_info->has_dual_banks) {
if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
optionbyte |= (1 << 3);
else if (strcmp("BOOT1", CMD_ARGV[0]) == 0)
@@ -1488,8 +1488,6 @@ static int stm32x_mass_erase(struct flash_bank *bank)
COMMAND_HANDLER(stm32x_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1501,7 +1499,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
retval = stm32x_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32x mass erase complete");
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index b49e76e..c1283bb 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -634,7 +634,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
*/
for (i = first; i <= last; i++) {
- int snb;
+ unsigned int snb;
if (stm32x_info->has_large_mem && i >= 12)
snb = (i - 12) | 0x10;
else
@@ -894,31 +894,68 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
}
-static int setup_sector(struct flash_bank *bank, int start, int num, int size)
+static void setup_sector(struct flash_bank *bank, int i, int size)
{
+ assert(i < bank->num_sectors);
+ bank->sectors[i].offset = bank->size;
+ bank->sectors[i].size = size;
+ bank->size += bank->sectors[i].size;
+ LOG_DEBUG("sector %d: %dkBytes", i, size >> 10);
+}
+
+static uint16_t sector_size_in_kb(int i, uint16_t max_sector_size_in_kb)
+{
+ assert(i >= 0);
+ if (i < 4)
+ return max_sector_size_in_kb / 8;
+ if (i == 4)
+ return max_sector_size_in_kb / 2;
+ return max_sector_size_in_kb;
+}
+
+static int calculate_number_of_sectors(struct flash_bank *bank,
+ uint16_t flash_size_in_kb,
+ uint16_t max_sector_size_in_kb)
+{
+ struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+ uint16_t remaining_flash_size_in_kb = flash_size_in_kb;
+ int nr_sectors;
- for (int i = start; i < (start + num) ; i++) {
- assert(i < bank->num_sectors);
- bank->sectors[i].offset = bank->size;
- bank->sectors[i].size = size;
- bank->size += bank->sectors[i].size;
- LOG_DEBUG("sector %d: %d kBytes", i, size >> 10);
+ /* Dual Bank Flash has two identically-arranged banks of sectors. */
+ if (stm32x_info->has_large_mem)
+ remaining_flash_size_in_kb /= 2;
+
+ for (nr_sectors = 0; remaining_flash_size_in_kb > 0; nr_sectors++) {
+ uint16_t size_in_kb = sector_size_in_kb(nr_sectors, max_sector_size_in_kb);
+ if (size_in_kb > remaining_flash_size_in_kb) {
+ LOG_INFO("%s Bank %" PRIu16 " kiB final sector clipped to %" PRIu16 " kiB",
+ stm32x_info->has_large_mem ? "Dual" : "Single",
+ flash_size_in_kb, remaining_flash_size_in_kb);
+ remaining_flash_size_in_kb = 0;
+ } else {
+ remaining_flash_size_in_kb -= size_in_kb;
+ }
}
- return start + num;
+ return stm32x_info->has_large_mem ? nr_sectors*2 : nr_sectors;
}
static void setup_bank(struct flash_bank *bank, int start,
uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb)
{
- int remain;
-
- start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024);
- start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024);
-
- /* remaining sectors all of size max_sector_size_in_kb */
- remain = (flash_size_in_kb / max_sector_size_in_kb) - 1;
- start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024);
+ uint16_t remaining_flash_size_in_kb = flash_size_in_kb;
+ int sector_index = 0;
+ while (remaining_flash_size_in_kb > 0) {
+ uint16_t size_in_kb = sector_size_in_kb(sector_index, max_sector_size_in_kb);
+ if (size_in_kb > remaining_flash_size_in_kb) {
+ /* Clip last sector. Already warned in
+ * calculate_number_of_sectors. */
+ size_in_kb = remaining_flash_size_in_kb;
+ }
+ setup_sector(bank, start + sector_index, size_in_kb * 1024);
+ remaining_flash_size_in_kb -= size_in_kb;
+ sector_index++;
+ }
}
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
@@ -1150,12 +1187,12 @@ static int stm32x_probe(struct flash_bank *bank)
}
/* calculate numbers of pages */
- int num_pages = flash_size_in_kb / max_sector_size_in_kb
- + (stm32x_info->has_large_mem ? 8 : 4);
+ int num_pages = calculate_number_of_sectors(
+ bank, flash_size_in_kb, max_sector_size_in_kb);
bank->base = base_address;
bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+ bank->sectors = calloc(num_pages, sizeof(struct flash_sector));
for (i = 0; i < num_pages; i++) {
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c
index fd6bf9a..7b6fdb3 100644
--- a/src/flash/nor/stm32h7x.c
+++ b/src/flash/nor/stm32h7x.c
@@ -57,8 +57,6 @@
#define FLASH_FW (1 << 6)
#define FLASH_START (1 << 7)
-#define FLASH_SNB(a) ((a) << 8)
-
/* FLASH_SR register bits */
#define FLASH_BSY (1 << 0) /* Operation in progress */
#define FLASH_QW (1 << 2) /* Operation queue in progress */
@@ -79,6 +77,15 @@
#define OPT_LOCK (1 << 0)
#define OPT_START (1 << 1)
+/* FLASH_OPTSR register bits */
+#define OPT_BSY (1 << 0)
+#define OPT_RDP_POS 8
+#define OPT_RDP_MASK (0xff << OPT_RDP_POS)
+#define OPT_OPTCHANGEERR (1 << 30)
+
+/* FLASH_OPTCCR register bits */
+#define OPT_CLR_OPTCHANGEERR (1 << 30)
+
/* register unlock keys */
#define KEY1 0x45670123
#define KEY2 0xCDEF89AB
@@ -92,68 +99,103 @@
#define FLASH_BANK1_ADDRESS 0x08100000
#define FLASH_REG_BASE_B0 0x52002000
#define FLASH_REG_BASE_B1 0x52002100
-#define FLASH_SIZE_ADDRESS 0x1FF1E880
-#define FLASH_BLOCK_SIZE 32
struct stm32h7x_rev {
uint16_t rev;
const char *str;
};
-struct stm32x_options {
- uint8_t RDP;
- uint32_t protection; /* bank1 WRP */
- uint32_t protection2; /* bank2 WRP */
- uint8_t user_options;
- uint8_t user2_options;
- uint8_t user3_options;
-};
+/* stm32h7x_part_info permits the store each device information and specificities.
+ * the default unit is byte unless the suffix '_kb' is used. */
struct stm32h7x_part_info {
uint16_t id;
const char *device_str;
const struct stm32h7x_rev *revs;
size_t num_revs;
- unsigned int page_size;
+ unsigned int page_size_kb;
+ unsigned int block_size; /* flash write word size in bytes */
uint16_t max_flash_size_kb;
- uint8_t has_dual_bank;
- uint16_t first_bank_size_kb; /* Used when has_dual_bank is true */
- uint32_t flash_base; /* Flash controller registers location */
- uint32_t fsize_base; /* Location of FSIZE register */
+ bool has_dual_bank;
+ uint16_t max_bank_size_kb; /* Used when has_dual_bank is true */
+ uint32_t fsize_addr; /* Location of FSIZE register */
+ uint32_t wps_group_size; /* write protection group sectors' count */
+ uint32_t wps_mask;
+ /* function to compute flash_cr register values */
+ uint32_t (*compute_flash_cr)(uint32_t cmd, int snb);
};
struct stm32h7x_flash_bank {
- int probed;
+ bool probed;
uint32_t idcode;
uint32_t user_bank_size;
- uint32_t flash_base; /* Address of flash reg controller */
- struct stm32x_options option_bytes;
+ uint32_t flash_regs_base; /* Address of flash reg controller */
const struct stm32h7x_part_info *part_info;
};
+enum stm32h7x_opt_rdp {
+ OPT_RDP_L0 = 0xaa,
+ OPT_RDP_L1 = 0x00,
+ OPT_RDP_L2 = 0xcc
+};
+
static const struct stm32h7x_rev stm32_450_revs[] = {
- { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" },
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" },
+};
+
+static const struct stm32h7x_rev stm32_480_revs[] = {
+ { 0x1000, "A"},
};
+static uint32_t stm32x_compute_flash_cr_450(uint32_t cmd, int snb)
+{
+ return cmd | (snb << 8);
+}
+
+static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb)
+{
+ /* save FW and START bits, to be right shifted by 2 bits later */
+ const uint32_t tmp = cmd & (FLASH_FW | FLASH_START);
+
+ /* mask parallelism (ignored), FW and START bits */
+ cmd &= ~(FLASH_PSIZE_64 | FLASH_FW | FLASH_START);
+
+ return cmd | (tmp >> 2) | (snb << 6);
+}
+
static const struct stm32h7x_part_info stm32h7x_parts[] = {
{
.id = 0x450,
.revs = stm32_450_revs,
.num_revs = ARRAY_SIZE(stm32_450_revs),
.device_str = "STM32H74x/75x",
- .page_size = 128, /* 128 KB */
+ .page_size_kb = 128,
+ .block_size = 32,
+ .max_flash_size_kb = 2048,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = true,
+ .fsize_addr = 0x1FF1E880,
+ .wps_group_size = 1,
+ .wps_mask = 0xFF,
+ .compute_flash_cr = stm32x_compute_flash_cr_450,
+ },
+ {
+ .id = 0x480,
+ .revs = stm32_480_revs,
+ .num_revs = ARRAY_SIZE(stm32_480_revs),
+ .device_str = "STM32H7Ax/7Bx",
+ .page_size_kb = 8,
+ .block_size = 16,
.max_flash_size_kb = 2048,
- .first_bank_size_kb = 1024,
- .has_dual_bank = 1,
- .flash_base = FLASH_REG_BASE_B0,
- .fsize_base = FLASH_SIZE_ADDRESS,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = true,
+ .fsize_addr = 0x08FFF80C,
+ .wps_group_size = 4,
+ .wps_mask = 0xFFFFFFFF,
+ .compute_flash_cr = stm32x_compute_flash_cr_480,
},
};
-static int stm32x_unlock_reg(struct flash_bank *bank);
-static int stm32x_lock_reg(struct flash_bank *bank);
-static int stm32x_probe(struct flash_bank *bank);
-
/* flash bank stm32x <base> <size> 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
@@ -166,51 +208,68 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank));
bank->driver_priv = stm32x_info;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->user_bank_size = bank->size;
return ERROR_OK;
}
-static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
{
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
- return reg + stm32x_info->flash_base;
+ return reg_offset + stm32x_info->flash_regs_base;
+}
+
+static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
+{
+ uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset);
+ int retval = target_read_u32(bank->target, reg_addr, value);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("error while reading from address 0x%" PRIx32, reg_addr);
+
+ return retval;
+}
+
+static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset);
+ int retval = target_write_u32(bank->target, reg_addr, value);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("error while writing to address 0x%" PRIx32, reg_addr);
+
+ return retval;
}
static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status)
{
- struct target *target = bank->target;
- return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status);
+ return stm32x_read_flash_reg(bank, FLASH_SR, status);
}
static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
{
- struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
uint32_t status;
int retval;
/* wait for flash operations completion */
for (;;) {
retval = stm32x_get_flash_status(bank, &status);
- if (retval != ERROR_OK) {
- LOG_INFO("wait_flash_op_queue, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base);
+ if (retval != ERROR_OK)
return retval;
- }
if ((status & FLASH_QW) == 0)
break;
if (timeout-- <= 0) {
- LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status);
+ LOG_ERROR("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status);
return ERROR_FAIL;
}
alive_sleep(1);
}
if (status & FLASH_WRPERR) {
- LOG_INFO("wait_flash_op_queue, WRPERR : error : remote address 0x%x", stm32x_info->flash_base);
+ LOG_ERROR("wait_flash_op_queue, WRPERR detected");
retval = ERROR_FAIL;
}
@@ -219,7 +278,7 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
if (retval == ERROR_OK)
retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original retval */
- target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status);
+ stm32x_write_flash_reg(bank, FLASH_CCR, status);
}
return retval;
}
@@ -227,12 +286,11 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
static int stm32x_unlock_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- struct target *target = bank->target;
/* first check if not already unlocked
* otherwise writing on FLASH_KEYR will fail
*/
- int retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl);
+ int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -240,15 +298,15 @@ static int stm32x_unlock_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock flash registers for bank */
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1);
+ retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY2);
+ retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl);
+ retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -262,9 +320,8 @@ static int stm32x_unlock_reg(struct flash_bank *bank)
static int stm32x_unlock_option_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- struct target *target = bank->target;
- int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl);
+ int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -272,15 +329,15 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock option registers */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl);
+ retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -292,159 +349,108 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
}
-static int stm32x_lock_reg(struct flash_bank *bank)
+static inline int stm32x_lock_reg(struct flash_bank *bank)
{
- struct target *target = bank->target;
-
- /* Lock bank reg */
- int retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_LOCK);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK);
}
-static int stm32x_read_options(struct flash_bank *bank)
+static inline int stm32x_lock_option_reg(struct flash_bank *bank)
{
- uint32_t optiondata;
- struct stm32h7x_flash_bank *stm32x_info = NULL;
- struct target *target = bank->target;
-
- stm32x_info = bank->driver_priv;
-
- /* read current option bytes */
- int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_CUR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
-
- /* decode option data */
- stm32x_info->option_bytes.user_options = optiondata & 0xfc;
- stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff;
- stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff;
- stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0xa3;
-
- if (stm32x_info->option_bytes.RDP != 0xAA)
- LOG_INFO("Device Security Bit Set");
-
- /* read current WPSN option bytes */
- retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_CUR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32x_info->option_bytes.protection = optiondata & 0xff;
-
- /* read current WPSN2 option bytes */
- retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_CUR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32x_info->option_bytes.protection2 = optiondata & 0xff;
-
- return ERROR_OK;
+ return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK);
}
-static int stm32x_write_options(struct flash_bank *bank)
+static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
{
- struct stm32h7x_flash_bank *stm32x_info = NULL;
- struct target *target = bank->target;
- uint32_t optiondata;
-
- stm32x_info = bank->driver_priv;
-
- int retval = stm32x_unlock_option_reg(bank);
- if (retval != ERROR_OK)
- return retval;
-
- /* rebuild option data */
- optiondata = stm32x_info->option_bytes.user_options;
- optiondata |= (stm32x_info->option_bytes.RDP << 8);
- optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16;
- optiondata |= (stm32x_info->option_bytes.user3_options & 0xa3) << 24;
+ int retval, retval2;
- /* program options */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_PRG, optiondata);
+ /* unlock option bytes for modification */
+ retval = stm32x_unlock_option_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
- optiondata = stm32x_info->option_bytes.protection & 0xff;
- /* Program protection WPSNPRG */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_PRG, optiondata);
+ /* write option bytes */
+ retval = stm32x_write_flash_reg(bank, reg_offset, value);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
- optiondata = stm32x_info->option_bytes.protection2 & 0xff;
- /* Program protection WPSNPRG2 */
- retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_PRG, optiondata);
- if (retval != ERROR_OK)
- return retval;
-
- optiondata = 0x40000000;
/* Remove OPT error flag before programming */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
/* start programming cycle */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
/* wait for completion */
int timeout = FLASH_ERASE_TIMEOUT;
+ uint32_t status;
for (;;) {
- uint32_t status;
- retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status);
+ retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status);
if (retval != ERROR_OK) {
- LOG_INFO("stm32x_write_options: wait_flash_op_queue : error");
- return retval;
+ LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR");
+ goto flash_options_lock;
}
- if ((status & FLASH_QW) == 0)
+ if ((status & OPT_BSY) == 0)
break;
if (timeout-- <= 0) {
- LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status);
- return ERROR_FAIL;
+ LOG_ERROR("waiting for OBL launch, time out expired, OPTSR: 0x%" PRIx32 "", status);
+ retval = ERROR_FAIL;
+ goto flash_options_lock;
}
alive_sleep(1);
}
- /* relock option registers */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK);
+ /* check for failure */
+ if (status & OPT_OPTCHANGEERR) {
+ LOG_ERROR("error changing option bytes (OPTCHANGEERR=1)");
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ }
+
+flash_options_lock:
+ retval2 = stm32x_lock_option_reg(bank);
+ if (retval2 != ERROR_OK)
+ LOG_ERROR("error during the lock of flash options");
+
+ return (retval == ERROR_OK) ? retval2 : retval;
+}
+
+static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask)
+{
+ uint32_t data;
+
+ int retval = stm32x_read_flash_reg(bank, reg_offset, &data);
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ data = (data & ~mask) | (value & mask);
+
+ return stm32x_write_option(bank, reg_offset, data);
}
static int stm32x_protect_check(struct flash_bank *bank)
{
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ uint32_t protection;
/* read 'write protection' settings */
- int retval = stm32x_read_options(bank);
+ int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection);
if (retval != ERROR_OK) {
- LOG_DEBUG("unable to read option bytes");
+ LOG_DEBUG("unable to read WPSN_CUR register");
return retval;
}
- for (int i = 0; i < bank->num_sectors; i++) {
- if (stm32x_info->flash_base == FLASH_REG_BASE_B0) {
- if (stm32x_info->option_bytes.protection & (1 << i))
- bank->sectors[i].is_protected = 0;
- else
- bank->sectors[i].is_protected = 1;
- } else {
- if (stm32x_info->option_bytes.protection2 & (1 << i))
- bank->sectors[i].is_protected = 0;
- else
- bank->sectors[i].is_protected = 1;
- }
- }
+ for (int i = 0; i < bank->num_prot_blocks; i++)
+ bank->prot_blocks[i].is_protected = protection & (1 << i) ? 0 : 1;
+
return ERROR_OK;
}
static int stm32x_erase(struct flash_bank *bank, int first, int last)
{
- struct target *target = bank->target;
- int retval;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ int retval, retval2;
assert(first < bank->num_sectors);
assert(last < bank->num_sectors);
@@ -454,7 +460,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
retval = stm32x_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
/*
Sector Erase
@@ -468,92 +474,84 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
*/
for (int i = first; i <= last; i++) {
LOG_DEBUG("erase sector %d", i);
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR),
- FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i));
if (retval != ERROR_OK) {
LOG_ERROR("Error erase sector %d", i);
- return retval;
+ goto flash_lock;
}
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR),
- FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i));
if (retval != ERROR_OK) {
LOG_ERROR("Error erase sector %d", i);
- return retval;
+ goto flash_lock;
}
retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK) {
LOG_ERROR("erase time-out or operation error sector %d", i);
- return retval;
+ goto flash_lock;
}
bank->sectors[i].is_erased = 1;
}
- retval = stm32x_lock_reg(bank);
- if (retval != ERROR_OK) {
+flash_lock:
+ retval2 = stm32x_lock_reg(bank);
+ if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
- return retval;
- }
- return ERROR_OK;
+ return (retval == ERROR_OK) ? retval2 : retval;
}
static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ uint32_t protection;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- /* read protection settings */
- int retval = stm32x_read_options(bank);
+
+ /* read 'write protection' settings */
+ int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection);
if (retval != ERROR_OK) {
- LOG_DEBUG("unable to read option bytes");
+ LOG_DEBUG("unable to read WPSN_CUR register");
return retval;
}
for (int i = first; i <= last; i++) {
- if (stm32x_info->flash_base == FLASH_REG_BASE_B0) {
- if (set)
- stm32x_info->option_bytes.protection &= ~(1 << i);
- else
- stm32x_info->option_bytes.protection |= (1 << i);
- } else {
- if (set)
- stm32x_info->option_bytes.protection2 &= ~(1 << i);
- else
- stm32x_info->option_bytes.protection2 |= (1 << i);
- }
+ if (set)
+ protection &= ~(1 << i);
+ else
+ protection |= (1 << i);
}
- LOG_INFO("stm32x_protect, option_bytes written WRP1 0x%x , WRP2 0x%x",
- (stm32x_info->option_bytes.protection & 0xff), (stm32x_info->option_bytes.protection2 & 0xff));
+ /* apply WRPSN mask */
+ protection &= 0xff;
- retval = stm32x_write_options(bank);
- if (retval != ERROR_OK)
- return retval;
+ LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection);
- return ERROR_OK;
+ /* apply new option value */
+ return stm32x_write_option(bank, FLASH_WPSN_PRG, protection);
}
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
/*
- * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get
+ * If the size of the data part of the buffer is not a multiple of .block_size, we get
* "corrupted fifo read" pointer in target_run_flash_async_algorithm()
*/
- uint32_t data_size = 512 * FLASH_BLOCK_SIZE; /* 16384 */
+ uint32_t data_size = 512 * stm32x_info->part_info->block_size;
uint32_t buffer_size = 8 + data_size;
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
- struct reg_param reg_params[5];
+ struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
int retval = ERROR_OK;
static const uint8_t stm32x_flash_write_code[] = {
@@ -588,7 +586,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
}
}
- LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size);
+ LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%" PRIx32, buffer_size);
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
@@ -596,27 +594,29 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer end */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* target address */
- init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* count (word-256 bits) */
- init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* flash reg base */
+ init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* count of words (word size = .block_size (bytes) */
+ init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* word size in bytes */
+ init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* flash reg base */
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[2].value, 0, 32, address);
buf_set_u32(reg_params[3].value, 0, 32, count);
- buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->flash_base);
+ buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->part_info->block_size);
+ buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base);
retval = target_run_flash_async_algorithm(target,
buffer,
count,
- FLASH_BLOCK_SIZE,
+ stm32x_info->part_info->block_size,
0, NULL,
- 5, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
if (retval == ERROR_FLASH_OPERATION_FAILED) {
- LOG_INFO("error executing stm32h7x flash write algorithm");
+ LOG_ERROR("error executing stm32h7x flash write algorithm");
uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32);
@@ -626,7 +626,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
if ((flash_sr & FLASH_ERROR) != 0) {
LOG_ERROR("flash write failed, FLASH_SR = %08" PRIx32, flash_sr);
/* Clear error + EOP flags but report errors */
- target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), flash_sr);
+ stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr);
retval = ERROR_FAIL;
}
}
@@ -639,6 +639,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
destroy_reg_param(&reg_params[4]);
+ destroy_reg_param(&reg_params[5]);
return retval;
}
@@ -646,6 +647,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
uint32_t address = bank->base + offset;
int retval, retval2;
@@ -654,19 +656,19 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_TARGET_NOT_HALTED;
}
- if (offset % FLASH_BLOCK_SIZE) {
- LOG_WARNING("offset 0x%" PRIx32 " breaks required 32-byte alignment", offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
+ /* should be enforced via bank->write_start_alignment */
+ assert(!(offset % stm32x_info->part_info->block_size));
+
+ /* should be enforced via bank->write_end_alignment */
+ assert(!(count % stm32x_info->part_info->block_size));
retval = stm32x_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
- uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE;
- uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE;
+ uint32_t blocks_remaining = count / stm32x_info->part_info->block_size;
- /* multiple words (32-bytes) to be programmed in block */
+ /* multiple words (n * .block_size) to be programmed in block */
if (blocks_remaining) {
retval = stm32x_write_block(bank, buffer, offset, blocks_remaining);
if (retval != ERROR_OK) {
@@ -676,8 +678,8 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
}
} else {
- buffer += blocks_remaining * FLASH_BLOCK_SIZE;
- address += blocks_remaining * FLASH_BLOCK_SIZE;
+ buffer += blocks_remaining * stm32x_info->part_info->block_size;
+ address += blocks_remaining * stm32x_info->part_info->block_size;
blocks_remaining = 0;
}
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
@@ -694,11 +696,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
4. Wait for flash operations completion
*/
while (blocks_remaining > 0) {
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0));
if (retval != ERROR_OK)
goto flash_lock;
- retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer);
+ retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer);
if (retval != ERROR_OK)
goto flash_lock;
@@ -706,49 +709,17 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
goto flash_lock;
- buffer += FLASH_BLOCK_SIZE;
- address += FLASH_BLOCK_SIZE;
+ buffer += stm32x_info->part_info->block_size;
+ address += stm32x_info->part_info->block_size;
blocks_remaining--;
}
- if (bytes_remaining) {
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64);
- if (retval != ERROR_OK)
- goto flash_lock;
-
- retval = target_write_buffer(target, address, bytes_remaining, buffer);
- if (retval != ERROR_OK)
- goto flash_lock;
-
- /* Force Write buffer of FLASH_BLOCK_SIZE = 32 bytes */
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64 | FLASH_FW);
- if (retval != ERROR_OK)
- goto flash_lock;
-
- retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT);
- if (retval != ERROR_OK)
- goto flash_lock;
- }
-
flash_lock:
retval2 = stm32x_lock_reg(bank);
if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
- if (retval == ERROR_OK)
- retval = retval2;
-
- return retval;
-}
-
-static void setup_sector(struct flash_bank *bank, int start, int num, int size)
-{
- for (int i = start; i < (start + num) ; i++) {
- assert(i < bank->num_sectors);
- bank->sectors[i].offset = bank->size;
- bank->sectors[i].size = size;
- bank->size += bank->sectors[i].size;
- }
+ return (retval == ERROR_OK) ? retval2 : retval;
}
static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id)
@@ -764,13 +735,10 @@ static int stm32x_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
- int i;
uint16_t flash_size_in_kb;
uint32_t device_id;
- uint32_t base_address = FLASH_BANK0_ADDRESS;
- uint32_t second_bank_base;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->part_info = NULL;
int retval = stm32x_read_id_code(bank, &stm32x_info->idcode);
@@ -792,44 +760,77 @@ static int stm32x_probe(struct flash_bank *bank)
LOG_INFO("Device: %s", stm32x_info->part_info->device_str);
}
- /* update the address of controller from data base */
- stm32x_info->flash_base = stm32x_info->part_info->flash_base;
+ /* update the address of controller */
+ if (bank->base == FLASH_BANK0_ADDRESS)
+ stm32x_info->flash_regs_base = FLASH_REG_BASE_B0;
+ else if (bank->base == FLASH_BANK1_ADDRESS)
+ stm32x_info->flash_regs_base = FLASH_REG_BASE_B1;
+ else {
+ LOG_WARNING("Flash register base not defined for bank %d", bank->bank_number);
+ return ERROR_FAIL;
+ }
+ LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base);
/* get flash size from target */
- retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb);
+ retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb);
if (retval != ERROR_OK) {
/* read error when device has invalid value, set max flash size */
flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb;
} else
LOG_INFO("flash size probed value %d", flash_size_in_kb);
- /* Lower flash size devices are single bank */
- if (stm32x_info->part_info->has_dual_bank && (flash_size_in_kb > stm32x_info->part_info->first_bank_size_kb)) {
- /* Use the configured base address to determine if this is the first or second flash bank.
- * Verify that the base address is reasonably correct and determine the flash bank size
+
+
+
+ /* setup bank size */
+ const uint32_t bank1_base = FLASH_BANK0_ADDRESS;
+ const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024;
+ bool has_dual_bank = stm32x_info->part_info->has_dual_bank;
+
+ switch (device_id) {
+ case 0x450:
+ case 0x480:
+ /* For STM32H74x/75x and STM32H7Ax/Bx
+ * - STM32H7xxxI devices contains dual bank, 1 Mbyte each
+ * - STM32H7xxxG devices contains dual bank, 512 Kbyte each
+ * - STM32H7xxxB devices contains single bank, 128 Kbyte
+ * - the second bank starts always from 0x08100000
*/
- second_bank_base = base_address + stm32x_info->part_info->first_bank_size_kb * 1024;
- if (bank->base == second_bank_base) {
- /* This is the second bank */
- base_address = second_bank_base;
- flash_size_in_kb = flash_size_in_kb - stm32x_info->part_info->first_bank_size_kb;
- /* bank1 also uses a register offset */
- stm32x_info->flash_base = FLASH_REG_BASE_B1;
- } else if (bank->base == base_address) {
- /* This is the first bank */
- flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb;
- } else {
- LOG_WARNING("STM32H flash bank base address config is incorrect. "
- TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
- bank->base, base_address, second_bank_base);
+ if (flash_size_in_kb == 128)
+ has_dual_bank = false;
+ else
+ /* flash size is 2M or 1M */
+ flash_size_in_kb /= 2;
+ break;
+ default:
+ LOG_ERROR("unsupported device");
+ return ERROR_FAIL;
+ }
+
+ if (has_dual_bank) {
+ LOG_INFO("STM32H7 flash has dual banks");
+ if (bank->base != bank1_base && bank->base != bank2_base) {
+ LOG_ERROR("STM32H7 flash bank base address config is incorrect. "
+ TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
+ bank->base, bank1_base, bank2_base);
return ERROR_FAIL;
}
- LOG_INFO("STM32H flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32,
- bank->bank_number, flash_size_in_kb, base_address);
} else {
- LOG_INFO("STM32H flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address);
+ LOG_INFO("STM32H7 flash has a single bank");
+ if (bank->base == bank2_base) {
+ LOG_ERROR("this device has a single bank only");
+ return ERROR_FAIL;
+ } else if (bank->base != bank1_base) {
+ LOG_ERROR("STM32H7 flash bank base address config is incorrect. "
+ TARGET_ADDR_FMT " but should be 0x%" PRIx32,
+ bank->base, bank1_base);
+ return ERROR_FAIL;
+ }
}
+ LOG_INFO("Bank (%d) size is %d kb, base address is 0x%" PRIx32,
+ bank->bank_number, flash_size_in_kb, (uint32_t) bank->base);
+
/* if the user sets the size manually then ignore the probed value
* this allows us to work around devices that have an invalid flash size register value */
if (stm32x_info->user_bank_size) {
@@ -842,33 +843,41 @@ static int stm32x_probe(struct flash_bank *bank)
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
+ bank->size = flash_size_in_kb * 1024;
+ bank->write_start_alignment = stm32x_info->part_info->block_size;
+ bank->write_end_alignment = stm32x_info->part_info->block_size;
- /* calculate numbers of pages */
- int num_pages = flash_size_in_kb / stm32x_info->part_info->page_size;
-
- /* check that calculation result makes sense */
- assert(num_pages > 0);
+ /* setup sectors */
+ bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb;
+ assert(bank->num_sectors > 0);
- if (bank->sectors) {
+ if (bank->sectors)
free(bank->sectors);
- bank->sectors = NULL;
- }
- bank->base = base_address;
- bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+ bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024,
+ bank->num_sectors);
+
if (bank->sectors == NULL) {
LOG_ERROR("failed to allocate bank sectors");
return ERROR_FAIL;
}
- bank->size = 0;
- /* fixed memory */
- setup_sector(bank, 0, num_pages, stm32x_info->part_info->page_size * 1024);
+ /* setup protection blocks */
+ const uint32_t wpsn = stm32x_info->part_info->wps_group_size;
+ assert(bank->num_sectors % wpsn == 0);
- for (i = 0; i < num_pages; i++) {
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 0;
+ bank->num_prot_blocks = bank->num_sectors / wpsn;
+ assert(bank->num_prot_blocks > 0);
+
+ if (bank->prot_blocks)
+ free(bank->prot_blocks);
+
+ bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024,
+ bank->num_prot_blocks);
+
+ if (bank->prot_blocks == NULL) {
+ LOG_ERROR("failed to allocate bank prot_block");
+ return ERROR_FAIL;
}
stm32x_info->probed = 1;
@@ -922,57 +931,52 @@ static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
-COMMAND_HANDLER(stm32x_handle_lock_command)
+static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp)
{
- struct target *target = NULL;
- struct stm32h7x_flash_bank *stm32x_info = NULL;
-
- if (CMD_ARGC < 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- struct flash_bank *bank;
- int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
- if (ERROR_OK != retval)
- return retval;
-
- stm32x_info = bank->driver_priv;
- target = bank->target;
-
- /* if we have a dual flash bank device then
- * we need to perform option byte lock on bank0 only */
- if (stm32x_info->flash_base != FLASH_REG_BASE_B0) {
- LOG_ERROR("Option Byte Lock Operation must use bank0");
- return ERROR_FLASH_OPERATION_FAILED;
- }
+ struct target *target = bank->target;
+ uint32_t optsr, cur_rdp;
+ int retval;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (stm32x_read_options(bank) != ERROR_OK) {
- command_print(CMD, "%s failed to read options",
- bank->driver->name);
- return ERROR_OK;
+ retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr);
+
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("unable to read FLASH_OPTSR_PRG register");
+ return retval;
}
- /* set readout protection */
- stm32x_info->option_bytes.RDP = 0;
- if (stm32x_write_options(bank) != ERROR_OK) {
- command_print(CMD, "%s failed to lock device",
- bank->driver->name);
+ /* get current RDP, and check if there is a change */
+ cur_rdp = (optsr & OPT_RDP_MASK) >> OPT_RDP_POS;
+ if (new_rdp == cur_rdp) {
+ LOG_INFO("the requested RDP value is already programmed");
return ERROR_OK;
}
- command_print(CMD, "%s locked", bank->driver->name);
- return ERROR_OK;
+ switch (new_rdp) {
+ case OPT_RDP_L0:
+ LOG_WARNING("unlocking the entire flash device");
+ break;
+ case OPT_RDP_L1:
+ LOG_WARNING("locking the entire flash device");
+ break;
+ case OPT_RDP_L2:
+ LOG_WARNING("locking the entire flash device, irreversible");
+ break;
+ }
+
+ /* apply new RDP */
+ optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS);
+
+ /* apply new option value */
+ return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr);
}
-COMMAND_HANDLER(stm32x_handle_unlock_command)
+COMMAND_HANDLER(stm32x_handle_lock_command)
{
- struct target *target = NULL;
- struct stm32h7x_flash_bank *stm32x_info = NULL;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -981,43 +985,41 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
if (ERROR_OK != retval)
return retval;
- stm32x_info = bank->driver_priv;
- target = bank->target;
+ retval = stm32x_set_rdp(bank, OPT_RDP_L1);
- /* if we have a dual flash bank device then
- * we need to perform option byte unlock on bank0 only */
- if (stm32x_info->flash_base != FLASH_REG_BASE_B0) {
- LOG_ERROR("Option Byte Unlock Operation must use bank0");
- return ERROR_FLASH_OPERATION_FAILED;
- }
+ if (retval != ERROR_OK)
+ command_print(CMD, "%s failed to lock device", bank->driver->name);
+ else
+ command_print(CMD, "%s locked", bank->driver->name);
- if (target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
+ return retval;
+}
- if (stm32x_read_options(bank) != ERROR_OK) {
- command_print(CMD, "%s failed to read options", bank->driver->name);
- return ERROR_OK;
- }
+COMMAND_HANDLER(stm32x_handle_unlock_command)
+{
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
- /* clear readout protection option byte
- * this will also force a device unlock if set */
- stm32x_info->option_bytes.RDP = 0xAA;
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
- if (stm32x_write_options(bank) != ERROR_OK) {
+ retval = stm32x_set_rdp(bank, OPT_RDP_L0);
+
+ if (retval != ERROR_OK)
command_print(CMD, "%s failed to unlock device", bank->driver->name);
- return ERROR_OK;
- }
- command_print(CMD, "%s unlocked.\n", bank->driver->name);
+ else
+ command_print(CMD, "%s unlocked", bank->driver->name);
- return ERROR_OK;
+ return retval;
}
static int stm32x_mass_erase(struct flash_bank *bank)
{
- int retval;
+ int retval, retval2;
struct target *target = bank->target;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -1026,34 +1028,33 @@ static int stm32x_mass_erase(struct flash_bank *bank)
retval = stm32x_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
/* mass erase flash memory bank */
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER | FLASH_PSIZE_64);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0));
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR),
- FLASH_BER | FLASH_PSIZE_64 | FLASH_START);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0));
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
retval = stm32x_wait_flash_op_queue(bank, 30000);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
- retval = stm32x_lock_reg(bank);
- if (retval != ERROR_OK) {
+flash_lock:
+ retval2 = stm32x_lock_reg(bank);
+ if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
- return retval;
- }
- return ERROR_OK;
+
+ return (retval == ERROR_OK) ? retval2 : retval;
}
COMMAND_HANDLER(stm32x_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1) {
command_print(CMD, "stm32h7x mass_erase <bank>");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1067,7 +1068,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
retval = stm32x_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32h7x mass erase complete");
@@ -1078,6 +1079,53 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
return retval;
}
+COMMAND_HANDLER(stm32x_handle_option_read_command)
+{
+ if (CMD_ARGC < 2) {
+ command_print(CMD, "stm32h7x option_read <bank> <option_reg offset>");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_offset, value;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+ retval = stm32x_read_flash_reg(bank, reg_offset, &value);
+ if (ERROR_OK != retval)
+ return retval;
+
+ command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "",
+ stm32x_get_flash_reg(bank, reg_offset), value);
+
+ return retval;
+}
+
+COMMAND_HANDLER(stm32x_handle_option_write_command)
+{
+ if (CMD_ARGC < 3) {
+ command_print(CMD, "stm32h7x option_write <bank> <option_reg offset> <value> [mask]");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_offset, value, mask = 0xffffffff;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
+ if (CMD_ARGC > 3)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask);
+
+ return stm32x_modify_option(bank, reg_offset, value, mask);
+}
+
static const struct command_registration stm32x_exec_command_handlers[] = {
{
.name = "lock",
@@ -1100,6 +1148,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.usage = "bank_id",
.help = "Erase entire flash device.",
},
+ {
+ .name = "option_read",
+ .handler = stm32x_handle_option_read_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id reg_offset",
+ .help = "Read and display device option bytes.",
+ },
+ {
+ .name = "option_write",
+ .handler = stm32x_handle_option_write_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id reg_offset value [mask]",
+ .help = "Write device option bit fields with provided value.",
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index f680542..94fcd32 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -1,7 +1,10 @@
/***************************************************************************
* Copyright (C) 2015 by Uwe Bonnes *
* bon@elektron.ikp.physik.tu-darmstadt.de *
- *
+ * *
+ * Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics *
+ * tarek.bouchkati@gmail.com *
+ * *
* 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 2 of the License, or *
@@ -24,6 +27,8 @@
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
+#include "bits.h"
+#include "stm32l4x.h"
/* STM32L4xxx series for reference.
*
@@ -47,91 +52,294 @@
* RM0394 devices have a single bank only.
*
* RM0432 devices have single and dual bank operating modes.
- * The FLASH size is 1Mbyte or 2Mbyte.
+ * - for STM32L4R/Sxx the FLASH size is 2Mbyte or 1Mbyte.
+ * - for STM32L4P/Q5x the FLASH size is 1Mbyte or 512Kbyte.
* Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode).
*
* Bank mode is controlled by two different bits in option bytes register.
- * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
- * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ * - for STM32L4R/Sxx
+ * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
+ * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ * - for STM32L4P5/Q5x
+ * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
+ * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode.
+ *
+ */
+
+/* STM32WBxxx series for reference.
+ *
+ * RM0434 (STM32WB55)
+ * http://www.st.com/resource/en/reference_manual/dm00318631.pdf
+ *
+ * RM0471 (STM32WB50)
+ * http://www.st.com/resource/en/reference_manual/dm00622834.pdf
+ */
+
+/* STM32WLxxx series for reference.
+ *
+ * RM0461 (STM32WLEx)
+ * http://www.st.com/resource/en/reference_manual/dm00530369.pdf
+ */
+
+/*
+ * STM32G0xxx series for reference.
+ *
+ * RM0444 (STM32G0x1)
+ * http://www.st.com/resource/en/reference_manual/dm00371828.pdf
+ *
+ * RM0454 (STM32G0x0)
+ * http://www.st.com/resource/en/reference_manual/dm00463896.pdf
+ */
+
+/*
+ * STM32G4xxx series for reference.
+ *
+ * RM0440 (STM32G43x/44x/47x/48x)
+ * http://www.st.com/resource/en/reference_manual/dm00355726.pdf
+ *
+ * Cat. 2 devices have single bank only, page size is 2kByte.
+ *
+ * Cat. 3 devices have single and dual bank operating modes,
+ * Page size is 2kByte (dual mode) or 4kByte (single mode).
*
+ * Bank mode is controlled by bit 22 (DBANK) in option bytes register.
+ * Both banks are treated as a single OpenOCD bank.
*/
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
#define FLASH_ERASE_TIMEOUT 250
-#define STM32_FLASH_BASE 0x40022000
-#define STM32_FLASH_ACR 0x40022000
-#define STM32_FLASH_KEYR 0x40022008
-#define STM32_FLASH_OPTKEYR 0x4002200c
-#define STM32_FLASH_SR 0x40022010
-#define STM32_FLASH_CR 0x40022014
-#define STM32_FLASH_OPTR 0x40022020
-#define STM32_FLASH_WRP1AR 0x4002202c
-#define STM32_FLASH_WRP1BR 0x40022030
-#define STM32_FLASH_WRP2AR 0x4002204c
-#define STM32_FLASH_WRP2BR 0x40022050
-
-/* FLASH_CR register bits */
-
-#define FLASH_PG (1 << 0)
-#define FLASH_PER (1 << 1)
-#define FLASH_MER1 (1 << 2)
-#define FLASH_PAGE_SHIFT 3
-#define FLASH_CR_BKER (1 << 11)
-#define FLASH_MER2 (1 << 15)
-#define FLASH_STRT (1 << 16)
-#define FLASH_OPTSTRT (1 << 17)
-#define FLASH_EOPIE (1 << 24)
-#define FLASH_ERRIE (1 << 25)
-#define FLASH_OBLLAUNCH (1 << 27)
-#define FLASH_OPTLOCK (1 << 30)
-#define FLASH_LOCK (1 << 31)
-
-/* FLASH_SR register bits */
-
-#define FLASH_BSY (1 << 16)
-/* Fast programming not used => related errors not used*/
-#define FLASH_PGSERR (1 << 7) /* Programming sequence error */
-#define FLASH_SIZERR (1 << 6) /* Size error */
-#define FLASH_PGAERR (1 << 5) /* Programming alignment error */
-#define FLASH_WRPERR (1 << 4) /* Write protection error */
-#define FLASH_PROGERR (1 << 3) /* Programming error */
-#define FLASH_OPERR (1 << 1) /* Operation error */
-#define FLASH_EOP (1 << 0) /* End of operation */
-
-#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGSERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR)
-
-/* STM32_FLASH_OBR bit definitions (reading) */
-
-#define OPT_DBANK_LE_1M (1 << 21) /* dual bank for devices up to 1M flash */
-#define OPT_DBANK_GE_2M (1 << 22) /* dual bank for devices with 2M flash */
-
-/* register unlock keys */
-
-#define KEY1 0x45670123
-#define KEY2 0xCDEF89AB
-
-/* option register unlock key */
-#define OPTKEY1 0x08192A3B
-#define OPTKEY2 0x4C5D6E7F
-
-#define RDP_LEVEL_0 0xAA
-#define RDP_LEVEL_1 0xBB
-#define RDP_LEVEL_2 0xCC
-
-
-/* other registers */
-#define DBGMCU_IDCODE 0xE0042000
-#define FLASH_SIZE_REG 0x1FFF75E0
+struct stm32l4_rev {
+ const uint16_t rev;
+ const char *str;
+};
+
+struct stm32l4_part_info {
+ uint16_t id;
+ const char *device_str;
+ const struct stm32l4_rev *revs;
+ const size_t num_revs;
+ const uint16_t max_flash_size_kb;
+ const bool has_dual_bank;
+ const uint32_t flash_regs_base;
+ const uint32_t fsize_addr;
+};
struct stm32l4_flash_bank {
- uint16_t bank2_start;
- int probed;
+ bool probed;
+ uint32_t idcode;
+ int bank1_sectors;
+ bool dual_bank_mode;
+ int hole_sectors;
+ uint32_t user_bank_size;
+ uint32_t wrpxxr_mask;
+ const struct stm32l4_part_info *part_info;
};
-/* flash bank stm32l4x <base> <size> 0 0 <target#>
- */
+/* human readable list of families this drivers supports */
+static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0";
+
+static const struct stm32l4_rev stm32_415_revs[] = {
+ { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
+};
+
+static const struct stm32l4_rev stm32_435_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
+};
+
+static const struct stm32l4_rev stm32_460_revs[] = {
+ { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_461_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_462_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
+};
+
+static const struct stm32l4_rev stm32_464_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
+};
+
+static const struct stm32l4_rev stm32_466_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_468_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
+};
+
+static const struct stm32l4_rev stm32_469_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
+};
+
+static const struct stm32l4_rev stm32_470_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" },
+};
+
+static const struct stm32l4_rev stm32_471_revs[] = {
+ { 0x1001, "Z" },
+};
+
+static const struct stm32l4_rev stm32_495_revs[] = {
+ { 0x2001, "2.1" },
+};
+
+static const struct stm32l4_rev stm32_496_revs[] = {
+ { 0x1000, "A" },
+};
+
+static const struct stm32l4_rev stm32_497_revs[] = {
+ { 0x1000, "1.0" },
+};
+
+static const struct stm32l4_part_info stm32l4_parts[] = {
+ {
+ .id = 0x415,
+ .revs = stm32_415_revs,
+ .num_revs = ARRAY_SIZE(stm32_415_revs),
+ .device_str = "STM32L47/L48xx",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x435,
+ .revs = stm32_435_revs,
+ .num_revs = ARRAY_SIZE(stm32_435_revs),
+ .device_str = "STM32L43/L44xx",
+ .max_flash_size_kb = 256,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x460,
+ .revs = stm32_460_revs,
+ .num_revs = ARRAY_SIZE(stm32_460_revs),
+ .device_str = "STM32G07/G08xx",
+ .max_flash_size_kb = 128,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x461,
+ .revs = stm32_461_revs,
+ .num_revs = ARRAY_SIZE(stm32_461_revs),
+ .device_str = "STM32L49/L4Axx",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x462,
+ .revs = stm32_462_revs,
+ .num_revs = ARRAY_SIZE(stm32_462_revs),
+ .device_str = "STM32L45/L46xx",
+ .max_flash_size_kb = 512,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x464,
+ .revs = stm32_464_revs,
+ .num_revs = ARRAY_SIZE(stm32_464_revs),
+ .device_str = "STM32L41/L42xx",
+ .max_flash_size_kb = 128,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x466,
+ .revs = stm32_466_revs,
+ .num_revs = ARRAY_SIZE(stm32_466_revs),
+ .device_str = "STM32G03/G04xx",
+ .max_flash_size_kb = 64,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x468,
+ .revs = stm32_468_revs,
+ .num_revs = ARRAY_SIZE(stm32_468_revs),
+ .device_str = "STM32G43/G44xx",
+ .max_flash_size_kb = 128,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x469,
+ .revs = stm32_469_revs,
+ .num_revs = ARRAY_SIZE(stm32_469_revs),
+ .device_str = "STM32G47/G48xx",
+ .max_flash_size_kb = 512,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x470,
+ .revs = stm32_470_revs,
+ .num_revs = ARRAY_SIZE(stm32_470_revs),
+ .device_str = "STM32L4R/L4Sxx",
+ .max_flash_size_kb = 2048,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x471,
+ .revs = stm32_471_revs,
+ .num_revs = ARRAY_SIZE(stm32_471_revs),
+ .device_str = "STM32L4P5/L4Q5x",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x495,
+ .revs = stm32_495_revs,
+ .num_revs = ARRAY_SIZE(stm32_495_revs),
+ .device_str = "STM32WB5x",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x58004000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x496,
+ .revs = stm32_496_revs,
+ .num_revs = ARRAY_SIZE(stm32_496_revs),
+ .device_str = "STM32WB3x",
+ .max_flash_size_kb = 512,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x58004000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x497,
+ .revs = stm32_497_revs,
+ .num_revs = ARRAY_SIZE(stm32_497_revs),
+ .device_str = "STM32WLEx",
+ .max_flash_size_kb = 256,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x58004000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+};
+
+/* flash bank stm32l4x <base> <size> 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
{
struct stm32l4_flash_bank *stm32l4_info;
@@ -144,32 +352,40 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
return ERROR_FAIL; /* Checkme: What better error to use?*/
bank->driver_priv = stm32l4_info;
- stm32l4_info->probed = 0;
+ /* The flash write must be aligned to a double word (8-bytes) boundary.
+ * Ask the flash infrastructure to ensure required alignment */
+ bank->write_start_alignment = bank->write_end_alignment = 8;
+
+ stm32l4_info->probed = false;
+ stm32l4_info->user_bank_size = bank->size;
return ERROR_OK;
}
-static inline int stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
{
- return reg;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ return stm32l4_info->part_info->flash_regs_base + reg_offset;
}
-static inline int stm32l4_get_flash_status(struct flash_bank *bank, uint32_t *status)
+static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
{
- struct target *target = bank->target;
- return target_read_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR), status);
+ return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value);
+}
+
+static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value);
}
static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
{
- struct target *target = bank->target;
uint32_t status;
int retval = ERROR_OK;
/* wait for busy to clear */
for (;;) {
- retval = stm32l4_get_flash_status(bank, &status);
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%" PRIx32 "", status);
@@ -195,20 +411,20 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* If this operation fails, we ignore it and report the original
* retval
*/
- target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR),
- status & FLASH_ERROR);
+ stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR);
}
+
return retval;
}
-static int stm32l4_unlock_reg(struct target *target)
+static int stm32l4_unlock_reg(struct flash_bank *bank)
{
uint32_t ctrl;
/* first check if not already unlocked
* otherwise writing on STM32_FLASH_KEYR will fail
*/
- int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -216,15 +432,15 @@ static int stm32l4_unlock_reg(struct target *target)
return ERROR_OK;
/* unlock flash registers */
- retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -236,11 +452,11 @@ static int stm32l4_unlock_reg(struct target *target)
return ERROR_OK;
}
-static int stm32l4_unlock_option_reg(struct target *target)
+static int stm32l4_unlock_option_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -248,15 +464,15 @@ static int stm32l4_unlock_option_reg(struct target *target)
return ERROR_OK;
/* unlock option registers */
- retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -268,66 +484,72 @@ static int stm32l4_unlock_option_reg(struct target *target)
return ERROR_OK;
}
-static int stm32l4_read_option(struct flash_bank *bank, uint32_t address, uint32_t* value)
-{
- struct target *target = bank->target;
- return target_read_u32(target, address, value);
-}
-
-static int stm32l4_write_option(struct flash_bank *bank, uint32_t address, uint32_t value, uint32_t mask)
+static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
+ uint32_t value, uint32_t mask)
{
- struct target *target = bank->target;
uint32_t optiondata;
+ int retval, retval2;
- int retval = target_read_u32(target, address, &optiondata);
+ retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata);
if (retval != ERROR_OK)
return retval;
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
- retval = stm32l4_unlock_option_reg(target);
+ retval = stm32l4_unlock_option_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
optiondata = (optiondata & ~mask) | (value & mask);
- retval = target_write_u32(target, address, optiondata);
+ retval = stm32l4_write_flash_reg(bank, reg_offset, optiondata);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
- retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OPTSTRT);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK);
+
if (retval != ERROR_OK)
return retval;
- return retval;
+ return retval2;
}
static int stm32l4_protect_check(struct flash_bank *bank)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
- stm32l4_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar);
- stm32l4_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br);
- stm32l4_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar);
- stm32l4_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br);
-
- const uint8_t wrp1a_start = wrp1ar & 0xFF;
- const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF;
- const uint8_t wrp1b_start = wrp1br & 0xFF;
- const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF;
- const uint8_t wrp2a_start = wrp2ar & 0xFF;
- const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF;
- const uint8_t wrp2b_start = wrp2br & 0xFF;
- const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF;
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar);
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br);
+ if (stm32l4_info->part_info->has_dual_bank) {
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar);
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br);
+ } else {
+ /* prevent unintialized errors */
+ wrp2ar = 0;
+ wrp2br = 0;
+ }
+
+ const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask;
for (int i = 0; i < bank->num_sectors; i++) {
- if (i < stm32l4_info->bank2_start) {
+ if (i < stm32l4_info->bank1_sectors) {
if (((i >= wrp1a_start) &&
(i <= wrp1a_end)) ||
((i >= wrp1b_start) &&
@@ -336,8 +558,9 @@ static int stm32l4_protect_check(struct flash_bank *bank)
else
bank->sectors[i].is_protected = 0;
} else {
+ assert(stm32l4_info->part_info->has_dual_bank == true);
uint8_t snb;
- snb = i - stm32l4_info->bank2_start;
+ snb = i - stm32l4_info->bank1_sectors;
if (((snb >= wrp2a_start) &&
(snb <= wrp2a_end)) ||
((snb >= wrp2b_start) &&
@@ -352,62 +575,60 @@ static int stm32l4_protect_check(struct flash_bank *bank)
static int stm32l4_erase(struct flash_bank *bank, int first, int last)
{
- struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
int i;
+ int retval, retval2;
- assert(first < bank->num_sectors);
- assert(last < bank->num_sectors);
+ assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- int retval;
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
/*
Sector Erase
To erase a sector, follow the procedure below:
1. Check that no Flash memory operation is ongoing by
- checking the BSY bit in the FLASH_SR register
+ checking the BSY bit in the FLASH_SR register
2. Set the PER bit and select the page and bank
you wish to erase in the FLASH_CR register
3. Set the STRT bit in the FLASH_CR register
4. Wait for the BSY bit to be cleared
*/
- struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
for (i = first; i <= last; i++) {
uint32_t erase_flags;
erase_flags = FLASH_PER | FLASH_STRT;
- if (i >= stm32l4_info->bank2_start) {
+ if (i >= stm32l4_info->bank1_sectors) {
uint8_t snb;
- snb = i - stm32l4_info->bank2_start;
+ snb = i - stm32l4_info->bank1_sectors;
erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
} else
erase_flags |= i << FLASH_PAGE_SHIFT;
- retval = target_write_u32(target,
- stm32l4_get_flash_reg(bank, STM32_FLASH_CR), erase_flags);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags);
if (retval != ERROR_OK)
- return retval;
+ break;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK)
- return retval;
+ break;
bank->sectors[i].is_erased = 1;
}
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ return retval2;
}
static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last)
@@ -423,9 +644,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
int ret = ERROR_OK;
/* Bank 2 */
uint32_t reg_value = 0xFF; /* Default to bank un-protected */
- if (last >= stm32l4_info->bank2_start) {
+ if (last >= stm32l4_info->bank1_sectors) {
if (set == 1) {
- uint8_t begin = first > stm32l4_info->bank2_start ? first : 0x00;
+ uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00;
reg_value = ((last & 0xFF) << 16) | begin;
}
@@ -433,9 +654,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
}
/* Bank 1 */
reg_value = 0xFF; /* Default to bank un-protected */
- if (first < stm32l4_info->bank2_start) {
+ if (first < stm32l4_info->bank1_sectors) {
if (set == 1) {
- uint8_t end = last >= stm32l4_info->bank2_start ? 0xFF : last;
+ uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last;
reg_value = (end << 16) | (first & 0xFF);
}
@@ -445,16 +666,16 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
return ret;
}
-/* Count is in halfwords */
+/* Count is in double-words */
static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+ uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- uint32_t buffer_size = 16384;
+ uint32_t buffer_size;
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
- struct reg_param reg_params[5];
+ struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
@@ -476,18 +697,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
return retval;
}
- /* memory buffer */
- while (target_alloc_working_area_try(target, buffer_size, &source) !=
- ERROR_OK) {
- buffer_size /= 2;
- if (buffer_size <= 256) {
- /* we already allocated the writing code, but failed to get a
- * buffer, free the algorithm */
- target_free_working_area(target, write_algorithm);
-
- LOG_WARNING("large enough working area not available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */
+ buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1);
+ if (buffer_size < 256) {
+ LOG_WARNING("large enough working area not available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ } else if (buffer_size > 16384) {
+ /* probably won't benefit from more than 16k ... */
+ buffer_size = 16384;
+ }
+
+ if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ LOG_ERROR("allocating working area failed");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
@@ -497,17 +719,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer end */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* target address */
init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* count (double word-64bit) */
- init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* flash base */
+ init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* flash status register */
+ init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* flash control register */
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[2].value, 0, 32, address);
- buf_set_u32(reg_params[3].value, 0, 32, count / 4);
- buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE);
+ buf_set_u32(reg_params[3].value, 0, 32, count);
+ buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR));
+ buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR));
- retval = target_run_flash_async_algorithm(target, buffer, count, 2,
+ retval = target_run_flash_async_algorithm(target, buffer, count, 8,
0, NULL,
- 5, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
@@ -523,7 +747,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
if (error != 0) {
LOG_ERROR("flash write failed = %08" PRIx32, error);
/* Clear but report errors */
- target_write_u32(target, STM32_FLASH_SR, error);
+ stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error);
retval = ERROR_FAIL;
}
}
@@ -536,195 +760,311 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
destroy_reg_param(&reg_params[4]);
+ destroy_reg_param(&reg_params[5]);
return retval;
}
static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+ uint32_t offset, uint32_t count)
{
- struct target *target = bank->target;
- int retval;
+ int retval = ERROR_OK, retval2;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (offset & 0x7) {
- LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment",
- offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ /* The flash write must be aligned to a double word (8-bytes) boundary.
+ * The flash infrastructure ensures it, do just a security check */
+ assert(offset % 8 == 0);
+ assert(count % 8 == 0);
+
+ /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether
+ * data to be written does not go into a gap:
+ * suppose buffer is fully contained in bank from sector 0 to sector
+ * num->sectors - 1 and sectors are ordered according to offset
+ */
+ struct flash_sector *head = &bank->sectors[0];
+ struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1];
+
+ while ((head < tail) && (offset >= (head + 1)->offset)) {
+ /* buffer does not intersect head nor gap behind head */
+ head++;
+ }
+
+ while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) {
+ /* buffer does not intersect tail nor gap before tail */
+ --tail;
}
- if (count & 0x7) {
- LOG_WARNING("Padding %d bytes to keep 8-byte write size",
- count & 7);
- count = (count + 7) & ~7;
- /* This pads the write chunk with random bytes by overrunning the
- * write buffer. Padding with the erased pattern 0xff is purely
- * cosmetical, as 8-byte flash words are ECC secured and the first
- * write will program the ECC bits. A second write would need
- * to reprogramm these ECC bits.
- * But this can only be done after erase!
- */
+ LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32,
+ offset, offset + count - 1, head->offset, tail->offset + tail->size - 1);
+
+ /* Now check that there is no gap from head to tail, this should work
+ * even for multiple or non-symmetric gaps
+ */
+ while (head < tail) {
+ if (head->offset + head->size != (head + 1)->offset) {
+ LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT,
+ bank->base + head->offset + head->size,
+ bank->base + (head + 1)->offset - 1);
+ retval = ERROR_FLASH_DST_OUT_OF_BANK;
+ }
+ head++;
}
- retval = stm32l4_unlock_reg(target);
if (retval != ERROR_OK)
return retval;
- /* Only full double words (8-byte) can be programmed*/
- retval = stm32l4_write_block(bank, buffer, offset, count / 2);
+ retval = stm32l4_unlock_reg(bank);
+ if (retval != ERROR_OK)
+ goto err_lock;
+
+ retval = stm32l4_write_block(bank, buffer, offset, count / 8);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
if (retval != ERROR_OK) {
- LOG_WARNING("block write failed");
+ LOG_ERROR("block write failed");
return retval;
+ }
+ return retval2;
+}
+
+static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
+{
+ int retval;
+
+ /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */
+ retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id);
+ if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) {
+ retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id);
+ if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) {
+ LOG_ERROR("can't get device id");
+ return (retval == ERROR_OK) ? ERROR_FAIL : retval;
}
+ }
- LOG_WARNING("block write succeeded");
- return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+ return retval;
}
static int stm32l4_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
- int i;
- uint16_t flash_size_in_kb = 0xffff;
- uint16_t max_flash_size_in_kb;
+ const struct stm32l4_part_info *part_info;
+ uint16_t flash_size_kb = 0xffff;
uint32_t device_id;
uint32_t options;
- uint32_t base_address = 0x08000000;
- stm32l4_info->probed = 0;
+ stm32l4_info->probed = false;
- /* read stm32 device id register */
- int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id);
+ /* read stm32 device id registers */
+ int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode);
if (retval != ERROR_OK)
return retval;
- LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
- /* set max flash size depending on family */
- switch (device_id & 0xfff) {
- case 0x470:
- max_flash_size_in_kb = 2048;
- break;
- case 0x461:
- case 0x415:
- max_flash_size_in_kb = 1024;
- break;
- case 0x462:
- max_flash_size_in_kb = 512;
- break;
- case 0x435:
- max_flash_size_in_kb = 256;
- break;
- default:
- LOG_WARNING("Cannot identify target as an STM32L4 family device.");
+ device_id = stm32l4_info->idcode & 0xFFF;
+
+ for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) {
+ if (device_id == stm32l4_parts[n].id)
+ stm32l4_info->part_info = &stm32l4_parts[n];
+ }
+
+ if (!stm32l4_info->part_info) {
+ LOG_WARNING("Cannot identify target as an %s family device.", device_families);
return ERROR_FAIL;
}
+ part_info = stm32l4_info->part_info;
+
+ char device_info[1024];
+ retval = bank->driver->info(bank, device_info, sizeof(device_info));
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info);
+
/* get flash size from target. */
- retval = target_read_u16(target, FLASH_SIZE_REG, &flash_size_in_kb);
+ retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb);
/* failed reading flash size or flash size invalid (early silicon),
* default to max target family */
- if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
+ if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0
+ || flash_size_kb > part_info->max_flash_size_kb) {
LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash",
- max_flash_size_in_kb);
- flash_size_in_kb = max_flash_size_in_kb;
+ part_info->max_flash_size_kb);
+ flash_size_kb = part_info->max_flash_size_kb;
+ }
+
+ /* if the user sets the size manually then ignore the probed value
+ * this allows us to work around devices that have a invalid flash size register value */
+ if (stm32l4_info->user_bank_size) {
+ LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE");
+ flash_size_kb = stm32l4_info->user_bank_size / 1024;
}
- LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
+ LOG_INFO("flash size = %dkbytes", flash_size_kb);
/* did we assign a flash size? */
- assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
-
- /* get options for DUAL BANK. */
- retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
+ assert((flash_size_kb != 0xffff) && flash_size_kb);
+ /* read flash option register */
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options);
if (retval != ERROR_OK)
return retval;
+ stm32l4_info->bank1_sectors = 0;
+ stm32l4_info->hole_sectors = 0;
+
int num_pages = 0;
- int page_size = 0;
-
- switch (device_id & 0xfff) {
- case 0x470:
- /* L4R/S have 1M or 2M FLASH and dual/single bank mode.
- * Page size is 4K or 8K.*/
- if (flash_size_in_kb == 2048) {
- stm32l4_info->bank2_start = 256;
- if (options & OPT_DBANK_GE_2M) {
- page_size = 4096;
- num_pages = 512;
- } else {
- page_size = 8192;
- num_pages = 256;
- }
- break;
- }
- if (flash_size_in_kb == 1024) {
- stm32l4_info->bank2_start = 128;
- if (options & OPT_DBANK_LE_1M) {
- page_size = 4096;
- num_pages = 256;
- } else {
- page_size = 8192;
- num_pages = 128;
- }
- break;
- }
- /* Invalid FLASH size for this device. */
- LOG_WARNING("Invalid flash size for STM32L4+ family device.");
- return ERROR_FAIL;
- case 0x461:
- case 0x415:
- /* These are dual-bank devices, we need to check the OPT_DBANK_LE_1M bit here */
- page_size = 2048;
- num_pages = flash_size_in_kb / 2;
- /* check that calculation result makes sense */
- assert(num_pages > 0);
- if ((flash_size_in_kb == 1024) || !(options & OPT_DBANK_LE_1M))
- stm32l4_info->bank2_start = 256;
- else
- stm32l4_info->bank2_start = num_pages / 2;
- break;
- case 0x462:
- case 0x435:
- default:
- /* These are single-bank devices */
- page_size = 2048;
- num_pages = flash_size_in_kb / 2;
- /* check that calculation result makes sense */
- assert(num_pages > 0);
- stm32l4_info->bank2_start = UINT16_MAX;
- break;
+ int page_size_kb = 0;
+
+ stm32l4_info->dual_bank_mode = false;
+
+ switch (device_id) {
+ case 0x415: /* STM32L47/L48xx */
+ case 0x461: /* STM32L49/L4Axx */
+ /* if flash size is max (1M) the device is always dual bank
+ * 0x415: has variants with 512K
+ * 0x461: has variants with 512 and 256
+ * for these variants:
+ * if DUAL_BANK = 0 -> single bank
+ * else -> dual bank without gap
+ * note: the page size is invariant
+ */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+
+ /* check DUAL_BANK bit[21] if the flash is less than 1M */
+ if (flash_size_kb == 1024 || (options & BIT(21))) {
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case 0x435: /* STM32L43/L44xx */
+ case 0x460: /* STM32G07/G08xx */
+ case 0x462: /* STM32L45/L46xx */
+ case 0x464: /* STM32L41/L42xx */
+ case 0x466: /* STM32G03/G04xx */
+ case 0x468: /* STM32G43/G44xx */
+ case 0x497: /* STM32WLEx */
+ /* single bank flash */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
+ case 0x469: /* STM32G47/G48xx */
+ /* STM32G47/8 can be single/dual bank:
+ * if DUAL_BANK = 0 -> single bank
+ * else -> dual bank WITH gap
+ */
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ if (options & BIT(22)) {
+ stm32l4_info->dual_bank_mode = true;
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+
+ /* for devices with trimmed flash, there is a gap between both banks */
+ stm32l4_info->hole_sectors =
+ (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb);
+ }
+ break;
+ case 0x470: /* STM32L4R/L4Sxx */
+ case 0x471: /* STM32L4P5/L4Q5x */
+ /* STM32L4R/S can be single/dual bank:
+ * if size = 2M check DBANK bit(22)
+ * if size = 1M check DB1M bit(21)
+ * STM32L4P/Q can be single/dual bank
+ * if size = 1M check DBANK bit(22)
+ * if size = 512K check DB512K bit(21)
+ */
+ page_size_kb = 8;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
+ if ((use_dbank_bit && (options & BIT(22))) ||
+ (!use_dbank_bit && (options & BIT(21)))) {
+ stm32l4_info->dual_bank_mode = true;
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case 0x495: /* STM32WB5x */
+ case 0x496: /* STM32WB3x */
+ /* single bank flash */
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
+ default:
+ LOG_ERROR("unsupported device");
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single");
+
+ const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb;
+
+ if (gap_size_kb != 0) {
+ LOG_INFO("gap detected from 0x%08" PRIx32 " to 0x%08" PRIx32,
+ STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors
+ * page_size_kb * 1024,
+ STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors
+ * page_size_kb + gap_size_kb) * 1024 - 1);
}
- /* Release sector table if allocated. */
+ /* number of significant bits in WRPxxR differs per device,
+ * always right adjusted, on some devices non-implemented
+ * bits read as '0', on others as '1' ...
+ * notably G4 Cat. 2 implement only 6 bits, contradicting the RM
+ */
+
+ /* use *max_flash_size* instead of actual size as the trimmed versions
+ * certainly use the same number of bits
+ * max_flash_size is always power of two, so max_pages too
+ */
+ uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb;
+ assert((max_pages & (max_pages - 1)) == 0);
+
+ /* in dual bank mode number of pages is doubled, but extra bit is bank selection */
+ stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1);
+ assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0);
+ LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask);
+
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
- /* Set bank configuration and construct sector table. */
- bank->base = base_address;
- bank->size = num_pages * page_size;
+ bank->size = (flash_size_kb + gap_size_kb) * 1024;
+ bank->base = STM32_FLASH_BANK_BASE;
bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
- if (!bank->sectors)
- return ERROR_FAIL; /* Checkme: What better error to use?*/
+ bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+ if (bank->sectors == NULL) {
+ LOG_ERROR("failed to allocate bank sectors");
+ return ERROR_FAIL;
+ }
- for (i = 0; i < num_pages; i++) {
- bank->sectors[i].offset = i * page_size;
- bank->sectors[i].size = page_size;
+ for (int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * page_size_kb * 1024;
+ /* in dual bank configuration, if there is a gap between banks
+ * we fix up the sector offset to consider this gap */
+ if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors)
+ bank->sectors[i].offset += gap_size_kb * 1024;
+ bank->sectors[i].size = page_size_kb * 1024;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
- stm32l4_info->probed = 1;
-
+ stm32l4_info->probed = true;
return ERROR_OK;
}
@@ -733,107 +1073,89 @@ static int stm32l4_auto_probe(struct flash_bank *bank)
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
if (stm32l4_info->probed)
return ERROR_OK;
+
return stm32l4_probe(bank);
}
static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
{
- struct target *target = bank->target;
- uint32_t dbgmcu_idcode;
-
- /* read stm32 device id register */
- int retval = target_read_u32(target, DBGMCU_IDCODE, &dbgmcu_idcode);
- if (retval != ERROR_OK)
- return retval;
-
- uint16_t device_id = dbgmcu_idcode & 0xfff;
- uint8_t rev_id = dbgmcu_idcode >> 28;
- uint8_t rev_minor = 0;
- int i;
-
- for (i = 16; i < 28; i++) {
- if (dbgmcu_idcode & (1 << i))
- rev_minor++;
- else
- break;
- }
-
- const char *device_str;
-
- switch (device_id) {
- case 0x470:
- device_str = "STM32L4R/4Sxx";
- break;
-
- case 0x461:
- device_str = "STM32L496/4A6";
- break;
-
- case 0x415:
- device_str = "STM32L475/476/486";
- break;
-
- case 0x462:
- device_str = "STM32L45x/46x";
- break;
-
- case 0x435:
- device_str = "STM32L43x/44x";
- break;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ const struct stm32l4_part_info *part_info = stm32l4_info->part_info;
+
+ if (part_info) {
+ const char *rev_str = NULL;
+ uint16_t rev_id = stm32l4_info->idcode >> 16;
+ for (unsigned int i = 0; i < part_info->num_revs; i++) {
+ if (rev_id == part_info->revs[i].rev) {
+ rev_str = part_info->revs[i].str;
+
+ if (rev_str != NULL) {
+ snprintf(buf, buf_size, "%s - Rev: %s%s",
+ part_info->device_str, rev_str, stm32l4_info->probed ?
+ (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : "");
+ return ERROR_OK;
+ }
+ }
+ }
- default:
- snprintf(buf, buf_size, "Cannot identify target as a STM32L4\n");
+ snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s",
+ part_info->device_str, rev_id, stm32l4_info->probed ?
+ (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : "");
+ return ERROR_OK;
+ } else {
+ snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families);
return ERROR_FAIL;
}
- snprintf(buf, buf_size, "%s - Rev: %1d.%02d",
- device_str, rev_id, rev_minor);
-
return ERROR_OK;
}
-static int stm32l4_mass_erase(struct flash_bank *bank, uint32_t action)
+static int stm32l4_mass_erase(struct flash_bank *bank)
{
- int retval;
+ int retval, retval2;
struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ uint32_t action = FLASH_MER1;
+
+ if (stm32l4_info->part_info->has_dual_bank)
+ action |= FLASH_MER2;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
/* mass erase flash memory */
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), action);
+ retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT / 10);
if (retval != ERROR_OK)
- return retval;
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR),
- action | FLASH_STRT);
+ goto err_lock;
+
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
- retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
+
+ retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ return retval2;
}
COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
{
- int i;
- uint32_t action;
-
if (CMD_ARGC < 1) {
command_print(CMD, "stm32l4x mass_erase <STM32L4 bank>");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -844,11 +1166,10 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
if (ERROR_OK != retval)
return retval;
- action = FLASH_MER1 | FLASH_MER2;
- retval = stm32l4_mass_erase(bank, action);
+ retval = stm32l4_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32l4x mass erase complete");
@@ -871,12 +1192,13 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command)
if (ERROR_OK != retval)
return retval;
- uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t reg_offset, reg_addr;
uint32_t value = 0;
- reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+ reg_offset = strtoul(CMD_ARGV[1], NULL, 16);
+ reg_addr = stm32l4_get_flash_reg(bank, reg_offset);
- retval = stm32l4_read_option(bank, reg_addr, &value);
+ retval = stm32l4_read_flash_reg(bank, reg_offset, &value);
if (ERROR_OK != retval)
return retval;
@@ -897,11 +1219,11 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
if (ERROR_OK != retval)
return retval;
- uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t reg_offset;
uint32_t value = 0;
uint32_t mask = 0xFFFFFFFF;
- reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+ reg_offset = strtoul(CMD_ARGV[1], NULL, 16);
value = strtoul(CMD_ARGV[2], NULL, 16);
if (CMD_ARGC > 3)
mask = strtoul(CMD_ARGV[3], NULL, 16);
@@ -910,13 +1232,13 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
"INFO: a reset or power cycle is required "
"for the new settings to take effect.", bank->driver->name);
- retval = stm32l4_write_option(bank, reg_addr, value, mask);
+ retval = stm32l4_write_option(bank, reg_offset, value, mask);
return retval;
}
COMMAND_HANDLER(stm32l4_handle_option_load_command)
{
- if (CMD_ARGC < 1)
+ if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
@@ -924,20 +1246,27 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command)
if (ERROR_OK != retval)
return retval;
- struct target *target = bank->target;
-
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (ERROR_OK != retval)
return retval;
- retval = stm32l4_unlock_option_reg(target);
+ retval = stm32l4_unlock_option_reg(bank);
if (ERROR_OK != retval)
return retval;
- /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */
- retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH);
+ /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload,
+ * but the RMs explicitly do *NOT* list this as power-on reset cause, and:
+ * "Note: If the read protection is set while the debugger is still
+ * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset."
+ */
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH);
+
+ command_print(CMD, "stm32l4x option load completed. Power-on reset might be required");
+
+ /* Need to re-probe after change */
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ stm32l4_info->probed = false;
- command_print(CMD, "stm32l4x option load (POR) completed.");
return retval;
}
diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h
new file mode 100644
index 0000000..abd8010
--- /dev/null
+++ b/src/flash/nor/stm32l4x.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Uwe Bonnes *
+ * bon@elektron.ikp.physik.tu-darmstadt.de *
+ *
+ * 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 2 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/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_STM32L4X
+#define OPENOCD_FLASH_NOR_STM32L4X
+
+/* Flash registers offsets */
+#define STM32_FLASH_ACR 0x00
+#define STM32_FLASH_KEYR 0x08
+#define STM32_FLASH_OPTKEYR 0x0c
+#define STM32_FLASH_SR 0x10
+#define STM32_FLASH_CR 0x14
+#define STM32_FLASH_OPTR 0x20
+#define STM32_FLASH_WRP1AR 0x2c
+#define STM32_FLASH_WRP1BR 0x30
+#define STM32_FLASH_WRP2AR 0x4c
+#define STM32_FLASH_WRP2BR 0x50
+
+/* FLASH_CR register bits */
+#define FLASH_PG (1 << 0)
+#define FLASH_PER (1 << 1)
+#define FLASH_MER1 (1 << 2)
+#define FLASH_PAGE_SHIFT 3
+#define FLASH_CR_BKER (1 << 11)
+#define FLASH_MER2 (1 << 15)
+#define FLASH_STRT (1 << 16)
+#define FLASH_OPTSTRT (1 << 17)
+#define FLASH_EOPIE (1 << 24)
+#define FLASH_ERRIE (1 << 25)
+#define FLASH_OBL_LAUNCH (1 << 27)
+#define FLASH_OPTLOCK (1 << 30)
+#define FLASH_LOCK (1 << 31)
+
+/* FLASH_SR register bits */
+#define FLASH_BSY (1 << 16)
+
+/* Fast programming not used => related errors not used*/
+#define FLASH_PGSERR (1 << 7) /* Programming sequence error */
+#define FLASH_SIZERR (1 << 6) /* Size error */
+#define FLASH_PGAERR (1 << 5) /* Programming alignment error */
+#define FLASH_WRPERR (1 << 4) /* Write protection error */
+#define FLASH_PROGERR (1 << 3) /* Programming error */
+#define FLASH_OPERR (1 << 1) /* Operation error */
+#define FLASH_EOP (1 << 0) /* End of operation */
+#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \
+ FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR)
+
+/* register unlock keys */
+#define KEY1 0x45670123
+#define KEY2 0xCDEF89AB
+
+/* option register unlock key */
+#define OPTKEY1 0x08192A3B
+#define OPTKEY2 0x4C5D6E7F
+
+#define RDP_LEVEL_0 0xAA
+#define RDP_LEVEL_1 0xBB
+#define RDP_LEVEL_2 0xCC
+
+/* other registers */
+#define DBGMCU_IDCODE_G0 0x40015800
+#define DBGMCU_IDCODE_L4_G4 0xE0042000
+#define DBGMCU_IDCODE_L5 0xE0044000
+
+#define STM32_FLASH_BANK_BASE 0x08000000
+
+#endif
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index e6473f8..c3f9c72 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -128,7 +128,7 @@ struct stm32lx_part_info {
};
struct stm32lx_flash_bank {
- int probed;
+ bool probed;
uint32_t idcode;
uint32_t user_bank_size;
uint32_t flash_base;
@@ -297,7 +297,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
bank->driver_priv = stm32lx_info;
- stm32lx_info->probed = 0;
+ stm32lx_info->probed = false;
stm32lx_info->user_bank_size = bank->size;
/* the stm32l erased value is 0x00 */
@@ -308,8 +308,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -321,7 +319,7 @@ COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
retval = stm32lx_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32lx mass erase complete");
@@ -731,14 +729,13 @@ static int stm32lx_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- int i;
uint16_t flash_size_in_kb;
uint32_t device_id;
uint32_t base_address = FLASH_BANK0_ADDRESS;
uint32_t second_bank_base;
unsigned int n;
- stm32lx_info->probed = 0;
+ stm32lx_info->probed = false;
int retval = stm32lx_read_id_code(bank->target, &device_id);
if (retval != ERROR_OK)
@@ -756,7 +753,7 @@ static int stm32lx_probe(struct flash_bank *bank)
}
if (n == ARRAY_SIZE(stm32lx_parts)) {
- LOG_WARNING("Cannot identify target as a STM32L family.");
+ LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device.");
return ERROR_FAIL;
} else {
LOG_INFO("Device: %s", stm32lx_info->part_info.device_str);
@@ -852,14 +849,14 @@ static int stm32lx_probe(struct flash_bank *bank)
return ERROR_FAIL;
}
- for (i = 0; i < num_sectors; i++) {
+ for (int i = 0; i < num_sectors; i++) {
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
bank->sectors[i].size = FLASH_SECTOR_SIZE;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
- stm32lx_info->probed = 1;
+ stm32lx_info->probed = true;
return ERROR_OK;
}
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index bd313a0..fb2053b 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -109,7 +109,7 @@ COMMAND_HANDLER(handle_flash_info_command)
return retval;
}
if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
- LOG_WARNING("Flash protection check is not implemented.");
+ LOG_INFO("Flash protection check is not implemented.");
command_print(CMD,
"#%d : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32
@@ -476,7 +476,7 @@ COMMAND_HANDLER(handle_flash_write_image_command)
COMMAND_HANDLER(handle_flash_fill_command)
{
target_addr_t address;
- uint32_t pattern;
+ uint64_t pattern;
uint32_t count;
struct target *target = get_current_target(CMD_CTX);
unsigned i;
@@ -487,7 +487,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern);
+ COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
struct flash_bank *bank;
@@ -496,6 +496,9 @@ COMMAND_HANDLER(handle_flash_fill_command)
return retval;
switch (CMD_NAME[4]) {
+ case 'd':
+ wordsize = 8;
+ break;
case 'w':
wordsize = 4;
break;
@@ -509,6 +512,11 @@ COMMAND_HANDLER(handle_flash_fill_command)
return ERROR_COMMAND_SYNTAX_ERROR;
}
+ if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) {
+ command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize);
+ return ERROR_FAIL;
+ }
+
if (count == 0)
return ERROR_OK;
@@ -541,6 +549,10 @@ COMMAND_HANDLER(handle_flash_fill_command)
uint8_t *ptr = buffer + padding_at_start;
switch (wordsize) {
+ case 8:
+ for (i = 0; i < count; i++, ptr += wordsize)
+ target_buffer_set_u64(target, ptr, pattern);
+ break;
case 4:
for (i = 0; i < count; i++, ptr += wordsize)
target_buffer_set_u32(target, ptr, pattern);
@@ -577,9 +589,12 @@ COMMAND_HANDLER(handle_flash_fill_command)
goto done;
for (i = 0, ptr = buffer; i < count; i++) {
- uint32_t readback = 0;
+ uint64_t readback = 0;
switch (wordsize) {
+ case 8:
+ readback = target_buffer_get_u64(target, ptr);
+ break;
case 4:
readback = target_buffer_get_u32(target, ptr);
break;
@@ -593,7 +608,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
if (readback != pattern) {
LOG_ERROR(
"Verification error address " TARGET_ADDR_FMT
- ", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32,
+ ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64,
address + i * wordsize, readback, pattern);
retval = ERROR_FAIL;
goto done;
@@ -613,6 +628,67 @@ done:
return retval;
}
+COMMAND_HANDLER(handle_flash_md_command)
+{
+ int retval;
+
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ target_addr_t address;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
+
+ uint32_t count = 1;
+ if (CMD_ARGC == 2)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count);
+
+ unsigned int wordsize;
+ switch (CMD_NAME[2]) {
+ case 'w':
+ wordsize = 4;
+ break;
+ case 'h':
+ wordsize = 2;
+ break;
+ case 'b':
+ wordsize = 1;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (count == 0)
+ return ERROR_OK;
+
+ struct target *target = get_current_target(CMD_CTX);
+ struct flash_bank *bank;
+ retval = get_flash_bank_by_addr(target, address, true, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t offset = address - bank->base;
+ uint32_t sizebytes = count * wordsize;
+ if (offset + sizebytes > bank->size) {
+ command_print(CMD, "Cannot cross flash bank borders");
+ return ERROR_FAIL;
+ }
+
+ uint8_t *buffer = calloc(count, wordsize);
+ if (buffer == NULL) {
+ command_print(CMD, "No memory for flash read buffer");
+ return ERROR_FAIL;
+ }
+
+ retval = flash_driver_read(bank, buffer, offset, sizebytes);
+ if (retval == ERROR_OK)
+ target_handle_md_output(CMD, target, address, wordsize, count, buffer);
+
+ free(buffer);
+
+ return retval;
+}
+
+
COMMAND_HANDLER(handle_flash_write_bank_command)
{
uint32_t offset;
@@ -952,7 +1028,7 @@ COMMAND_HANDLER(handle_flash_padded_value_command)
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value);
- command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", \
+ command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u",
p->default_padded_value, p->bank_number);
return retval;
@@ -1003,6 +1079,14 @@ static const struct command_registration flash_exec_command_handlers[] = {
},
{
+ .name = "filld",
+ .handler = handle_flash_fill_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address value n",
+ .help = "Fill n double-words with 64-bit value, starting at "
+ "word address. (No autoerase.)",
+ },
+ {
.name = "fillw",
.handler = handle_flash_fill_command,
.mode = COMMAND_EXEC,
@@ -1027,6 +1111,27 @@ static const struct command_registration flash_exec_command_handlers[] = {
"word address. (No autoerase.)",
},
{
+ .name = "mdb",
+ .handler = handle_flash_md_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address [count]",
+ .help = "Display bytes from flash.",
+ },
+ {
+ .name = "mdh",
+ .handler = handle_flash_md_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address [count]",
+ .help = "Display half-words from flash.",
+ },
+ {
+ .name = "mdw",
+ .handler = handle_flash_md_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address [count]",
+ .help = "Display words from flash.",
+ },
+ {
.name = "write_bank",
.handler = handle_flash_write_bank_command,
.mode = COMMAND_EXEC,
diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c
index 90557b8..bc16aca 100644
--- a/src/flash/nor/tms470.c
+++ b/src/flash/nor/tms470.c
@@ -709,6 +709,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector)
* Select one or more bits in FMBSEA or FMBSEB to disable Level 1
* protection for the particular sector to be erased/written.
*/
+ assert(sector >= 0);
if (sector < 16) {
target_read_u32(target, 0xFFE88008, &fmbsea);
target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector));
diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c
index a0c35c5..ba35c2c 100644
--- a/src/flash/nor/xcf.c
+++ b/src/flash/nor/xcf.c
@@ -625,7 +625,6 @@ static int xcf_probe(struct flash_bank *bank)
default:
LOG_ERROR("Unknown flash device ID 0x%X", id);
return ERROR_FAIL;
- break;
}
bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));