aboutsummaryrefslogtreecommitdiff
path: root/src/flash
diff options
context:
space:
mode:
Diffstat (limited to 'src/flash')
-rw-r--r--src/flash/Makefile.am30
-rw-r--r--src/flash/common.h1
-rw-r--r--src/flash/nand/Makefile.am79
-rw-r--r--src/flash/nand/tcl.c6
-rw-r--r--src/flash/nor/Makefile.am130
-rw-r--r--src/flash/nor/at91sam4.c561
-rw-r--r--src/flash/nor/at91sam4l.c13
-rw-r--r--src/flash/nor/at91sam7.c2
-rw-r--r--src/flash/nor/at91samd.c108
-rw-r--r--src/flash/nor/ath79.c901
-rw-r--r--src/flash/nor/atsamv.c3
-rw-r--r--src/flash/nor/avrf.c1
-rw-r--r--src/flash/nor/cfi.c64
-rw-r--r--src/flash/nor/core.c21
-rw-r--r--src/flash/nor/core.h3
-rw-r--r--src/flash/nor/drivers.c2
-rw-r--r--src/flash/nor/efm32.c6
-rw-r--r--src/flash/nor/em357.c5
-rw-r--r--src/flash/nor/fm4.c2
-rw-r--r--src/flash/nor/kinetis.c196
-rw-r--r--src/flash/nor/lpc2000.c17
-rw-r--r--src/flash/nor/lpcspifi.c2
-rw-r--r--src/flash/nor/mdr.c3
-rw-r--r--src/flash/nor/nrf51.c76
-rw-r--r--src/flash/nor/pic32mx.c3
-rw-r--r--src/flash/nor/stm32f2x.c9
-rw-r--r--src/flash/nor/stm32l4x.c41
-rw-r--r--src/flash/nor/stm32lx.c189
-rw-r--r--src/flash/nor/tcl.c55
-rw-r--r--src/flash/nor/virtual.c1
-rw-r--r--src/flash/nor/xmc1xxx.c2
-rw-r--r--src/flash/nor/xmc4xxx.c111
32 files changed, 2005 insertions, 638 deletions
diff --git a/src/flash/Makefile.am b/src/flash/Makefile.am
index ece4018..a1b46f8 100644
--- a/src/flash/Makefile.am
+++ b/src/flash/Makefile.am
@@ -1,23 +1,13 @@
-include $(top_srcdir)/common.mk
+noinst_LTLIBRARIES += %D%/libflash.la
+%C%_libflash_la_SOURCES = \
+ %D%/common.c %D%/common.h \
+ %D%/mflash.c %D%/mflash.h
-SUBDIRS = \
- nor \
- nand
+%C%_libflash_la_LIBADD = \
+ %D%/nor/libocdflashnor.la \
+ %D%/nand/libocdflashnand.la
-METASOURCES = AUTO
-noinst_LTLIBRARIES = libflash.la
-libflash_la_SOURCES = \
- common.c \
- mflash.c
+STARTUP_TCL_SRCS += %D%/startup.tcl
-libflash_la_LIBADD = \
- $(top_builddir)/src/flash/nor/libocdflashnor.la \
- $(top_builddir)/src/flash/nand/libocdflashnand.la
-
-noinst_HEADERS = \
- common.h \
- mflash.h
-
-EXTRA_DIST = startup.tcl
-
-MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+include %D%/nor/Makefile.am
+include %D%/nand/Makefile.am
diff --git a/src/flash/common.h b/src/flash/common.h
index ce26fcc..4244f13 100644
--- a/src/flash/common.h
+++ b/src/flash/common.h
@@ -44,5 +44,6 @@ bool flash_driver_name_matches(const char *name, const char *expected);
#define ERROR_FLASH_SECTOR_NOT_ERASED (-906)
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
+#define ERROR_FLASH_PROTECTED (-909)
#endif /* OPENOCD_FLASH_COMMON_H */
diff --git a/src/flash/nand/Makefile.am b/src/flash/nand/Makefile.am
index 2ddd096..abe90f8 100644
--- a/src/flash/nand/Makefile.am
+++ b/src/flash/nand/Makefile.am
@@ -1,46 +1,43 @@
-include $(top_srcdir)/common.mk
+noinst_LTLIBRARIES += %D%/libocdflashnand.la
-noinst_LTLIBRARIES = libocdflashnand.la
-
-libocdflashnand_la_SOURCES = \
- ecc.c \
- ecc_kw.c \
- core.c \
- fileio.c \
- tcl.c \
- arm_io.c \
+%C%_libocdflashnand_la_SOURCES = \
+ %D%/ecc.c \
+ %D%/ecc_kw.c \
+ %D%/core.c \
+ %D%/fileio.c \
+ %D%/tcl.c \
+ %D%/arm_io.c \
$(NAND_DRIVERS) \
- driver.c
+ %D%/driver.c \
+ $(NANDHEADERS)
NAND_DRIVERS = \
- nonce.c \
- davinci.c \
- lpc3180.c \
- lpc32xx.c \
- mxc.c \
- mx3.c \
- orion.c \
- s3c24xx.c \
- s3c2410.c \
- s3c2412.c \
- s3c2440.c \
- s3c2443.c \
- s3c6400.c \
- at91sam9.c \
- nuc910.c
-
-noinst_HEADERS = \
- arm_io.h \
- core.h \
- driver.h \
- fileio.h \
- imp.h \
- lpc3180.h \
- lpc32xx.h \
- mxc.h \
- mx3.h \
- s3c24xx.h \
- s3c24xx_regs.h \
- nuc910.h
+ %D%/nonce.c \
+ %D%/davinci.c \
+ %D%/lpc3180.c \
+ %D%/lpc32xx.c \
+ %D%/mxc.c \
+ %D%/mx3.c \
+ %D%/orion.c \
+ %D%/s3c24xx.c \
+ %D%/s3c2410.c \
+ %D%/s3c2412.c \
+ %D%/s3c2440.c \
+ %D%/s3c2443.c \
+ %D%/s3c6400.c \
+ %D%/at91sam9.c \
+ %D%/nuc910.c
-MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+NANDHEADERS = \
+ %D%/arm_io.h \
+ %D%/core.h \
+ %D%/driver.h \
+ %D%/fileio.h \
+ %D%/imp.h \
+ %D%/lpc3180.h \
+ %D%/lpc32xx.h \
+ %D%/mxc.h \
+ %D%/mx3.h \
+ %D%/s3c24xx.h \
+ %D%/s3c24xx_regs.h \
+ %D%/nuc910.h
diff --git a/src/flash/nand/tcl.c b/src/flash/nand/tcl.c
index cbdeda5..d9738c5 100644
--- a/src/flash/nand/tcl.c
+++ b/src/flash/nand/tcl.c
@@ -254,7 +254,8 @@ COMMAND_HANDLER(handle_nand_write_command)
int bytes_read = nand_fileio_read(nand, &s);
if (bytes_read <= 0) {
command_print(CMD_CTX, "error while reading file");
- return nand_fileio_cleanup(&s);
+ nand_fileio_cleanup(&s);
+ return ERROR_FAIL;
}
s.size -= bytes_read;
@@ -264,7 +265,8 @@ COMMAND_HANDLER(handle_nand_write_command)
command_print(CMD_CTX, "failed writing file %s "
"to NAND flash %s at offset 0x%8.8" PRIx32,
CMD_ARGV[1], CMD_ARGV[0], s.address);
- return nand_fileio_cleanup(&s);
+ nand_fileio_cleanup(&s);
+ return retval;
}
s.address += s.page_size;
}
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 084e6b6..759e98c 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -1,70 +1,68 @@
-include $(top_srcdir)/common.mk
-
-noinst_LTLIBRARIES = libocdflashnor.la
-libocdflashnor_la_SOURCES = \
- core.c \
- tcl.c \
+noinst_LTLIBRARIES += %D%/libocdflashnor.la
+%C%_libocdflashnor_la_SOURCES = \
+ %D%/core.c \
+ %D%/tcl.c \
$(NOR_DRIVERS) \
- drivers.c
+ %D%/drivers.c \
+ $(NORHEADERS)
NOR_DRIVERS = \
- aduc702x.c \
- aducm360.c \
- ambiqmicro.c \
- at91sam4.c \
- at91sam4l.c \
- at91samd.c \
- at91sam3.c \
- at91sam7.c \
- atsamv.c \
- avrf.c \
- cfi.c \
- dsp5680xx_flash.c \
- efm32.c \
- em357.c \
- fespi.c \
- faux.c \
- fm3.c \
- fm4.c \
- jtagspi.c \
- kinetis.c \
- kinetis_ke.c \
- lpc2000.c \
- lpc288x.c \
- lpc2900.c \
- lpcspifi.c \
- mdr.c \
- mrvlqspi.c \
- niietcm4.c \
- non_cfi.c \
- nrf51.c \
- numicro.c \
- ocl.c \
- pic32mx.c \
- psoc4.c \
- sim3x.c \
- spi.c \
- stmsmi.c \
- stellaris.c \
- stm32f1x.c \
- stm32f2x.c \
- stm32lx.c \
- stm32l4x.c \
- str7x.c \
- str9x.c \
- str9xpec.c \
- tms470.c \
- virtual.c \
- xmc1xxx.c \
- xmc4xxx.c
-
-noinst_HEADERS = \
- core.h \
- cfi.h \
- driver.h \
- imp.h \
- non_cfi.h \
- ocl.h \
- spi.h
+ %D%/aduc702x.c \
+ %D%/aducm360.c \
+ %D%/ambiqmicro.c \
+ %D%/at91sam4.c \
+ %D%/at91sam4l.c \
+ %D%/at91samd.c \
+ %D%/at91sam3.c \
+ %D%/at91sam7.c \
+ %D%/ath79.c \
+ %D%/atsamv.c \
+ %D%/avrf.c \
+ %D%/cfi.c \
+ %D%/dsp5680xx_flash.c \
+ %D%/efm32.c \
+ %D%/em357.c \
+ %D%/fespi.c \
+ %D%/faux.c \
+ %D%/fm3.c \
+ %D%/fm4.c \
+ %D%/jtagspi.c \
+ %D%/kinetis.c \
+ %D%/kinetis_ke.c \
+ %D%/lpc2000.c \
+ %D%/lpc288x.c \
+ %D%/lpc2900.c \
+ %D%/lpcspifi.c \
+ %D%/mdr.c \
+ %D%/mrvlqspi.c \
+ %D%/niietcm4.c \
+ %D%/non_cfi.c \
+ %D%/nrf51.c \
+ %D%/numicro.c \
+ %D%/ocl.c \
+ %D%/pic32mx.c \
+ %D%/psoc4.c \
+ %D%/sim3x.c \
+ %D%/spi.c \
+ %D%/stmsmi.c \
+ %D%/stellaris.c \
+ %D%/stm32f1x.c \
+ %D%/stm32f2x.c \
+ %D%/stm32lx.c \
+ %D%/stm32l4x.c \
+ %D%/str7x.c \
+ %D%/str9x.c \
+ %D%/str9xpec.c \
+ %D%/tms470.c \
+ %D%/virtual.c \
+ %D%/xmc1xxx.c \
+ %D%/xmc4xxx.c
-MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+NORHEADERS = \
+ %D%/core.h \
+ %D%/cfi.h \
+ %D%/driver.h \
+ %D%/imp.h \
+ %D%/non_cfi.h \
+ %D%/ocl.h \
+ %D%/spi.h
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index 50aa98b..ff75b41 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -65,8 +65,9 @@
#define REG_NAME_WIDTH (12)
-/* at91sam4s/at91sam4e series (has always one flash bank)*/
+/* at91sam4s/at91sam4e/at91sam4c series (has always one flash bank)*/
#define FLASH_BANK_BASE_S 0x00400000
+#define FLASH_BANK_BASE_C 0x01000000
/* at91sam4sd series (two one flash banks), first bank address */
#define FLASH_BANK0_BASE_SD FLASH_BANK_BASE_S
@@ -75,6 +76,10 @@
/* at91sam4sd32x, second bank address */
#define FLASH_BANK1_BASE_2048K_SD (FLASH_BANK0_BASE_SD+(2048*1024/2))
+/* at91sam4c32x, first and second bank address */
+#define FLASH_BANK0_BASE_C32 FLASH_BANK_BASE_C
+#define FLASH_BANK1_BASE_C32 (FLASH_BANK_BASE_C+(2048*1024/2))
+
#define AT91C_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */
#define AT91C_EFC_FCMD_WP (0x1) /* (EFC) Write Page */
#define AT91C_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */
@@ -258,6 +263,188 @@ static struct sam4_chip *get_current_sam4(struct command_context *cmd_ctx)
/* these are used to *initialize* the "pChip->details" structure. */
static const struct sam4_chip_details all_sam4_details[] = {
+ /* Start at91sam4c* series */
+ /* at91sam4c32e - LQFP144 */
+ {
+ .chipid_cidr = 0xA66D0EE0,
+ .name = "at91sam4c32e",
+ .total_flash_size = 2024 * 1024,
+ .total_sram_size = 256 * 1024,
+ .n_gpnvms = 3,
+ .n_banks = 2,
+/* .bank[0] = { */
+ {
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK0_BASE_C32,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = { */
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 1,
+ .base_address = FLASH_BANK1_BASE_C32,
+ .controller_address = 0x400e0c00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+ },
+ },
+ /* at91sam4c32c - LQFP100 */
+ {
+ .chipid_cidr = 0xA64D0EE0,
+ .name = "at91sam4c32c",
+ .total_flash_size = 2024 * 1024,
+ .total_sram_size = 256 * 1024,
+ .n_gpnvms = 3,
+ .n_banks = 2,
+/* .bank[0] = { */
+ {
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK0_BASE_C32,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = { */
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 1,
+ .base_address = FLASH_BANK1_BASE_C32,
+ .controller_address = 0x400e0c00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+ },
+ },
+ /* at91sam4c16c - LQFP100 */
+ {
+ .chipid_cidr = 0xA64C0CE0,
+ .name = "at91sam4c16c",
+ .total_flash_size = 1024 * 1024,
+ .total_sram_size = 128 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_C,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+ /* at91sam4c8c - LQFP100 */
+ {
+ .chipid_cidr = 0xA64C0AE0,
+ .name = "at91sam4c8c",
+ .total_flash_size = 512 * 1024,
+ .total_sram_size = 128 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_C,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 512 * 1024,
+ .nsectors = 64,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+ /* at91sam4c4c (rev B) - LQFP100 */
+ {
+ .chipid_cidr = 0xA64C0CE5,
+ .name = "at91sam4c4c",
+ .total_flash_size = 256 * 1024,
+ .total_sram_size = 128 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_C,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 256 * 1024,
+ .nsectors = 32,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
/* Start at91sam4e* series */
/*atsam4e16e - LQFP144/LFBGA144*/
@@ -479,7 +666,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -495,7 +682,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
},
- /*atsam4s16b - LQFP64/QFN64*/
+ /*atsam4s16b - LQFP64/QFN64/WLCSP64*/
{
.chipid_cidr = 0x289C0CE0,
.name = "at91sam4s16b",
@@ -512,7 +699,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -545,7 +732,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -578,7 +765,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -611,7 +798,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -627,7 +814,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
},
- /*atsam4s8b - LQFP64/BGA64*/
+ /*atsam4s8b - LQFP64/QFN64/WLCSP64*/
{
.chipid_cidr = 0x289C0AE0,
.name = "at91sam4s8b",
@@ -644,7 +831,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -677,7 +864,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -694,7 +881,75 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
- /*atsam4s4a - LQFP48/BGA48*/
+ /*atsam4s4c - LQFP100/BGA100*/
+ {
+ .chipid_cidr = 0x28ab09e0,
+ .name = "at91sam4s4c",
+ .total_flash_size = 256 * 1024,
+ .total_sram_size = 64 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 256 * 1024,
+ .nsectors = 32,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+
+ /*atsam4s4b - LQFP64/QFN64/WLCSP64*/
+ {
+ .chipid_cidr = 0x289b09e0,
+ .name = "at91sam4s4b",
+ .total_flash_size = 256 * 1024,
+ .total_sram_size = 64 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 256 * 1024,
+ .nsectors = 32,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+
+ /*atsam4s4a - LQFP48/QFN48*/
{
.chipid_cidr = 0x288b09e0,
.name = "at91sam4s4a",
@@ -711,7 +966,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 256 * 1024,
.nsectors = 32,
@@ -728,7 +983,109 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
- /*at91sam4sd32c*/
+ /*atsam4s2c - LQFP100/BGA100*/
+ {
+ .chipid_cidr = 0x28ab07e0,
+ .name = "at91sam4s2c",
+ .total_flash_size = 128 * 1024,
+ .total_sram_size = 64 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 128 * 1024,
+ .nsectors = 16,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+
+ /*atsam4s2b - LQPF64/QFN64/WLCSP64*/
+ {
+ .chipid_cidr = 0x289b07e0,
+ .name = "at91sam4s2b",
+ .total_flash_size = 128 * 1024,
+ .total_sram_size = 64 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 128 * 1024,
+ .nsectors = 16,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+
+ /*atsam4s2a - LQFP48/QFN48*/
+ {
+ .chipid_cidr = 0x288b07e0,
+ .name = "at91sam4s2a",
+ .total_flash_size = 128 * 1024,
+ .total_sram_size = 64 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+ {
+/* .bank[0] = {*/
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 128 * 1024,
+ .nsectors = 16,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
+
+ /*at91sam4sd32c - LQFP100/BGA100*/
{
.chipid_cidr = 0x29a70ee0,
.name = "at91sam4sd32c",
@@ -746,7 +1103,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -762,7 +1119,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 1,
.base_address = FLASH_BANK1_BASE_2048K_SD,
.controller_address = 0x400e0c00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -772,7 +1129,51 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
- /*at91sam4sd16c*/
+ /*at91sam4sd32b - LQFP64/BGA64*/
+ {
+ .chipid_cidr = 0x29970ee0,
+ .name = "at91sam4sd32b",
+ .total_flash_size = 2048 * 1024,
+ .total_sram_size = 160 * 1024,
+ .n_gpnvms = 3,
+ .n_banks = 2,
+
+/* .bank[0] = { */
+ {
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK0_BASE_SD,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+
+/* .bank[1] = { */
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 1,
+ .base_address = FLASH_BANK1_BASE_2048K_SD,
+ .controller_address = 0x400e0c00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+ },
+ },
+
+ /*at91sam4sd16c - LQFP100/BGA100*/
{
.chipid_cidr = 0x29a70ce0,
.name = "at91sam4sd16c",
@@ -790,7 +1191,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -806,7 +1207,51 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 1,
.base_address = FLASH_BANK1_BASE_1024K_SD,
.controller_address = 0x400e0c00,
- .flash_wait_states = 6, /* workaround silicon bug */
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 512 * 1024,
+ .nsectors = 64,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+ },
+ },
+
+ /*at91sam4sd16b - LQFP64/BGA64*/
+ {
+ .chipid_cidr = 0x29970ce0,
+ .name = "at91sam4sd16b",
+ .total_flash_size = 1024 * 1024,
+ .total_sram_size = 160 * 1024,
+ .n_gpnvms = 3,
+ .n_banks = 2,
+
+/* .bank[0] = { */
+ {
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK0_BASE_SD,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 512 * 1024,
+ .nsectors = 64,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+
+/* .bank[1] = { */
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 1,
+ .base_address = FLASH_BANK1_BASE_1024K_SD,
+ .controller_address = 0x400e0c00,
+ .flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -895,6 +1340,74 @@ static const struct sam4_chip_details all_sam4_details[] = {
}
},
+ /* atsamg55g19 */
+ {
+ .chipid_cidr = 0x24470ae0,
+ .name = "atsamg55g19",
+ .total_flash_size = 512 * 1024,
+ .total_sram_size = 160 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+
+ {
+/* .bank[0] = */
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 512 * 1024,
+ .nsectors = 64,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = */
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+ },
+ }
+ },
+
+ /* atsamg55j19 */
+ {
+ .chipid_cidr = 0x24570ae0,
+ .name = "atsamg55j19",
+ .total_flash_size = 512 * 1024,
+ .total_sram_size = 160 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+
+ {
+/* .bank[0] = */
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 512 * 1024,
+ .nsectors = 64,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = */
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+ },
+ }
+ },
+
/* terminate */
{
.chipid_cidr = 0,
@@ -1402,7 +1915,7 @@ static uint32_t sam4_reg_fieldname(struct sam4_chip *pChip,
static const char _unknown[] = "unknown";
static const char *const eproc_names[] = {
- _unknown, /* 0 */
+ "Cortex-M7", /* 0 */
"arm946es", /* 1 */
"arm7tdmi", /* 2 */
"Cortex-M3", /* 3 */
@@ -1430,7 +1943,7 @@ static const char *const nvpsize[] = {
"64K bytes", /* 5 */
_unknown, /* 6 */
"128K bytes", /* 7 */
- _unknown, /* 8 */
+ "160K bytes", /* 8 */
"256K bytes", /* 9 */
"512K bytes", /* 10 */
_unknown, /* 11 */
@@ -1472,12 +1985,16 @@ static const struct archnames { unsigned value; const char *name; } archnames[]
{ 0x42, "AT91x42 Series" },
{ 0x43, "SAMG51 Series"
},
+ { 0x44, "SAMG55 Series (49-pin WLCSP)" },
+ { 0x45, "SAMG55 Series (64-pin)" },
{ 0x47, "SAMG53 Series"
},
{ 0x55, "AT91x55 Series" },
{ 0x60, "AT91SAM7Axx Series" },
{ 0x61, "AT91SAM7AQxx Series" },
{ 0x63, "AT91x63 Series" },
+ { 0x64, "SAM4CxxC (100-pin version)" },
+ { 0x66, "SAM4CxxE (144-pin version)" },
{ 0x70, "AT91SAM7Sxx Series" },
{ 0x71, "AT91SAM7XCxx Series" },
{ 0x72, "AT91SAM7SExx Series" },
@@ -1975,15 +2492,17 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command)
/* at91sam4s series only has bank 0*/
/* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/
case FLASH_BANK_BASE_S:
+ case FLASH_BANK_BASE_C:
bank->driver_priv = &(pChip->details.bank[0]);
bank->bank_number = 0;
pChip->details.bank[0].pChip = pChip;
pChip->details.bank[0].pBank = bank;
break;
- /* Bank 1 of at91sam4sd series */
+ /* Bank 1 of at91sam4sd/at91sam4c32 series */
case FLASH_BANK1_BASE_1024K_SD:
case FLASH_BANK1_BASE_2048K_SD:
+ case FLASH_BANK1_BASE_C32:
bank->driver_priv = &(pChip->details.bank[1]);
bank->bank_number = 1;
pChip->details.bank[1].pChip = pChip;
diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c
index 4710512..0a605d5 100644
--- a/src/flash/nor/at91sam4l.c
+++ b/src/flash/nor/at91sam4l.c
@@ -645,10 +645,15 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer,
COMMAND_HANDLER(sam4l_handle_reset_deassert)
{
struct target *target = get_current_target(CMD_CTX);
- struct armv7m_common *armv7m = target_to_armv7m(target);
int retval = ERROR_OK;
enum reset_types jtag_reset_config = jtag_get_reset_config();
+ /* If the target has been unresponsive before, try to re-establish
+ * communication now - CPU is held in reset by DSU, DAP is working */
+ if (!target_was_examined(target))
+ target_examine_one(target);
+ target_poll(target);
+
/* In case of sysresetreq, debug retains state set in cortex_m_assert_reset()
* so we just release reset held by SMAP
*
@@ -657,14 +662,14 @@ COMMAND_HANDLER(sam4l_handle_reset_deassert)
* After vectreset SMAP release is not needed however makes no harm
*/
if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) {
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
+ retval = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
if (retval == ERROR_OK)
- retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR,
+ retval = target_write_u32(target, DCB_DEMCR,
TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
/* do not return on error here, releasing SMAP reset is more important */
}
- int retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, SMAP_SCR, SMAP_SCR_HCR);
+ int retval2 = target_write_u32(target, SMAP_SCR, SMAP_SCR_HCR);
if (retval2 != ERROR_OK)
return retval2;
diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c
index ccb1a74..03f771c 100644
--- a/src/flash/nor/at91sam7.c
+++ b/src/flash/nor/at91sam7.c
@@ -661,7 +661,7 @@ static int at91sam7_erase_check(struct flash_bank *bank)
retval = target_blank_check_memory(target,
bank->base + bank->sectors[nSector].offset,
bank->sectors[nSector].size,
- &blank);
+ &blank, bank->erased_value);
if (retval != ERROR_OK) {
fast_check = 0;
break;
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index 58b367a..f018e89 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -36,6 +36,7 @@
#define SAMD_DSU_STATUSA 1 /* DSU status register */
#define SAMD_DSU_DID 0x18 /* Device ID register */
+#define SAMD_DSU_CTRL_EXT 0x100 /* CTRL register, external access */
#define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */
#define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */
@@ -423,39 +424,43 @@ static int samd_probe(struct flash_bank *bank)
return ERROR_OK;
}
-static bool samd_check_error(struct target *target)
+static int samd_check_error(struct target *target)
{
- int ret;
- bool error;
+ int ret, ret2;
uint16_t status;
ret = target_read_u16(target,
SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status);
if (ret != ERROR_OK) {
LOG_ERROR("Can't read NVM status");
- return true;
+ return ret;
}
- if (status & 0x001C) {
- if (status & (1 << 4)) /* NVME */
- LOG_ERROR("SAMD: NVM Error");
- if (status & (1 << 3)) /* LOCKE */
- LOG_ERROR("SAMD: NVM lock error");
- if (status & (1 << 2)) /* PROGE */
- LOG_ERROR("SAMD: NVM programming error");
+ if ((status & 0x001C) == 0)
+ return ERROR_OK;
- error = true;
- } else {
- error = false;
+ if (status & (1 << 4)) { /* NVME */
+ LOG_ERROR("SAMD: NVM Error");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (status & (1 << 3)) { /* LOCKE */
+ LOG_ERROR("SAMD: NVM lock error");
+ ret = ERROR_FLASH_PROTECTED;
+ }
+
+ if (status & (1 << 2)) { /* PROGE */
+ LOG_ERROR("SAMD: NVM programming error");
+ ret = ERROR_FLASH_OPER_UNSUPPORTED;
}
/* Clear the error conditions by writing a one to them */
- ret = target_write_u16(target,
+ ret2 = target_write_u16(target,
SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, status);
- if (ret != ERROR_OK)
+ if (ret2 != ERROR_OK)
LOG_ERROR("Can't clear NVM error conditions");
- return error;
+ return ret;
}
static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
@@ -474,10 +479,7 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
return res;
/* Check to see if the NVM command resulted in an error condition. */
- if (samd_check_error(target))
- return ERROR_FAIL;
-
- return ERROR_OK;
+ return samd_check_error(target);
}
static int samd_erase_row(struct target *target, uint32_t address)
@@ -531,12 +533,19 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
uint8_t startb, uint8_t endb)
{
int res;
+ uint32_t nvm_ctrlb;
+ bool manual_wp = true;
if (is_user_row_reserved_bit(startb) || is_user_row_reserved_bit(endb)) {
LOG_ERROR("Can't modify bits in the requested range");
return ERROR_FAIL;
}
+ /* Check if we need to do manual page write commands */
+ res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb);
+ if (res == ERROR_OK)
+ manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0;
+
/* Retrieve the MCU's page size, in bytes. This is also the size of the
* entire User Row. */
uint32_t page_size;
@@ -559,8 +568,8 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
if (!buf)
return ERROR_FAIL;
- /* Read the user row (comprising one page) by half-words. */
- res = target_read_memory(target, SAMD_USER_ROW, 2, page_size / 2, buf);
+ /* Read the user row (comprising one page) by words. */
+ res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
if (res != ERROR_OK)
goto out_user_row;
@@ -579,20 +588,18 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
/* Modify */
buf_set_u32(buf, startb, endb - startb + 1, value);
- /* Write the page buffer back out to the target. A Flash write will be
- * triggered automatically. */
+ /* Write the page buffer back out to the target. */
res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
if (res != ERROR_OK)
goto out_user_row;
- if (samd_check_error(target)) {
- res = ERROR_FAIL;
- goto out_user_row;
+ if (manual_wp) {
+ /* Trigger flash write */
+ res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_WAP);
+ } else {
+ res = samd_check_error(target);
}
- /* Success */
- res = ERROR_OK;
-
out_user_row:
free(buf);
@@ -784,18 +791,15 @@ static int samd_write(struct flash_bank *bank, const uint8_t *buffer,
* then issue CMD_WP always */
if (manual_wp || pg_offset + 4 * nw < chip->page_size) {
res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_WP);
- if (res != ERROR_OK) {
- LOG_ERROR("%s: %d", __func__, __LINE__);
- goto free_pb;
- }
- }
+ } else {
+ /* Access through AHB is stalled while flash is being programmed */
+ usleep(200);
- /* Access through AHB is stalled while flash is being programmed */
- usleep(200);
+ res = samd_check_error(bank->target);
+ }
- if (samd_check_error(bank->target)) {
+ if (res != ERROR_OK) {
LOG_ERROR("%s: write failed at address 0x%08" PRIx32, __func__, address);
- res = ERROR_FAIL;
goto free_pb;
}
@@ -856,18 +860,23 @@ COMMAND_HANDLER(samd_handle_info_command)
COMMAND_HANDLER(samd_handle_chip_erase_command)
{
struct target *target = get_current_target(CMD_CTX);
+ int res = ERROR_FAIL;
if (target) {
/* Enable access to the DSU by disabling the write protect bit */
target_write_u32(target, SAMD_PAC1, (1<<1));
+ /* intentionally without error checking - not accessible on secured chip */
+
/* Tell the DSU to perform a full chip erase. It takes about 240ms to
* perform the erase. */
- target_write_u8(target, SAMD_DSU, (1<<4));
-
- command_print(CMD_CTX, "chip erased");
+ res = target_write_u8(target, SAMD_DSU + SAMD_DSU_CTRL_EXT, (1<<4));
+ if (res == ERROR_OK)
+ command_print(CMD_CTX, "chip erase started");
+ else
+ command_print(CMD_CTX, "write to DSU CTRL failed");
}
- return ERROR_OK;
+ return res;
}
COMMAND_HANDLER(samd_handle_set_security_command)
@@ -1018,10 +1027,15 @@ COMMAND_HANDLER(samd_handle_bootloader_command)
COMMAND_HANDLER(samd_handle_reset_deassert)
{
struct target *target = get_current_target(CMD_CTX);
- struct armv7m_common *armv7m = target_to_armv7m(target);
int retval = ERROR_OK;
enum reset_types jtag_reset_config = jtag_get_reset_config();
+ /* If the target has been unresponsive before, try to re-establish
+ * communication now - CPU is held in reset by DSU, DAP is working */
+ if (!target_was_examined(target))
+ target_examine_one(target);
+ target_poll(target);
+
/* In case of sysresetreq, debug retains state set in cortex_m_assert_reset()
* so we just release reset held by DSU
*
@@ -1030,9 +1044,9 @@ COMMAND_HANDLER(samd_handle_reset_deassert)
* After vectreset DSU release is not needed however makes no harm
*/
if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) {
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
+ retval = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
if (retval == ERROR_OK)
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR,
+ retval = target_write_u32(target, DCB_DEMCR,
TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
/* do not return on error here, releasing DSU reset is more important */
}
diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c
new file mode 100644
index 0000000..451e843
--- /dev/null
+++ b/src/flash/nor/ath79.c
@@ -0,0 +1,901 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Tobias Diedrich *
+ * <ranma+openwrt@tdiedrich.de> *
+ * *
+ * based on the stmsmi code written by Antonio Borneo *
+ * <borneo.antonio@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 *
+ * (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, write to the *
+ * Free Software Foundation, Inc. *
+ * *
+ ***************************************************************************/
+/*
+ * Driver for the Atheros AR7xxx/AR9xxx SPI flash interface.
+ *
+ * Since no SPI mode register is present, presumably only
+ * SPI "mode 3" (CPOL=1 and CPHA=1) is supported.
+ *
+ * The SPI interface supports up to 3 chip selects, however the SPI flash
+ * used for booting the system must be connected to CS0.
+ *
+ * On boot, the first 4MiB of flash space are memory-mapped into the
+ * area bf000000 - bfffffff (4 copies), so the MIPS bootstrap
+ * vector bfc00000 is mapped to the beginning of the flash.
+ *
+ * By writing a 1 to the REMAP_DISABLE bit in the SPI_CONTROL register,
+ * the full area of 16MiB is mapped.
+ *
+ * By writing a 0 to the SPI_FUNCTION_SELECT register (write-only dword
+ * register @bf000000), memory mapping is disabled and the SPI registers
+ * are exposed to the CPU instead:
+ * bf000000 SPI_FUNCTION_SELECT
+ * bf000004 SPI_CONTROL
+ * bf000008 SPI_IO_CONTROL
+ * bf00000c SPI_READ_DATA
+ *
+ * When not memory-mapped, the SPI interface is essentially bitbanged
+ * using SPI_CONTROL and SPI_IO_CONTROL with the only hardware-assistance
+ * being the 32bit read-only shift-register SPI_READ_DATA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "spi.h"
+#include <jtag/jtag.h>
+#include <helper/time_support.h>
+#include <helper/types.h>
+#include <target/mips32.h>
+#include <target/mips32_pracc.h>
+#include <target/target.h>
+
+#define BITS_PER_BYTE 8
+
+#define ATH79_REG_FS 0
+#define ATH79_REG_CLOCK 4
+#define ATH79_REG_WRITE 8
+#define ATH79_REG_DATA 12
+
+#define ATH79_SPI_CS_ALLHI 0x70000
+#define ATH79_SPI_CS0_HI 0x10000
+#define ATH79_SPI_CS1_HI 0x20000
+#define ATH79_SPI_CS2_HI 0x40000
+#define ATH79_SPI_CE_HI 0x00100
+#define ATH79_SPI_DO_HI 0x00001
+
+#define ATH79_XFER_FINAL 0x00000001
+#define ATH79_XFER_PARTIAL 0x00000000
+
+/* Timeout in ms */
+#define ATH79_MAX_TIMEOUT (3000)
+
+struct ath79_spi_ctx {
+ uint8_t *page_buf;
+ int pre_deselect;
+ int post_deselect;
+};
+
+struct ath79_flash_bank {
+ int probed;
+ int chipselect;
+ uint32_t io_base;
+ const struct flash_device *dev;
+ struct ath79_spi_ctx spi;
+};
+
+struct ath79_target {
+ char *name;
+ uint32_t tap_idcode;
+ uint32_t io_base;
+};
+
+static const struct ath79_target target_devices[] = {
+ /* name, tap_idcode, io_base */
+ { "ATH79", 0x00000001, 0xbf000000 },
+ { NULL, 0, 0 }
+};
+
+static const uint32_t ath79_chipselects[] = {
+ (~ATH79_SPI_CS0_HI & ATH79_SPI_CS_ALLHI),
+ (~ATH79_SPI_CS1_HI & ATH79_SPI_CS_ALLHI),
+ (~ATH79_SPI_CS2_HI & ATH79_SPI_CS_ALLHI),
+};
+
+static void ath79_pracc_addn(struct pracc_queue_info *ctx,
+ const uint32_t *instr,
+ int n)
+{
+ for (int i = 0; i < n; i++)
+ pracc_add(ctx, 0, instr[i]);
+}
+
+static int ath79_spi_bitbang_codegen(struct ath79_flash_bank *ath79_info,
+ struct pracc_queue_info *ctx,
+ uint8_t *data, int len,
+ int partial_xfer)
+{
+ uint32_t cs_high = ATH79_SPI_CS_ALLHI;
+ uint32_t cs_low = ath79_chipselects[ath79_info->chipselect];
+ uint32_t clock_high = cs_low | ATH79_SPI_CE_HI;
+ uint32_t clock_low = cs_low;
+ uint32_t pracc_out = 0;
+ uint32_t io_base = ath79_info->io_base;
+
+ const uint32_t preamble1[] = {
+ /* $15 = MIPS32_PRACC_BASE_ADDR */
+ MIPS32_LUI(0, 15, PRACC_UPPER_BASE_ADDR),
+ /* $1 = io_base */
+ MIPS32_LUI(0, 1, UPPER16(io_base)),
+ };
+ ath79_pracc_addn(ctx, preamble1, ARRAY_SIZE(preamble1));
+ if (ath79_info->spi.pre_deselect) {
+ /* Clear deselect flag so we don't deselect again if
+ * this is a partial xfer.
+ */
+ ath79_info->spi.pre_deselect = 0;
+ const uint32_t pre_deselect[] = {
+ /* [$1 + FS] = 1 (enable flash io register access) */
+ MIPS32_LUI(0, 2, UPPER16(1)),
+ MIPS32_ORI(0, 2, 2, LOWER16(1)),
+ MIPS32_SW(0, 2, ATH79_REG_FS, 1),
+ /* deselect flash just in case */
+ /* $2 = SPI_CS_DIS */
+ MIPS32_LUI(0, 2, UPPER16(cs_high)),
+ MIPS32_ORI(0, 2, 2, LOWER16(cs_high)),
+ /* [$1 + WRITE] = $2 */
+ MIPS32_SW(0, 2, ATH79_REG_WRITE, 1),
+ };
+ ath79_pracc_addn(ctx, pre_deselect, ARRAY_SIZE(pre_deselect));
+ }
+ const uint32_t preamble2[] = {
+ /* t0 = CLOCK_LOW + 0-bit */
+ MIPS32_LUI(0, 8, UPPER16((clock_low + 0))),
+ MIPS32_ORI(0, 8, 8, LOWER16((clock_low + 0))),
+ /* t1 = CLOCK_LOW + 1-bit */
+ MIPS32_LUI(0, 9, UPPER16((clock_low + 1))),
+ MIPS32_ORI(0, 9, 9, LOWER16((clock_low + 1))),
+ /* t2 = CLOCK_HIGH + 0-bit */
+ MIPS32_LUI(0, 10, UPPER16((clock_high + 0))),
+ MIPS32_ORI(0, 10, 10, LOWER16((clock_high + 0))),
+ /* t3 = CLOCK_HIGH + 1-bit */
+ MIPS32_LUI(0, 11, UPPER16((clock_high + 1))),
+ MIPS32_ORI(0, 11, 11, LOWER16((clock_high + 1))),
+ };
+ ath79_pracc_addn(ctx, preamble2, ARRAY_SIZE(preamble2));
+
+ for (int i = 0; i < len; i++) {
+ uint8_t x = data[i];
+
+ /* Generate bitbang code for one byte, highest bit first .*/
+ for (int j = BITS_PER_BYTE - 1; j >= 0; j--) {
+ int bit = ((x >> j) & 1);
+
+ if (bit) {
+ /* [$1 + WRITE] = t1 */
+ pracc_add(ctx, 0,
+ MIPS32_SW(0, 9, ATH79_REG_WRITE, 1));
+ /* [$1 + WRITE] = t3 */
+ pracc_add(ctx, 0,
+ MIPS32_SW(0, 11, ATH79_REG_WRITE, 1));
+ } else {
+ /* [$1 + WRITE] = t0 */
+ pracc_add(ctx, 0,
+ MIPS32_SW(0, 8, ATH79_REG_WRITE, 1));
+ /* [$1 + WRITE] = t2 */
+ pracc_add(ctx, 0,
+ MIPS32_SW(0, 10, ATH79_REG_WRITE, 1));
+ }
+ }
+ if (i % 4 == 3) {
+ /* $3 = [$1 + DATA] */
+ pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1));
+ /* [OUTi] = $3 */
+ pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out,
+ MIPS32_SW(0, 3, PRACC_OUT_OFFSET +
+ pracc_out, 15));
+ pracc_out += 4;
+ }
+ }
+ if (len & 3) { /* not a multiple of 4 bytes */
+ /* $3 = [$1 + DATA] */
+ pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1));
+ /* [OUTi] = $3 */
+ pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out,
+ MIPS32_SW(0, 3, PRACC_OUT_OFFSET + pracc_out, 15));
+ pracc_out += 4;
+ }
+
+ if (ath79_info->spi.post_deselect && !partial_xfer) {
+ const uint32_t post_deselect[] = {
+ /* $2 = SPI_CS_DIS */
+ MIPS32_LUI(0, 2, UPPER16(cs_high)),
+ MIPS32_ORI(0, 2, 2, LOWER16(cs_high)),
+ /* [$1 + WRITE] = $2 */
+ MIPS32_SW(0, 2, ATH79_REG_WRITE, 1),
+
+ /* [$1 + FS] = 0 (disable flash io register access) */
+ MIPS32_XORI(0, 2, 2, 0),
+ MIPS32_SW(0, 2, ATH79_REG_FS, 1),
+ };
+ ath79_pracc_addn(ctx, post_deselect, ARRAY_SIZE(post_deselect));
+ }
+
+ /* common pracc epilogue */
+ /* jump to start */
+ pracc_add(ctx, 0, MIPS32_B(0, NEG16(ctx->code_count + 1)));
+ /* restore $15 from DeSave */
+ pracc_add(ctx, 0, MIPS32_MFC0(0, 15, 31, 0));
+
+ return pracc_out / 4;
+}
+
+static int ath79_spi_bitbang_chunk(struct flash_bank *bank,
+ uint8_t *data, int len, int *transferred)
+{
+ struct target *target = bank->target;
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+ struct mips32_common *mips32 = target_to_mips32(target);
+ struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+ int pracc_words;
+
+ /*
+ * These constants must match the worst case in the above code
+ * generator function ath79_spi_bitbang_codegen.
+ */
+ const int pracc_pre_post = 26;
+ const int pracc_loop_byte = 8 * 2 + 2;
+
+ struct pracc_queue_info ctx = {
+ .ejtag_info = ejtag_info
+ };
+ int max_len = (PRACC_MAX_INSTRUCTIONS - pracc_pre_post) / pracc_loop_byte;
+ int to_xfer = len > max_len ? max_len : len;
+ int partial_xfer = len != to_xfer;
+ int padded_len = (to_xfer + 3) & ~3;
+ uint32_t *out = malloc(padded_len);
+
+ if (!out) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ *transferred = 0;
+ pracc_queue_init(&ctx);
+
+ LOG_DEBUG("ath79_spi_bitbang_bytes(%p, %08x, %p, %d)",
+ target, ath79_info->io_base, data, len);
+
+ LOG_DEBUG("max code %d => max len %d. to_xfer %d",
+ PRACC_MAX_INSTRUCTIONS, max_len, to_xfer);
+
+ pracc_words = ath79_spi_bitbang_codegen(
+ ath79_info, &ctx, data, to_xfer, partial_xfer);
+
+ LOG_DEBUG("Assembled %d instructions, %d stores",
+ ctx.code_count, ctx.store_count);
+
+ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, out, 1);
+ if (ctx.retval != ERROR_OK)
+ goto exit;
+
+ if (to_xfer & 3) { /* Not a multiple of 4 bytes. */
+ /*
+ * Need to realign last word since we didn't shift the
+ * full 32 bits.
+ */
+ int missed_bytes = 4 - (to_xfer & 3);
+
+ out[pracc_words - 1] <<= BITS_PER_BYTE * missed_bytes;
+ }
+
+ /*
+ * pracc reads return uint32_t in host endianness, convert to
+ * target endianness.
+ * Since we know the ATH79 target is big endian and the SPI
+ * shift register has the bytes in highest to lowest bit order,
+ * this will ensure correct memory byte order regardless of host
+ * endianness.
+ */
+ target_buffer_set_u32_array(target, (uint8_t *)out, pracc_words, out);
+
+ if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) {
+ for (int i = 0; i < to_xfer; i++) {
+ LOG_DEBUG("bitbang %02x => %02x",
+ data[i], ((uint8_t *)out)[i]);
+ }
+ }
+ memcpy(data, out, to_xfer);
+ *transferred = to_xfer;
+
+exit:
+ pracc_queue_free(&ctx);
+ free(out);
+ return ctx.retval;
+}
+
+static void ath79_spi_bitbang_prepare(struct flash_bank *bank)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+
+ ath79_info->spi.pre_deselect = 1;
+}
+
+static int ath79_spi_bitbang_bytes(struct flash_bank *bank,
+ uint8_t *data, int len, uint32_t flags)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+ int retval;
+ int transferred;
+
+ ath79_info->spi.post_deselect = !!(flags & ATH79_XFER_FINAL);
+
+ do {
+ transferred = 0;
+ retval = ath79_spi_bitbang_chunk(
+ bank, data, len, &transferred);
+ if (retval != ERROR_OK)
+ return retval;
+
+ data += transferred;
+ len -= transferred;
+ } while (len > 0);
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(ath79_flash_bank_command)
+{
+ struct ath79_flash_bank *ath79_info;
+ int chipselect = 0;
+
+ LOG_DEBUG("%s", __func__);
+
+ if (CMD_ARGC < 6 || CMD_ARGC > 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 7) {
+ if (strcmp(CMD_ARGV[6], "cs0") == 0)
+ chipselect = 0; /* default */
+ else if (strcmp(CMD_ARGV[6], "cs1") == 0)
+ chipselect = 1;
+ else if (strcmp(CMD_ARGV[6], "cs2") == 0)
+ chipselect = 2;
+ else {
+ LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ }
+
+ ath79_info = calloc(1, sizeof(struct ath79_flash_bank));
+ if (!ath79_info) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ ath79_info->chipselect = chipselect;
+ bank->driver_priv = ath79_info;
+
+ return ERROR_OK;
+}
+
+/* Read the status register of the external SPI flash chip. */
+static int read_status_reg(struct flash_bank *bank, uint32_t *status)
+{
+ uint8_t spi_bytes[] = {SPIFLASH_READ_STATUS, 0};
+ int retval;
+
+ /* Send SPI command "read STATUS" */
+ ath79_spi_bitbang_prepare(bank);
+ retval = ath79_spi_bitbang_bytes(
+ bank, spi_bytes, sizeof(spi_bytes),
+ ATH79_XFER_FINAL);
+
+ *status = spi_bytes[1];
+
+ return retval;
+}
+
+/* check for WIP (write in progress) bit in status register */
+/* timeout in ms */
+static int wait_till_ready(struct flash_bank *bank, int timeout)
+{
+ uint32_t status;
+ int retval;
+ long long endtime;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ /* read flash status register */
+ retval = read_status_reg(bank, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((status & SPIFLASH_BSY_BIT) == 0)
+ return ERROR_OK;
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_FAIL;
+}
+
+/* Send "write enable" command to SPI flash chip. */
+static int ath79_write_enable(struct flash_bank *bank)
+{
+ uint32_t status;
+ int retval;
+
+ uint8_t spi_bytes[] = {SPIFLASH_WRITE_ENABLE};
+
+ /* Send SPI command "write enable" */
+ ath79_spi_bitbang_prepare(bank);
+ retval = ath79_spi_bitbang_bytes(
+ bank, spi_bytes, sizeof(spi_bytes),
+ ATH79_XFER_FINAL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* read flash status register */
+ retval = read_status_reg(bank, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Check write enabled */
+ if ((status & SPIFLASH_WE_BIT) == 0) {
+ LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32,
+ status);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int erase_command(struct flash_bank *bank, int sector)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+ uint32_t offset = bank->sectors[sector].offset;
+
+ uint8_t spi_bytes[] = {
+ ath79_info->dev->erase_cmd,
+ offset >> 16,
+ offset >> 8,
+ offset
+ };
+
+ /* bitbang command */
+ ath79_spi_bitbang_prepare(bank);
+ return ath79_spi_bitbang_bytes(
+ bank, spi_bytes, sizeof(spi_bytes),
+ ATH79_XFER_FINAL);
+}
+
+static int ath79_erase_sector(struct flash_bank *bank, int sector)
+{
+ int retval = ath79_write_enable(bank);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* send SPI command "block erase" */
+ retval = erase_command(bank, sector);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* poll WIP for end of self timed Sector Erase cycle */
+ return wait_till_ready(bank, ATH79_MAX_TIMEOUT);
+}
+
+static int ath79_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct ath79_flash_bank *ath79_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 (!ath79_info->probed) {
+ LOG_ERROR("Flash bank not probed");
+ return ERROR_FLASH_BANK_NOT_PROBED;
+ }
+
+ 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 = ath79_erase_sector(bank, sector);
+ if (retval != ERROR_OK)
+ break;
+ keep_alive();
+ }
+
+ return retval;
+}
+
+static int ath79_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 ath79_write_page(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t address, uint32_t len)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+ uint8_t spi_bytes[] = {
+ SPIFLASH_PAGE_PROGRAM,
+ address >> 16,
+ address >> 8,
+ address,
+ };
+ int retval;
+ uint32_t i;
+
+ if (address & 0xff) {
+ LOG_ERROR("ath79_write_page: unaligned write address: %08x",
+ address);
+ return ERROR_FAIL;
+ }
+ if (!ath79_info->spi.page_buf) {
+ LOG_ERROR("ath79_write_page: page buffer not initialized");
+ return ERROR_FAIL;
+ }
+ if (len > ath79_info->dev->pagesize) {
+ LOG_ERROR("ath79_write_page: len bigger than page size %d: %d",
+ ath79_info->dev->pagesize, len);
+ return ERROR_FAIL;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (buffer[i] != 0xff)
+ break;
+ }
+ if (i == len) /* all 0xff, no need to program. */
+ return ERROR_OK;
+
+ LOG_INFO("writing %d bytes to flash page @0x%08x", len, address);
+
+ memcpy(ath79_info->spi.page_buf, buffer, len);
+
+ /* unlock writes */
+ retval = ath79_write_enable(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* bitbang command */
+ ath79_spi_bitbang_prepare(bank);
+ retval = ath79_spi_bitbang_bytes(
+ bank, spi_bytes, sizeof(spi_bytes),
+ ATH79_XFER_PARTIAL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* write data */
+ return ath79_spi_bitbang_bytes(
+ bank, ath79_info->spi.page_buf, len,
+ ATH79_XFER_FINAL);
+}
+
+static int ath79_write_buffer(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t address, uint32_t len)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+ const uint32_t page_size = ath79_info->dev->pagesize;
+ int retval;
+
+ LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32,
+ __func__, address, len);
+
+ while (len > 0) {
+ int page_len = len > page_size ? page_size : len;
+
+ retval = ath79_write_page(
+ bank, buffer, address, page_len);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += page_size;
+ address += page_size;
+ len -= page_len;
+ }
+
+ return ERROR_OK;
+}
+
+static int ath79_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ int sector;
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (offset < bank->base || offset >= bank->base + bank->size) {
+ LOG_ERROR("Start address out of range");
+ return ERROR_FAIL;
+ }
+
+ offset -= bank->base;
+
+ 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;
+ }
+
+ /* 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;
+ }
+ }
+
+ return ath79_write_buffer(bank, buffer, offset, count);
+}
+
+static int ath79_read_buffer(struct flash_bank *bank, uint8_t *buffer,
+ uint32_t address, uint32_t len)
+{
+ uint8_t spi_bytes[] = {
+ SPIFLASH_READ,
+ address >> 16,
+ address >> 8,
+ address,
+ };
+ int retval;
+
+ LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32,
+ __func__, address, len);
+
+ if (address & 0xff) {
+ LOG_ERROR("ath79_read_buffer: unaligned read address: %08x",
+ address);
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("reading %d bytes from flash @0x%08x", len, address);
+
+ /* bitbang command */
+ ath79_spi_bitbang_prepare(bank);
+ retval = ath79_spi_bitbang_bytes(
+ bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_PARTIAL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* read data */
+ return ath79_spi_bitbang_bytes(
+ bank, buffer, len, ATH79_XFER_FINAL);
+}
+
+static int ath79_read(struct flash_bank *bank, uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (offset < bank->base || offset >= bank->base + bank->size) {
+ LOG_ERROR("Start address out of range");
+ return ERROR_FAIL;
+ }
+
+ offset -= bank->base;
+
+ 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;
+ }
+
+ return ath79_read_buffer(bank, buffer, offset, count);
+}
+
+/* Return ID of flash device */
+static int read_flash_id(struct flash_bank *bank, uint32_t *id)
+{
+ struct target *target = bank->target;
+ int retval;
+ uint8_t spi_bytes[] = {SPIFLASH_READ_ID, 0, 0, 0};
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Send SPI command "read ID" */
+ ath79_spi_bitbang_prepare(bank);
+ retval = ath79_spi_bitbang_bytes(
+ bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_FINAL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *id = (spi_bytes[1] << 0)
+ | (spi_bytes[2] << 8)
+ | (spi_bytes[3] << 16);
+
+ if (*id == 0xffffff) {
+ LOG_ERROR("No SPI flash found");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int ath79_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+ struct flash_sector *sectors;
+ uint32_t id = 0; /* silence uninitialized warning */
+ const struct ath79_target *target_device;
+ int retval;
+
+ if (ath79_info->probed) {
+ free(bank->sectors);
+ free(ath79_info->spi.page_buf);
+ }
+ ath79_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;
+ }
+
+ ath79_info->io_base = target_device->io_base;
+
+ LOG_DEBUG("Found device %s at address 0x%" PRIx32,
+ target_device->name, bank->base);
+
+ retval = read_flash_id(bank, &id);
+ if (retval != ERROR_OK)
+ return retval;
+
+ ath79_info->dev = NULL;
+ for (const struct flash_device *p = flash_devices; p->name; p++)
+ if (p->device_id == id) {
+ ath79_info->dev = p;
+ break;
+ }
+
+ if (!ath79_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 ")",
+ ath79_info->dev->name, ath79_info->dev->device_id);
+
+ /* Set correct size value */
+ bank->size = ath79_info->dev->size_in_bytes;
+
+ /* create and fill sectors array */
+ bank->num_sectors =
+ ath79_info->dev->size_in_bytes / ath79_info->dev->sectorsize;
+ sectors = calloc(1, sizeof(struct flash_sector) * bank->num_sectors);
+ if (!sectors) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+ ath79_info->spi.page_buf = malloc(ath79_info->dev->pagesize);
+ if (!ath79_info->spi.page_buf) {
+ LOG_ERROR("not enough memory");
+ free(sectors);
+ return ERROR_FAIL;
+ }
+
+ for (int sector = 0; sector < bank->num_sectors; sector++) {
+ sectors[sector].offset = sector * ath79_info->dev->sectorsize;
+ sectors[sector].size = ath79_info->dev->sectorsize;
+ sectors[sector].is_erased = 0;
+ sectors[sector].is_protected = 1;
+ }
+
+ bank->sectors = sectors;
+ ath79_info->probed = 1;
+ return ERROR_OK;
+}
+
+static int ath79_auto_probe(struct flash_bank *bank)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+
+ if (ath79_info->probed)
+ return ERROR_OK;
+ return ath79_probe(bank);
+}
+
+static int ath79_flash_blank_check(struct flash_bank *bank)
+{
+ /* Not implemented */
+ return ERROR_OK;
+}
+
+static int ath79_protect_check(struct flash_bank *bank)
+{
+ /* Not implemented */
+ return ERROR_OK;
+}
+
+static int get_ath79_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct ath79_flash_bank *ath79_info = bank->driver_priv;
+
+ if (!ath79_info->probed) {
+ snprintf(buf, buf_size,
+ "\nATH79 flash bank not probed yet\n");
+ return ERROR_OK;
+ }
+
+ snprintf(buf, buf_size, "\nATH79 flash information:\n"
+ " Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+ ath79_info->dev->name, ath79_info->dev->device_id);
+
+ return ERROR_OK;
+}
+
+struct flash_driver ath79_flash = {
+ .name = "ath79",
+ .flash_bank_command = ath79_flash_bank_command,
+ .erase = ath79_erase,
+ .protect = ath79_protect,
+ .write = ath79_write,
+ .read = ath79_read,
+ .probe = ath79_probe,
+ .auto_probe = ath79_auto_probe,
+ .erase_check = ath79_flash_blank_check,
+ .protect_check = ath79_protect_check,
+ .info = get_ath79_info,
+};
diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c
index d21419d..73f0238 100644
--- a/src/flash/nor/atsamv.c
+++ b/src/flash/nor/atsamv.c
@@ -363,6 +363,9 @@ static int samv_probe(struct flash_bank *bank)
uint8_t nvm_size_code = (device_id >> 8) & 0xf;
switch (nvm_size_code) {
+ case 10:
+ bank->size = 512 * 1024;
+ break;
case 12:
bank->size = 1024 * 1024;
break;
diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c
index 627418c..11cc3b2 100644
--- a/src/flash/nor/avrf.c
+++ b/src/flash/nor/avrf.c
@@ -66,6 +66,7 @@ static const struct avrf_type avft_chips_info[] = {
* eeprom_page_size, eeprom_page_num
*/
{"atmega128", 0x9702, 256, 512, 8, 512},
+ {"atmega128rfa1", 0xa701, 128, 512, 8, 512},
{"at90can128", 0x9781, 256, 512, 8, 512},
{"at90usb128", 0x9782, 256, 512, 8, 512},
{"atmega164p", 0x940a, 128, 128, 4, 128},
diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c
index f7d8a90..ac0db82 100644
--- a/src/flash/nor/cfi.c
+++ b/src/flash/nor/cfi.c
@@ -1312,7 +1312,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, const uint8_t *buffer,
busy_pattern_val = cfi_command_val(bank, 0x80);
error_pattern_val = cfi_command_val(bank, 0x7e);
- LOG_DEBUG("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32,
+ LOG_DEBUG("Using target buffer at " TARGET_ADDR_FMT " and of size 0x%04" PRIx32,
source->address, buffer_size);
/* Programming main loop */
@@ -1424,50 +1424,50 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t
static const uint32_t mips_word_16_code[] = {
/* start: */
- MIPS32_LHU(9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */
- MIPS32_ADDI(4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */
- MIPS32_SH(13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */
- MIPS32_SH(15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */
- MIPS32_SH(7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */
- MIPS32_SH(9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */
+ MIPS32_LHU(0, 9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */
+ MIPS32_ADDI(0, 4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */
+ MIPS32_SH(0, 13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */
+ MIPS32_SH(0, 15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */
+ MIPS32_SH(0, 7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */
+ MIPS32_SH(0, 9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */
MIPS32_NOP, /* nop */
/* busy: */
- MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */
- MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */
- MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */
- MIPS32_BNE(11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */
- MIPS32_NOP, /* nop */
-
- MIPS32_SRL(10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */
- MIPS32_AND(11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */
- MIPS32_BNE(11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */
- MIPS32_NOP, /* nop */
-
- MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */
- MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */
- MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */
- MIPS32_BNE(11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */
+ MIPS32_LHU(0, 10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */
+ MIPS32_XOR(0, 11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */
+ MIPS32_AND(0, 11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */
+ MIPS32_BNE(0, 11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */
+ MIPS32_NOP, /* nop */
+
+ MIPS32_SRL(0, 10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */
+ MIPS32_AND(0, 11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */
+ MIPS32_BNE(0, 11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */
+ MIPS32_NOP, /* nop */
+
+ MIPS32_LHU(0, 10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */
+ MIPS32_XOR(0, 11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */
+ MIPS32_AND(0, 11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */
+ MIPS32_BNE(0, 11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */
MIPS32_NOP, /* nop */
- MIPS32_XOR(9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */
- MIPS32_BEQ(9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */
+ MIPS32_XOR(0, 9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */
+ MIPS32_BEQ(0, 9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */
MIPS32_NOP, /* nop */
/* cont: */
- MIPS32_ADDI(6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */
- MIPS32_BNE(6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */
+ MIPS32_ADDI(0, 6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */
+ MIPS32_BNE(0, 6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */
MIPS32_NOP, /* nop */
- MIPS32_LUI(9, 0), /* lui $t1, 0 */
- MIPS32_ORI(9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */
+ MIPS32_LUI(0, 9, 0), /* lui $t1, 0 */
+ MIPS32_ORI(0, 9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */
- MIPS32_B(4), /* b done ; goto done */
+ MIPS32_B(0, 4), /* b done ; goto done */
MIPS32_NOP, /* nop */
/* cont2: */
- MIPS32_ADDI(5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */
- MIPS32_B(NEG16(33)), /* b start ; goto start */
+ MIPS32_ADDI(0, 5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */
+ MIPS32_B(0, NEG16(33)), /* b start ; goto start */
MIPS32_NOP, /* nop */
/* done: */
- MIPS32_SDBBP, /* sdbbp ; break(); */
+ MIPS32_SDBBP(0), /* sdbbp ; break(); */
};
mips32_info.common_magic = MIPS32_COMMON_MAGIC;
diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c
index 7a62ba1..ab69a32 100644
--- a/src/flash/nor/core.c
+++ b/src/flash/nor/core.c
@@ -50,10 +50,17 @@ int flash_driver_erase(struct flash_bank *bank, int first, int last)
int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
{
int retval;
+ int num_blocks;
+
+ if (bank->num_prot_blocks)
+ num_blocks = bank->num_prot_blocks;
+ else
+ num_blocks = bank->num_sectors;
+
/* callers may not supply illegal parameters ... */
- if (first < 0 || first > last || last >= bank->num_sectors) {
- LOG_ERROR("illegal sector range");
+ if (first < 0 || first > last || last >= num_blocks) {
+ LOG_ERROR("illegal protection block range");
return ERROR_FAIL;
}
@@ -69,11 +76,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
* the target could have reset, power cycled, been hot plugged,
* the application could have run, etc.
*
- * Drivers only receive valid sector range.
+ * Drivers only receive valid protection block range.
*/
retval = bank->driver->protect(bank, set, first, last);
if (retval != ERROR_OK)
- LOG_ERROR("failed setting protection for areas %d to %d", first, last);
+ LOG_ERROR("failed setting protection for blocks %d to %d", first, last);
return retval;
}
@@ -288,7 +295,7 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
goto done;
for (nBytes = 0; nBytes < chunk; nBytes++) {
- if (buffer[nBytes] != 0xFF) {
+ if (buffer[nBytes] != bank->erased_value) {
bank->sectors[i].is_erased = 0;
break;
}
@@ -319,12 +326,12 @@ int default_flash_blank_check(struct flash_bank *bank)
uint32_t address = bank->base + bank->sectors[i].offset;
uint32_t size = bank->sectors[i].size;
- retval = target_blank_check_memory(target, address, size, &blank);
+ retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value);
if (retval != ERROR_OK) {
fast_check = 0;
break;
}
- if (blank == 0xFF)
+ if (blank == bank->erased_value)
bank->sectors[i].is_erased = 1;
else
bank->sectors[i].is_erased = 0;
diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h
index 60d4483..338363e 100644
--- a/src/flash/nor/core.h
+++ b/src/flash/nor/core.h
@@ -90,6 +90,9 @@ struct flash_bank {
int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
+ /** Erased value. Defaults to 0xFF. */
+ uint8_t erased_value;
+
/** Default padded value used, normally this matches the flash
* erased value. Defaults to 0xFF. */
uint8_t default_padded_value;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index e7b6a88..56b451c 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -28,6 +28,7 @@ extern struct flash_driver at91sam4_flash;
extern struct flash_driver at91sam4l_flash;
extern struct flash_driver at91sam7_flash;
extern struct flash_driver at91samd_flash;
+extern struct flash_driver ath79_flash;
extern struct flash_driver atsamv_flash;
extern struct flash_driver avr_flash;
extern struct flash_driver cfi_flash;
@@ -81,6 +82,7 @@ static struct flash_driver *flash_drivers[] = {
&at91sam4l_flash,
&at91sam7_flash,
&at91samd_flash,
+ &ath79_flash,
&atsamv_flash,
&avr_flash,
&cfi_flash,
diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c
index 0b33829..81c1a37 100644
--- a/src/flash/nor/efm32.c
+++ b/src/flash/nor/efm32.c
@@ -456,10 +456,10 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
uint32_t *ptr = NULL;
int ret = 0;
- assert(!(bank->num_sectors & 0x1f));
+ assert(bank->num_sectors > 0);
- data_size = bank->num_sectors / 8; /* number of data bytes */
- data_size /= 4; /* ...and data dwords */
+ /* calculate the number of 32-bit words to read (one lock bit per sector) */
+ data_size = (bank->num_sectors + 31) / 32;
ptr = efm32x_info->lb_page;
diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c
index 1501562..a11743b 100644
--- a/src/flash/nor/em357.c
+++ b/src/flash/nor/em357.c
@@ -702,6 +702,11 @@ static int em357_probe(struct flash_bank *bank)
num_pages = 128;
page_size = 2048;
break;
+ case 0x80000:
+ /* 512k -- 256 2k pages */
+ num_pages = 256;
+ page_size = 2048;
+ break;
default:
LOG_WARNING("No size specified for em357 flash driver, assuming 192k!");
num_pages = 96;
diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c
index c348c1d..c8fe8b6 100644
--- a/src/flash/nor/fm4.c
+++ b/src/flash/nor/fm4.c
@@ -272,7 +272,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2);
uint32_t addr = bank->base + offset;
- LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
+ LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" TARGET_PRIxADDR,
MIN(halfwords * 2, byte_count), data_workarea->address);
retval = target_write_buffer(target, data_workarea->address,
diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c
index e9cf8fa..7e9bbde 100644
--- a/src/flash/nor/kinetis.c
+++ b/src/flash/nor/kinetis.c
@@ -102,6 +102,7 @@
#define WDOG_STCTRH 0x40052000
#define SMC_PMCTRL 0x4007E001
#define SMC_PMSTAT 0x4007E003
+#define MCM_PLACR 0xF000300C
/* Values */
#define PM_STAT_RUN 0x01
@@ -206,6 +207,7 @@
#define KINETIS_SDID_FAMILYID_K4X 0x40000000
#define KINETIS_SDID_FAMILYID_K6X 0x60000000
#define KINETIS_SDID_FAMILYID_K7X 0x70000000
+#define KINETIS_SDID_FAMILYID_K8X 0x80000000
struct kinetis_flash_bank {
bool probed;
@@ -231,7 +233,8 @@ struct kinetis_flash_bank {
FS_PROGRAM_SECTOR = 1,
FS_PROGRAM_LONGWORD = 2,
FS_PROGRAM_PHRASE = 4, /* Unsupported */
- FS_INVALIDATE_CACHE = 8,
+ FS_INVALIDATE_CACHE_K = 8,
+ FS_INVALIDATE_CACHE_L = 0x10,
} flash_support;
};
@@ -609,6 +612,9 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
return ERROR_OK;
}
+ if (!dap->ops)
+ return ERROR_OK; /* too early to check, in JTAG mode ops may not be initialised */
+
uint32_t val;
int retval;
@@ -623,7 +629,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
}
if (val == 0)
- return ERROR_OK;
+ return ERROR_OK; /* dap not yet initialised */
bool found = false;
for (size_t i = 0; i < ARRAY_SIZE(kinetis_known_mdm_ids); i++) {
@@ -862,65 +868,7 @@ static int kinetis_ftfx_prepare(struct target *target)
/* Kinetis Program-LongWord Microcodes */
static const uint8_t kinetis_flash_write_code[] = {
- /* Params:
- * r0 - workarea buffer
- * r1 - target address
- * r2 - wordcount
- * Clobbered:
- * r4 - tmp
- * r5 - tmp
- * r6 - tmp
- * r7 - tmp
- */
-
- /* .L1: */
- /* for(register uint32_t i=0;i<wcount;i++){ */
- 0x04, 0x1C, /* mov r4, r0 */
- 0x00, 0x23, /* mov r3, #0 */
- /* .L2: */
- 0x0E, 0x1A, /* sub r6, r1, r0 */
- 0xA6, 0x19, /* add r6, r4, r6 */
- 0x93, 0x42, /* cmp r3, r2 */
- 0x16, 0xD0, /* beq .L9 */
- /* .L5: */
- /* while((FTFx_FSTAT&FTFA_FSTAT_CCIF_MASK) != FTFA_FSTAT_CCIF_MASK){}; */
- 0x0B, 0x4D, /* ldr r5, .L10 */
- 0x2F, 0x78, /* ldrb r7, [r5] */
- 0x7F, 0xB2, /* sxtb r7, r7 */
- 0x00, 0x2F, /* cmp r7, #0 */
- 0xFA, 0xDA, /* bge .L5 */
- /* FTFx_FSTAT = FTFA_FSTAT_ACCERR_MASK|FTFA_FSTAT_FPVIOL_MASK|FTFA_FSTAT_RDCO */
- 0x70, 0x27, /* mov r7, #112 */
- 0x2F, 0x70, /* strb r7, [r5] */
- /* FTFx_FCCOB3 = faddr; */
- 0x09, 0x4F, /* ldr r7, .L10+4 */
- 0x3E, 0x60, /* str r6, [r7] */
- 0x06, 0x27, /* mov r7, #6 */
- /* FTFx_FCCOB0 = 0x06; */
- 0x08, 0x4E, /* ldr r6, .L10+8 */
- 0x37, 0x70, /* strb r7, [r6] */
- /* FTFx_FCCOB7 = *pLW; */
- 0x80, 0xCC, /* ldmia r4!, {r7} */
- 0x08, 0x4E, /* ldr r6, .L10+12 */
- 0x37, 0x60, /* str r7, [r6] */
- /* FTFx_FSTAT = FTFA_FSTAT_CCIF_MASK; */
- 0x80, 0x27, /* mov r7, #128 */
- 0x2F, 0x70, /* strb r7, [r5] */
- /* .L4: */
- /* while((FTFx_FSTAT&FTFA_FSTAT_CCIF_MASK) != FTFA_FSTAT_CCIF_MASK){}; */
- 0x2E, 0x78, /* ldrb r6, [r5] */
- 0x77, 0xB2, /* sxtb r7, r6 */
- 0x00, 0x2F, /* cmp r7, #0 */
- 0xFB, 0xDA, /* bge .L4 */
- 0x01, 0x33, /* add r3, r3, #1 */
- 0xE4, 0xE7, /* b .L2 */
- /* .L9: */
- 0x00, 0xBE, /* bkpt #0 */
- /* .L10: */
- 0x00, 0x00, 0x02, 0x40, /* .word 1073872896 */
- 0x04, 0x00, 0x02, 0x40, /* .word 1073872900 */
- 0x07, 0x00, 0x02, 0x40, /* .word 1073872903 */
- 0x08, 0x00, 0x02, 0x40, /* .word 1073872904 */
+#include "../../../contrib/loaders/flash/kinetis/kinetis_flash.inc"
};
/* Program LongWord Block Write */
@@ -933,20 +881,11 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
struct working_area *source;
struct kinetis_flash_bank *kinfo = bank->driver_priv;
uint32_t address = kinfo->prog_base + offset;
- struct reg_param reg_params[3];
+ uint32_t end_address;
+ struct reg_param reg_params[5];
struct armv7m_algorithm armv7m_info;
- int retval = ERROR_OK;
-
- /* Params:
- * r0 - workarea buffer
- * r1 - target address
- * r2 - wordcount
- * Clobbered:
- * r4 - tmp
- * r5 - tmp
- * r6 - tmp
- * r7 - tmp
- */
+ int retval;
+ uint8_t fstat;
/* Increase buffer_size if needed */
if (buffer_size < (target->working_area_size/2))
@@ -979,35 +918,39 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
- init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* *pLW (*buffer) */
- init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* faddr */
- init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* number of words to program */
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* address */
+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* word count */
+ 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], "r4", 32, PARAM_OUT);
- /* write code buffer and use Flash programming code within kinetis */
- /* Set breakpoint to 0 with time-out of 1000 ms */
- while (wcount > 0) {
- uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+ buf_set_u32(reg_params[1].value, 0, 32, wcount);
+ buf_set_u32(reg_params[2].value, 0, 32, source->address);
+ buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
+ buf_set_u32(reg_params[4].value, 0, 32, FTFx_FSTAT);
- retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer);
- if (retval != ERROR_OK)
- break;
+ retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
+ 0, NULL,
+ 5, reg_params,
+ source->address, source->size,
+ write_algorithm->address, 0,
+ &armv7m_info);
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- buf_set_u32(reg_params[1].value, 0, 32, address);
- buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+ if (retval == ERROR_FLASH_OPERATION_FAILED) {
+ end_address = buf_get_u32(reg_params[0].value, 0, 32);
- retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
- write_algorithm->address, 0, 100000, &armv7m_info);
- if (retval != ERROR_OK) {
- LOG_ERROR("Error executing kinetis Flash programming algorithm");
- retval = ERROR_FLASH_OPERATION_FAILED;
- break;
- }
+ LOG_ERROR("Error writing flash at %08" PRIx32, end_address);
- buffer += thisrun_count * 4;
- address += thisrun_count * 4;
- wcount -= thisrun_count;
- }
+ retval = target_read_u8(target, FTFx_FSTAT, &fstat);
+ if (retval == ERROR_OK) {
+ retval = kinetis_ftfx_decode_error(fstat);
+
+ /* reset error flags */
+ target_write_u8(target, FTFx_FSTAT, 0x70);
+ }
+ } else if (retval != ERROR_OK)
+ LOG_ERROR("Error executing kinetis Flash programming algorithm");
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
@@ -1015,6 +958,8 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
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]);
return retval;
}
@@ -1236,12 +1181,13 @@ static int kinetis_check_run_mode(struct target *target)
static void kinetis_invalidate_flash_cache(struct flash_bank *bank)
{
struct kinetis_flash_bank *kinfo = bank->driver_priv;
- uint8_t pfb01cr_byte2 = 0xf0;
- if (!(kinfo->flash_support & FS_INVALIDATE_CACHE))
- return;
+ if (kinfo->flash_support & FS_INVALIDATE_CACHE_K)
+ target_write_u8(bank->target, FMC_PFB01CR + 2, 0xf0);
+
+ else if (kinfo->flash_support & FS_INVALIDATE_CACHE_L)
+ target_write_u8(bank->target, MCM_PLACR + 1, 0x04);
- target_write_memory(bank->target, FMC_PFB01CR + 2, 1, 1, &pfb01cr_byte2);
return;
}
@@ -1425,7 +1371,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
if (!(kinfo->flash_support & FS_PROGRAM_SECTOR)) {
/* fallback to longword write */
fallback = 1;
- LOG_WARNING("This device supports Program Longword execution only.");
+ LOG_INFO("This device supports Program Longword execution only.");
} else {
result = kinetis_make_ram_ready(bank->target);
if (result != ERROR_OK) {
@@ -1604,7 +1550,7 @@ static int kinetis_probe(struct flash_bank *bank)
pflash_sector_size_bytes = 1<<10;
nvm_sector_size_bytes = 1<<10;
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
break;
case KINETIS_K_SDID_K10_M72:
case KINETIS_K_SDID_K20_M72:
@@ -1617,7 +1563,7 @@ static int kinetis_probe(struct flash_bank *bank)
pflash_sector_size_bytes = 2<<10;
nvm_sector_size_bytes = 1<<10;
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
kinfo->max_flash_prog_size = 1<<10;
break;
case KINETIS_K_SDID_K10_M100:
@@ -1633,7 +1579,7 @@ static int kinetis_probe(struct flash_bank *bank)
pflash_sector_size_bytes = 2<<10;
nvm_sector_size_bytes = 2<<10;
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
break;
case KINETIS_K_SDID_K21_M120:
case KINETIS_K_SDID_K22_M120:
@@ -1642,7 +1588,7 @@ static int kinetis_probe(struct flash_bank *bank)
kinfo->max_flash_prog_size = 1<<10;
nvm_sector_size_bytes = 4<<10;
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
break;
case KINETIS_K_SDID_K10_M120:
case KINETIS_K_SDID_K20_M120:
@@ -1652,7 +1598,7 @@ static int kinetis_probe(struct flash_bank *bank)
pflash_sector_size_bytes = 4<<10;
nvm_sector_size_bytes = 4<<10;
num_blocks = 4;
- kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
break;
default:
LOG_ERROR("Unsupported K-family FAMID");
@@ -1666,7 +1612,7 @@ static int kinetis_probe(struct flash_bank *bank)
/* K02FN64, K02FN128: FTFA, 2kB sectors */
pflash_sector_size_bytes = 2<<10;
num_blocks = 1;
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
break;
case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX2: {
@@ -1681,7 +1627,7 @@ static int kinetis_probe(struct flash_bank *bank)
/* MK24FN1M */
pflash_sector_size_bytes = 4<<10;
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
kinfo->max_flash_prog_size = 1<<10;
break;
}
@@ -1691,7 +1637,7 @@ static int kinetis_probe(struct flash_bank *bank)
/* K22 with new-style SDID - smaller pflash with FTFA, 2kB sectors */
pflash_sector_size_bytes = 2<<10;
/* autodetect 1 or 2 blocks */
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
break;
}
LOG_ERROR("Unsupported Kinetis K22 DIEID");
@@ -1702,12 +1648,12 @@ static int kinetis_probe(struct flash_bank *bank)
if ((kinfo->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN256) {
/* K24FN256 - smaller pflash with FTFA */
num_blocks = 1;
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
break;
}
/* K24FN1M without errata 7534 */
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
kinfo->max_flash_prog_size = 1<<10;
break;
@@ -1721,7 +1667,7 @@ static int kinetis_probe(struct flash_bank *bank)
nvm_sector_size_bytes = 4<<10;
kinfo->max_flash_prog_size = 1<<10;
num_blocks = 2;
- kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
break;
case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX6:
@@ -1732,8 +1678,18 @@ static int kinetis_probe(struct flash_bank *bank)
nvm_sector_size_bytes = 4<<10;
kinfo->max_flash_prog_size = 1<<10;
num_blocks = 4;
- kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K;
break;
+
+ case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0:
+ case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1:
+ case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2:
+ /* K80FN256, K81FN256, K82FN256 */
+ pflash_sector_size_bytes = 4<<10;
+ num_blocks = 1;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
+ break;
+
default:
LOG_ERROR("Unsupported Kinetis FAMILYID SUBFAMID");
}
@@ -1744,7 +1700,7 @@ static int kinetis_probe(struct flash_bank *bank)
pflash_sector_size_bytes = 1<<10;
nvm_sector_size_bytes = 1<<10;
/* autodetect 1 or 2 blocks */
- kinfo->flash_support = FS_PROGRAM_LONGWORD;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L;
break;
case KINETIS_SDID_SERIESID_KV:
@@ -1754,14 +1710,14 @@ static int kinetis_probe(struct flash_bank *bank)
/* KV10: FTFA, 1kB sectors */
pflash_sector_size_bytes = 1<<10;
num_blocks = 1;
- kinfo->flash_support = FS_PROGRAM_LONGWORD;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L;
break;
case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX1:
/* KV11: FTFA, 2kB sectors */
pflash_sector_size_bytes = 2<<10;
num_blocks = 1;
- kinfo->flash_support = FS_PROGRAM_LONGWORD;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L;
break;
case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX0:
@@ -1770,7 +1726,7 @@ static int kinetis_probe(struct flash_bank *bank)
/* KV31: FTFA, 2kB sectors, 2 blocks */
pflash_sector_size_bytes = 2<<10;
/* autodetect 1 or 2 blocks */
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
break;
case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX2:
@@ -1779,7 +1735,7 @@ static int kinetis_probe(struct flash_bank *bank)
/* KV4x: FTFA, 4kB sectors */
pflash_sector_size_bytes = 4<<10;
num_blocks = 1;
- kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE;
+ kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K;
break;
default:
diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c
index 76cd86b..9da5da2 100644
--- a/src/flash/nor/lpc2000.c
+++ b/src/flash/nor/lpc2000.c
@@ -259,6 +259,8 @@
#define IAP_CODE_LEN 0x34
+#define LPC11xx_REG_SECTORS 24
+
typedef enum {
lpc2000_v1,
lpc2000_v2,
@@ -554,14 +556,21 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
exit(-1);
}
lpc2000_info->cmd51_max_buffer = 512; /* smallest MCU in the series, LPC1110, has 1 kB of SRAM */
- bank->num_sectors = bank->size / 4096;
+ unsigned int large_sectors = 0;
+ unsigned int normal_sectors = bank->size / 4096;
+
+ if (normal_sectors > LPC11xx_REG_SECTORS) {
+ large_sectors = (normal_sectors - LPC11xx_REG_SECTORS) / 8;
+ normal_sectors = LPC11xx_REG_SECTORS;
+ }
+
+ bank->num_sectors = normal_sectors + large_sectors;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = offset;
- /* all sectors are 4kB-sized */
- bank->sectors[i].size = 4 * 1024;
+ bank->sectors[i].size = (i < LPC11xx_REG_SECTORS ? 4 : 32) * 1024;
offset += bank->sectors[i].size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
@@ -679,7 +688,7 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working
int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate);
if (retval != ERROR_OK) {
- LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)",
+ LOG_ERROR("Write memory at address 0x%8.8" TARGET_PRIxADDR " failed (check work_area definition)",
(*iap_working_area)->address);
target_free_working_area(target, *iap_working_area);
}
diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c
index 4eb6cc3..943c151 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -186,7 +186,7 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
return retval;
}
- LOG_DEBUG("Writing algorithm to working area at 0x%08" PRIx32,
+ LOG_DEBUG("Writing algorithm to working area at 0x%08" TARGET_PRIxADDR,
spifi_init_algorithm->address);
/* Write algorithm to working area */
retval = target_write_buffer(target,
diff --git a/src/flash/nor/mdr.c b/src/flash/nor/mdr.c
index 374cb6f..8ceb1bf 100644
--- a/src/flash/nor/mdr.c
+++ b/src/flash/nor/mdr.c
@@ -171,7 +171,8 @@ static int mdr_erase(struct flash_bank *bank, int first, int last)
if (retval != ERROR_OK)
goto reset_pg_and_lock;
- if ((first == 0) && (last == (bank->num_sectors - 1))) {
+ if ((first == 0) && (last == (bank->num_sectors - 1)) &&
+ !mdr_info->mem_type) {
retval = mdr_mass_erase(bank);
goto reset_pg_and_lock;
}
diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf51.c
index 69bf666..7b7acf4 100644
--- a/src/flash/nor/nrf51.c
+++ b/src/flash/nor/nrf51.c
@@ -108,7 +108,6 @@ enum nrf51_nvmc_config_bits {
struct nrf51_info {
uint32_t code_page_size;
- uint32_t code_memory_size;
struct {
bool probed;
@@ -121,6 +120,7 @@ struct nrf51_info {
struct nrf51_device_spec {
uint16_t hwid;
+ const char *part;
const char *variant;
const char *build_code;
unsigned int flash_size_kb;
@@ -142,30 +142,35 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
/* nRF51822 Devices (IC rev 1). */
{
.hwid = 0x001D,
+ .part = "51822",
.variant = "QFAA",
.build_code = "CA/C0",
.flash_size_kb = 256,
},
{
.hwid = 0x0026,
+ .part = "51822",
.variant = "QFAB",
.build_code = "AA",
.flash_size_kb = 128,
},
{
.hwid = 0x0027,
+ .part = "51822",
.variant = "QFAB",
.build_code = "A0",
.flash_size_kb = 128,
},
{
.hwid = 0x0020,
+ .part = "51822",
.variant = "CEAA",
.build_code = "BA",
.flash_size_kb = 256,
},
{
.hwid = 0x002F,
+ .part = "51822",
.variant = "CEAA",
.build_code = "B0",
.flash_size_kb = 256,
@@ -174,54 +179,63 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
/* nRF51822 Devices (IC rev 2). */
{
.hwid = 0x002A,
+ .part = "51822",
.variant = "QFAA",
.build_code = "FA0",
.flash_size_kb = 256,
},
{
.hwid = 0x0044,
+ .part = "51822",
.variant = "QFAA",
.build_code = "GC0",
.flash_size_kb = 256,
},
{
.hwid = 0x003C,
+ .part = "51822",
.variant = "QFAA",
.build_code = "G0",
.flash_size_kb = 256,
},
{
.hwid = 0x0057,
+ .part = "51822",
.variant = "QFAA",
.build_code = "G2",
.flash_size_kb = 256,
},
{
.hwid = 0x0058,
+ .part = "51822",
.variant = "QFAA",
.build_code = "G3",
.flash_size_kb = 256,
},
{
.hwid = 0x004C,
+ .part = "51822",
.variant = "QFAB",
.build_code = "B0",
.flash_size_kb = 128,
},
{
.hwid = 0x0040,
+ .part = "51822",
.variant = "CEAA",
.build_code = "CA0",
.flash_size_kb = 256,
},
{
.hwid = 0x0047,
+ .part = "51822",
.variant = "CEAA",
.build_code = "DA0",
.flash_size_kb = 256,
},
{
.hwid = 0x004D,
+ .part = "51822",
.variant = "CEAA",
.build_code = "D00",
.flash_size_kb = 256,
@@ -230,62 +244,79 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
/* nRF51822 Devices (IC rev 3). */
{
.hwid = 0x0072,
+ .part = "51822",
.variant = "QFAA",
.build_code = "H0",
.flash_size_kb = 256,
},
{
.hwid = 0x007B,
+ .part = "51822",
.variant = "QFAB",
.build_code = "C0",
.flash_size_kb = 128,
},
{
.hwid = 0x0083,
+ .part = "51822",
.variant = "QFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
{
.hwid = 0x0084,
+ .part = "51822",
.variant = "QFAC",
.build_code = "A1",
.flash_size_kb = 256,
},
{
.hwid = 0x007D,
+ .part = "51822",
.variant = "CDAB",
.build_code = "A0",
.flash_size_kb = 128,
},
{
.hwid = 0x0079,
+ .part = "51822",
.variant = "CEAA",
.build_code = "E0",
.flash_size_kb = 256,
},
{
.hwid = 0x0087,
+ .part = "51822",
.variant = "CFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
+ {
+ .hwid = 0x008F,
+ .part = "51822",
+ .variant = "QFAA",
+ .build_code = "H1",
+ .flash_size_kb = 256,
+ },
/* nRF51422 Devices (IC rev 1). */
{
.hwid = 0x001E,
+ .part = "51422",
.variant = "QFAA",
.build_code = "CA",
.flash_size_kb = 256,
},
{
.hwid = 0x0024,
+ .part = "51422",
.variant = "QFAA",
.build_code = "C0",
.flash_size_kb = 256,
},
{
.hwid = 0x0031,
+ .part = "51422",
.variant = "CEAA",
.build_code = "A0A",
.flash_size_kb = 256,
@@ -294,24 +325,28 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
/* nRF51422 Devices (IC rev 2). */
{
.hwid = 0x002D,
+ .part = "51422",
.variant = "QFAA",
.build_code = "DAA",
.flash_size_kb = 256,
},
{
.hwid = 0x002E,
+ .part = "51422",
.variant = "QFAA",
.build_code = "E0",
.flash_size_kb = 256,
},
{
.hwid = 0x0061,
+ .part = "51422",
.variant = "QFAB",
.build_code = "A00",
.flash_size_kb = 128,
},
{
.hwid = 0x0050,
+ .part = "51422",
.variant = "CEAA",
.build_code = "B0",
.flash_size_kb = 256,
@@ -320,42 +355,49 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
/* nRF51422 Devices (IC rev 3). */
{
.hwid = 0x0073,
+ .part = "51422",
.variant = "QFAA",
.build_code = "F0",
.flash_size_kb = 256,
},
{
.hwid = 0x007C,
+ .part = "51422",
.variant = "QFAB",
.build_code = "B0",
.flash_size_kb = 128,
},
{
.hwid = 0x0085,
+ .part = "51422",
.variant = "QFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
{
.hwid = 0x0086,
+ .part = "51422",
.variant = "QFAC",
.build_code = "A1",
.flash_size_kb = 256,
},
{
.hwid = 0x007E,
+ .part = "51422",
.variant = "CDAB",
.build_code = "A0",
.flash_size_kb = 128,
},
{
.hwid = 0x007A,
+ .part = "51422",
.variant = "CEAA",
.build_code = "C0",
.flash_size_kb = 256,
},
{
.hwid = 0x0088,
+ .part = "51422",
.variant = "CFAC",
.build_code = "A0",
.flash_size_kb = 256,
@@ -366,6 +408,7 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
in the nRF51 Series Compatibility Matrix V1.0. */
{
.hwid = 0x0071,
+ .part = "51822",
.variant = "QFAC",
.build_code = "AB",
.flash_size_kb = 256,
@@ -627,43 +670,46 @@ static int nrf51_probe(struct flash_bank *bank)
* bytes of the CONFIGID register */
const struct nrf51_device_spec *spec = NULL;
- for (size_t i = 0; i < ARRAY_SIZE(nrf51_known_devices_table); i++)
+ for (size_t i = 0; i < ARRAY_SIZE(nrf51_known_devices_table); i++) {
if (hwid == nrf51_known_devices_table[i].hwid) {
spec = &nrf51_known_devices_table[i];
break;
}
+ }
if (!chip->bank[0].probed && !chip->bank[1].probed) {
if (spec)
- LOG_INFO("nRF51822-%s(build code: %s) %ukB Flash",
- spec->variant, spec->build_code, spec->flash_size_kb);
+ LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash",
+ spec->part, spec->variant, spec->build_code,
+ spec->flash_size_kb);
else
LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid);
}
-
if (bank->base == NRF51_FLASH_BASE) {
+ /* The value stored in NRF51_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
res = target_read_u32(chip->target, NRF51_FICR_CODEPAGESIZE,
- &chip->code_page_size);
+ &chip->code_page_size);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code page size");
return res;
}
- res = target_read_u32(chip->target, NRF51_FICR_CODESIZE,
- &chip->code_memory_size);
+ /* Note the register name is misleading,
+ * NRF51_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, NRF51_FICR_CODESIZE, &num_sectors);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code memory size");
return res;
}
- if (spec && chip->code_memory_size != spec->flash_size_kb) {
- LOG_ERROR("Chip's reported Flash capacity does not match expected one");
- return ERROR_FAIL;
- }
+ 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 = chip->code_memory_size * 1024;
- bank->num_sectors = bank->size / chip->code_page_size;
bank->sectors = calloc(bank->num_sectors,
sizeof((bank->sectors)[0]));
if (!bank->sectors)
@@ -1272,7 +1318,7 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size)
"reset value for XTALFREQ: %"PRIx32"\n"
"firmware id: 0x%04"PRIx32,
ficr[0].value,
- ficr[1].value,
+ (ficr[1].value * ficr[0].value) / 1024,
(ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024,
((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present",
ficr[4].value,
diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c
index de212ed..1f148fd 100644
--- a/src/flash/nor/pic32mx.c
+++ b/src/flash/nor/pic32mx.c
@@ -879,7 +879,6 @@ COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
COMMAND_HANDLER(pic32mx_handle_unlock_command)
{
- uint32_t mchip_cmd;
struct target *target = NULL;
struct mips_m4k_common *mips_m4k;
struct mips_ejtag *ejtag_info;
@@ -904,7 +903,7 @@ COMMAND_HANDLER(pic32mx_handle_unlock_command)
mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND);
/* first check status of device */
- mchip_cmd = MCHP_STATUS;
+ uint8_t mchip_cmd = MCHP_STATUS;
mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
if (mchip_cmd & (1 << 7)) {
/* device is not locked */
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index 1acab82..4d75095 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -110,6 +110,9 @@
#define FLASH_ERASE_TIMEOUT 10000
#define FLASH_WRITE_TIMEOUT 5
+/* Mass erase time can be as high as 32 s in x8 mode. */
+#define FLASH_MASS_ERASE_TIMEOUT 33000
+
#define STM32_FLASH_BASE 0x40023c00
#define STM32_FLASH_ACR 0x40023c00
#define STM32_FLASH_KEYR 0x40023c04
@@ -399,8 +402,8 @@ static int stm32x_write_options(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
- /* wait for completion */
- retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+ /* wait for completion, this might trigger a security erase and take a while */
+ retval = stm32x_wait_status_busy(bank, FLASH_MASS_ERASE_TIMEOUT);
if (retval != ERROR_OK)
return retval;
@@ -1257,7 +1260,7 @@ static int stm32x_mass_erase(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
- retval = stm32x_wait_status_busy(bank, 30000);
+ retval = stm32x_wait_status_busy(bank, FLASH_MASS_ERASE_TIMEOUT);
if (retval != ERROR_OK)
return retval;
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index 129b281..fa0c48b 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -27,18 +27,22 @@
/* STM32L4xxx series for reference.
*
- * RM0351
- * http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00083560.pdf
+ * RM0351 (STM32L4x5/STM32L4x6)
+ * http://www.st.com/resource/en/reference_manual/dm00083560.pdf
*
- * STM32L476RG Datasheet (for erase timing)
- * http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00108832.pdf
+ * RM0394 (STM32L43x/44x/45x/46x)
+ * http://www.st.com/resource/en/reference_manual/dm00151940.pdf
*
+ * STM32L476RG Datasheet (for erase timing)
+ * http://www.st.com/resource/en/datasheet/stm32l476rg.pdf
*
- * The device has normally two banks, but on 512 and 256 kiB devices an
- * option byte is available to map all sectors to the first bank.
+ * The RM0351 devices have normally two banks, but on 512 and 256 kiB devices
+ * an option byte is available to map all sectors to the first bank.
* Both STM32 banks are treated as one OpenOCD bank, as other STM32 devices
* handlers do!
*
+ * RM0394 devices have a single bank only.
+ *
*/
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
@@ -614,9 +618,16 @@ static int stm32l4_probe(struct flash_bank *bank)
/* set max flash size depending on family */
switch (device_id & 0xfff) {
+ 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 a STM32L4 family.");
return ERROR_FAIL;
@@ -698,7 +709,7 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
if (retval != ERROR_OK)
return retval;
- uint16_t device_id = dbgmcu_idcode & 0xffff;
+ uint16_t device_id = dbgmcu_idcode & 0xfff;
uint8_t rev_id = dbgmcu_idcode >> 28;
uint8_t rev_minor = 0;
int i;
@@ -713,8 +724,20 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
const char *device_str;
switch (device_id) {
- case 0x6415:
- device_str = "STM32L4xx";
+ 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;
default:
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index 376c0f8..e4f499d 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -105,6 +105,7 @@ static int stm32lx_lock(struct flash_bank *bank);
static int stm32lx_unlock(struct flash_bank *bank);
static int stm32lx_mass_erase(struct flash_bank *bank);
static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout);
+static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t flash_size_in_kb);
struct stm32lx_rev {
uint16_t rev;
@@ -132,7 +133,7 @@ struct stm32lx_flash_bank {
uint32_t user_bank_size;
uint32_t flash_base;
- const struct stm32lx_part_info *part_info;
+ struct stm32lx_part_info part_info;
};
static const struct stm32lx_rev stm32_416_revs[] = {
@@ -245,7 +246,7 @@ static const struct stm32lx_part_info stm32lx_parts[] = {
.page_size = 256,
.pages_per_sector = 16,
.max_flash_size_kb = 512,
- .first_bank_size_kb = 256,
+ .first_bank_size_kb = 0, /* determined in runtime */
.has_dual_banks = true,
.flash_base = 0x40023C00,
.fsize_base = 0x1FF800CC,
@@ -258,8 +259,8 @@ static const struct stm32lx_part_info stm32lx_parts[] = {
.page_size = 128,
.pages_per_sector = 32,
.max_flash_size_kb = 192,
- .first_bank_size_kb = 128,
- .has_dual_banks = true,
+ .first_bank_size_kb = 0, /* determined in runtime */
+ .has_dual_banks = false, /* determined in runtime */
.flash_base = 0x40022000,
.fsize_base = 0x1FF8007C,
},
@@ -300,7 +301,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
stm32lx_info->user_bank_size = bank->size;
/* the stm32l erased value is 0x00 */
- bank->default_padded_value = 0x00;
+ bank->default_padded_value = bank->erased_value = 0x00;
return ERROR_OK;
}
@@ -436,7 +437,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- uint32_t hp_nb = stm32lx_info->part_info->page_size / 2;
+ uint32_t hp_nb = stm32lx_info->part_info.page_size / 2;
uint32_t buffer_size = 16384;
struct working_area *write_algorithm;
struct working_area *source;
@@ -450,19 +451,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
/* see contib/loaders/flash/stm32lx.S for src */
static const uint8_t stm32lx_flash_write_code[] = {
- /* write_word: */
- 0x00, 0x23, /* movs r3, #0 */
- 0x04, 0xe0, /* b test_done */
-
- /* write_word: */
- 0x51, 0xf8, 0x04, 0xcb, /* ldr ip, [r1], #4 */
- 0x40, 0xf8, 0x04, 0xcb, /* str ip, [r0], #4 */
- 0x01, 0x33, /* adds r3, #1 */
-
- /* test_done: */
- 0x93, 0x42, /* cmp r3, r2 */
- 0xf8, 0xd3, /* bcc write_word */
- 0x00, 0xbe, /* bkpt 0 */
+ 0x92, 0x00, 0x8A, 0x18, 0x01, 0xE0, 0x08, 0xC9, 0x08, 0xC0, 0x91, 0x42, 0xFB, 0xD1, 0x00, 0xBE
};
/* Make sure we're performing a half-page aligned write. */
@@ -495,7 +484,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
else
buffer_size /= 2;
- if (buffer_size <= stm32lx_info->part_info->page_size) {
+ if (buffer_size <= stm32lx_info->part_info.page_size) {
/* we already allocated the writing code, but failed to get a
* buffer, free the algorithm */
target_free_working_area(target, write_algorithm);
@@ -588,7 +577,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
* is reduced by 50% using this slower method.
*/
- LOG_WARNING("couldn't use loader, falling back to page memory writes");
+ LOG_WARNING("Couldn't use loader, falling back to page memory writes");
while (count > 0) {
uint32_t this_count;
@@ -629,7 +618,7 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer,
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- uint32_t hp_nb = stm32lx_info->part_info->page_size / 2;
+ uint32_t hp_nb = stm32lx_info->part_info.page_size / 2;
uint32_t halfpages_number;
uint32_t bytes_remaining = 0;
uint32_t address = bank->base + offset;
@@ -759,9 +748,9 @@ static int stm32lx_probe(struct flash_bank *bank)
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->part_info = NULL;
int retval = stm32lx_read_id_code(bank->target, &device_id);
if (retval != ERROR_OK)
@@ -771,22 +760,24 @@ static int stm32lx_probe(struct flash_bank *bank)
LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id);
- for (unsigned int n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) {
- if ((device_id & 0xfff) == stm32lx_parts[n].id)
- stm32lx_info->part_info = &stm32lx_parts[n];
+ for (n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) {
+ if ((device_id & 0xfff) == stm32lx_parts[n].id) {
+ stm32lx_info->part_info = stm32lx_parts[n];
+ break;
+ }
}
- if (!stm32lx_info->part_info) {
+ if (n == ARRAY_SIZE(stm32lx_parts)) {
LOG_WARNING("Cannot identify target as a STM32L family.");
return ERROR_FAIL;
} else {
- LOG_INFO("Device: %s", stm32lx_info->part_info->device_str);
+ LOG_INFO("Device: %s", stm32lx_info->part_info.device_str);
}
- stm32lx_info->flash_base = stm32lx_info->part_info->flash_base;
+ stm32lx_info->flash_base = stm32lx_info->part_info.flash_base;
/* Get the flash size from target. */
- retval = target_read_u16(target, stm32lx_info->part_info->fsize_base,
+ retval = target_read_u16(target, stm32lx_info->part_info.fsize_base,
&flash_size_in_kb);
/* 0x436 devices report their flash size as a 0 or 1 code indicating 384K
@@ -803,29 +794,34 @@ static int stm32lx_probe(struct flash_bank *bank)
* default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
LOG_WARNING("STM32L flash size failed, probe inaccurate - assuming %dk flash",
- stm32lx_info->part_info->max_flash_size_kb);
- flash_size_in_kb = stm32lx_info->part_info->max_flash_size_kb;
- } else if (flash_size_in_kb > stm32lx_info->part_info->max_flash_size_kb) {
+ stm32lx_info->part_info.max_flash_size_kb);
+ flash_size_in_kb = stm32lx_info->part_info.max_flash_size_kb;
+ } else if (flash_size_in_kb > stm32lx_info->part_info.max_flash_size_kb) {
LOG_WARNING("STM32L probed flash size assumed incorrect since FLASH_SIZE=%dk > %dk, - assuming %dk flash",
- flash_size_in_kb, stm32lx_info->part_info->max_flash_size_kb,
- stm32lx_info->part_info->max_flash_size_kb);
- flash_size_in_kb = stm32lx_info->part_info->max_flash_size_kb;
+ flash_size_in_kb, stm32lx_info->part_info.max_flash_size_kb,
+ stm32lx_info->part_info.max_flash_size_kb);
+ flash_size_in_kb = stm32lx_info->part_info.max_flash_size_kb;
}
- if (stm32lx_info->part_info->has_dual_banks) {
+ /* Overwrite default dual-bank configuration */
+ retval = stm32lx_update_part_info(bank, flash_size_in_kb);
+ if (retval != ERROR_OK)
+ return ERROR_FAIL;
+
+ if (stm32lx_info->part_info.has_dual_banks) {
/* 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
*/
second_bank_base = base_address +
- stm32lx_info->part_info->first_bank_size_kb * 1024;
+ stm32lx_info->part_info.first_bank_size_kb * 1024;
if (bank->base == second_bank_base || !bank->base) {
/* This is the second bank */
base_address = second_bank_base;
flash_size_in_kb = flash_size_in_kb -
- stm32lx_info->part_info->first_bank_size_kb;
+ stm32lx_info->part_info.first_bank_size_kb;
} else if (bank->base == base_address) {
/* This is the first bank */
- flash_size_in_kb = stm32lx_info->part_info->first_bank_size_kb;
+ flash_size_in_kb = stm32lx_info->part_info.first_bank_size_kb;
} else {
LOG_WARNING("STM32L flash bank base address config is incorrect."
" 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
@@ -884,60 +880,13 @@ static int stm32lx_auto_probe(struct flash_bank *bank)
return stm32lx_probe(bank);
}
-static int stm32lx_erase_check(struct flash_bank *bank)
-{
- struct target *target = bank->target;
- const int buffer_size = 4096;
- int i;
- uint32_t nBytes;
- int retval = ERROR_OK;
-
- if (bank->target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- uint8_t *buffer = malloc(buffer_size);
- if (buffer == NULL) {
- LOG_ERROR("failed to allocate read buffer");
- return ERROR_FAIL;
- }
-
- for (i = 0; i < bank->num_sectors; i++) {
- uint32_t j;
- bank->sectors[i].is_erased = 1;
-
- /* Loop chunk by chunk over the sector */
- for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
- uint32_t chunk;
- chunk = buffer_size;
- if (chunk > (j - bank->sectors[i].size))
- chunk = (j - bank->sectors[i].size);
-
- retval = target_read_memory(target, bank->base
- + bank->sectors[i].offset + j, 4, chunk / 4, buffer);
- if (retval != ERROR_OK)
- break;
-
- for (nBytes = 0; nBytes < chunk; nBytes++) {
- if (buffer[nBytes] != 0x00) {
- bank->sectors[i].is_erased = 0;
- break;
- }
- }
- }
- if (retval != ERROR_OK)
- break;
- }
- free(buffer);
-
- return retval;
-}
-
/* This method must return a string displaying information about the bank */
static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
+ const struct stm32lx_part_info *info = &stm32lx_info->part_info;
+ uint16_t rev_id = stm32lx_info->idcode >> 16;
+ const char *rev_str = NULL;
if (!stm32lx_info->probed) {
int retval = stm32lx_probe(bank);
@@ -948,32 +897,21 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
}
}
- const struct stm32lx_part_info *info = stm32lx_info->part_info;
-
- if (info) {
- const char *rev_str = NULL;
- uint16_t rev_id = stm32lx_info->idcode >> 16;
+ for (unsigned int i = 0; i < info->num_revs; i++)
+ if (rev_id == info->revs[i].rev)
+ rev_str = info->revs[i].str;
- for (unsigned int i = 0; i < info->num_revs; i++)
- if (rev_id == info->revs[i].rev)
- rev_str = info->revs[i].str;
-
- if (rev_str != NULL) {
- snprintf(buf, buf_size,
- "%s - Rev: %s",
- stm32lx_info->part_info->device_str, rev_str);
- } else {
- snprintf(buf, buf_size,
- "%s - Rev: unknown (0x%04x)",
- stm32lx_info->part_info->device_str, rev_id);
- }
-
- return ERROR_OK;
+ if (rev_str != NULL) {
+ snprintf(buf, buf_size,
+ "%s - Rev: %s",
+ info->device_str, rev_str);
} else {
- snprintf(buf, buf_size, "Cannot identify target as a STM32Lx");
-
- return ERROR_FAIL;
+ snprintf(buf, buf_size,
+ "%s - Rev: unknown (0x%04x)",
+ info->device_str, rev_id);
}
+
+ return ERROR_OK;
}
static const struct command_registration stm32lx_exec_command_handlers[] = {
@@ -1022,7 +960,7 @@ struct flash_driver stm32lx_flash = {
.read = default_flash_read,
.probe = stm32lx_probe,
.auto_probe = stm32lx_auto_probe,
- .erase_check = stm32lx_erase_check,
+ .erase_check = default_flash_blank_check,
.protect_check = stm32lx_protect_check,
.info = stm32lx_get_info,
};
@@ -1182,7 +1120,7 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector)
if (retval != ERROR_OK)
return retval;
- for (int page = 0; page < (int)stm32lx_info->part_info->pages_per_sector;
+ for (int page = 0; page < (int)stm32lx_info->part_info.pages_per_sector;
page++) {
reg32 = FLASH_PECR__PROG | FLASH_PECR__ERASE;
retval = target_write_u32(target,
@@ -1195,7 +1133,7 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector)
return retval;
uint32_t addr = bank->base + bank->sectors[sector].offset + (page
- * stm32lx_info->part_info->page_size);
+ * stm32lx_info->part_info.page_size);
retval = target_write_u32(target, addr, 0x0);
if (retval != ERROR_OK)
return retval;
@@ -1419,3 +1357,22 @@ static int stm32lx_mass_erase(struct flash_bank *bank)
return ERROR_OK;
}
+
+static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t flash_size_in_kb)
+{
+ struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
+
+ switch (stm32lx_info->part_info.id) {
+ case 0x447: /* STM32L0xx (Cat.5) devices */
+ if (flash_size_in_kb == 192 || flash_size_in_kb == 128) {
+ stm32lx_info->part_info.first_bank_size_kb = flash_size_in_kb / 2;
+ stm32lx_info->part_info.has_dual_banks = true;
+ }
+ break;
+ case 0x437: /* STM32L1xx (Cat.5/Cat.6) */
+ stm32lx_info->part_info.first_bank_size_kb = flash_size_in_kb / 2;
+ break;
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index 6dd2140..b93d126 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -297,8 +297,8 @@ static int flash_check_sector_parameters(struct command_context *cmd_ctx,
}
if (!(last <= (num_sectors - 1))) {
- command_print(cmd_ctx, "ERROR: last sector must be <= %d",
- (int) num_sectors - 1);
+ command_print(cmd_ctx, "ERROR: last sector must be <= %" PRIu32,
+ num_sectors - 1);
return ERROR_FAIL;
}
@@ -341,7 +341,7 @@ COMMAND_HANDLER(handle_flash_erase_command)
"in %fs", first, last, p->bank_number, duration_elapsed(&bench));
}
- return ERROR_OK;
+ return retval;
}
COMMAND_HANDLER(handle_flash_protect_command)
@@ -380,10 +380,9 @@ COMMAND_HANDLER(handle_flash_protect_command)
retval = flash_driver_protect(p, set, first, last);
if (retval == ERROR_OK) {
- command_print(CMD_CTX, "%s protection for sectors %i "
- "through %i on flash bank %d",
- (set) ? "set" : "cleared", (int) first,
- (int) last, p->bank_number);
+ command_print(CMD_CTX, "%s protection for sectors %" PRIu32
+ " through %" PRIu32 " on flash bank %d",
+ (set) ? "set" : "cleared", first, last, p->bank_number);
}
return retval;
@@ -600,7 +599,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
- return ERROR_OK;
+ return ERROR_FAIL;
size_t filesize;
retval = fileio_size(fileio, &filesize);
@@ -619,7 +618,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
if (fileio_read(fileio, filesize, buffer, &buf_cnt) != ERROR_OK) {
free(buffer);
fileio_close(fileio);
- return ERROR_OK;
+ return ERROR_FAIL;
}
retval = flash_driver_write(p, buffer, offset, buf_cnt);
@@ -690,9 +689,9 @@ COMMAND_HANDLER(handle_flash_read_bank_command)
}
if (duration_measure(&bench) == ERROR_OK)
- command_print(CMD_CTX, "wrote %ld bytes to file %s from flash bank %u"
+ command_print(CMD_CTX, "wrote %zd bytes to file %s from flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
- (long)written, CMD_ARGV[1], p->bank_number, offset,
+ written, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, written));
return retval;
@@ -708,7 +707,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
size_t filesize;
int differ;
- if (CMD_ARGC != 3)
+ if (CMD_ARGC < 2 || CMD_ARGC > 3)
return ERROR_COMMAND_SYNTAX_ERROR;
struct duration bench;
@@ -719,7 +718,16 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
if (ERROR_OK != retval)
return retval;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
+ offset = 0;
+
+ if (CMD_ARGC > 2)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
+
+ if (offset > p->size) {
+ LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
+ offset);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY);
if (retval != ERROR_OK) {
@@ -770,9 +778,9 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
}
if (duration_measure(&bench) == ERROR_OK)
- command_print(CMD_CTX, "read %ld bytes from file %s and flash bank %u"
+ command_print(CMD_CTX, "read %zd bytes from file %s and flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
- (long)read_cnt, CMD_ARGV[1], p->bank_number, offset,
+ read_cnt, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, read_cnt));
differ = memcmp(buffer_file, buffer_flash, read_cnt);
@@ -927,19 +935,20 @@ static const struct command_registration flash_exec_command_handlers[] = {
.name = "verify_bank",
.handler = handle_flash_verify_bank_command,
.mode = COMMAND_EXEC,
- .usage = "bank_id filename offset",
- .help = "Read binary data from flash bank and file, "
- "starting at specified byte offset from the "
- "beginning of the bank. Compare the contents.",
+ .usage = "bank_id filename [offset]",
+ .help = "Compare the contents of a file with the contents of the "
+ "flash bank. Allow optional offset from beginning of the bank "
+ "(defaults to zero).",
},
{
.name = "protect",
.handler = handle_flash_protect_command,
.mode = COMMAND_EXEC,
- .usage = "bank_id first_sector [last_sector|'last'] "
+ .usage = "bank_id first_block [last_block|'last'] "
"('on'|'off')",
- .help = "Turn protection on or off for a range of sectors "
- "in a given flash bank.",
+ .help = "Turn protection on or off for a range of protection "
+ "blocks or sectors in a given flash bank. "
+ "See 'flash info' output for a list of blocks.",
},
{
.name = "padded_value",
@@ -1012,7 +1021,7 @@ COMMAND_HANDLER(handle_flash_bank_command)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width);
- c->default_padded_value = 0xff;
+ c->default_padded_value = c->erased_value = 0xff;
c->num_sectors = 0;
c->sectors = NULL;
c->num_prot_blocks = 0;
diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c
index 3cb793e..06981f4 100644
--- a/src/flash/nor/virtual.c
+++ b/src/flash/nor/virtual.c
@@ -44,6 +44,7 @@ static void virtual_update_bank_info(struct flash_bank *bank)
bank->size = master_bank->size;
bank->chip_width = master_bank->chip_width;
bank->bus_width = master_bank->bus_width;
+ bank->erased_value = master_bank->erased_value;
bank->default_padded_value = master_bank->default_padded_value;
bank->num_sectors = master_bank->num_sectors;
bank->sectors = master_bank->sectors;
diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c
index bb2ec12..0a76b21 100644
--- a/src/flash/nor/xmc1xxx.c
+++ b/src/flash/nor/xmc1xxx.c
@@ -305,7 +305,7 @@ static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t blocks = MIN(block_count, data_workarea->size / NVM_BLOCK_SIZE);
uint32_t addr = bank->base + offset;
- LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
+ LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" TARGET_PRIxADDR,
MIN(blocks * NVM_BLOCK_SIZE, byte_count),
data_workarea->address);
diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c
index 39aec79..02df46a 100644
--- a/src/flash/nor/xmc4xxx.c
+++ b/src/flash/nor/xmc4xxx.c
@@ -183,7 +183,7 @@
/* Flash controller configuration values */
#define FLASH_ID_XMC4500 0xA2
-#define FLASH_ID_XMC4700_4800 0x92
+#define FLASH_ID_XMC4300_XMC4700_4800 0x92
#define FLASH_ID_XMC4100_4200 0x9C
#define FLASH_ID_XMC4400 0x9F
@@ -319,8 +319,8 @@ static int xmc4xxx_load_bank_layout(struct flash_bank *bank)
}
/* This part doesn't follow the typical standard of 0xff
- * being the default padding value.*/
- bank->default_padded_value = 0x00;
+ * being the erased value.*/
+ bank->default_padded_value = bank->erased_value = 0x00;
return ERROR_OK;
}
@@ -383,7 +383,7 @@ static int xmc4xxx_probe(struct flash_bank *bank)
bank->num_sectors = 12;
LOG_DEBUG("XMC4xxx: XMC4500 detected.");
break;
- case FLASH_ID_XMC4700_4800:
+ case FLASH_ID_XMC4300_XMC4700_4800:
bank->num_sectors = 16;
LOG_DEBUG("XMC4xxx: XMC4700/4800 detected.");
break;
@@ -617,99 +617,6 @@ static int xmc4xxx_enter_page_mode(struct flash_bank *bank)
return res;
}
-/* The logical erase value of an xmc4xxx memory cell is 0x00,
- * therefore, we cannot use the built in flash blank check and must
- * implement our own */
-
-/** Checks whether a memory region is zeroed. */
-static int xmc4xxx_blank_check_memory(struct target *target,
- uint32_t address, uint32_t count, uint32_t *blank)
-{
- struct working_area *erase_check_algorithm;
- struct reg_param reg_params[3];
- struct armv7m_algorithm armv7m_info;
- int retval;
-
- static const uint8_t erase_check_code[] = {
-#include "../../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
- };
-
- /* make sure we have a working area */
- if (target_alloc_working_area(target, sizeof(erase_check_code),
- &erase_check_algorithm) != ERROR_OK)
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-
- retval = target_write_buffer(target, erase_check_algorithm->address,
- sizeof(erase_check_code), (uint8_t *)erase_check_code);
- if (retval != ERROR_OK)
- goto cleanup;
-
- armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
- armv7m_info.core_mode = ARM_MODE_THREAD;
-
- init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
- buf_set_u32(reg_params[0].value, 0, 32, address);
-
- init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
- buf_set_u32(reg_params[1].value, 0, 32, count);
-
- init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
- buf_set_u32(reg_params[2].value, 0, 32, 0x00);
-
- retval = target_run_algorithm(target,
- 0,
- NULL,
- 3,
- reg_params,
- erase_check_algorithm->address,
- erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
- 10000,
- &armv7m_info);
-
- if (retval == ERROR_OK)
- *blank = buf_get_u32(reg_params[2].value, 0, 32);
-
- destroy_reg_param(&reg_params[0]);
- destroy_reg_param(&reg_params[1]);
- destroy_reg_param(&reg_params[2]);
-
-cleanup:
- target_free_working_area(target, erase_check_algorithm);
-
- return retval;
-}
-
-static int xmc4xxx_flash_blank_check(struct flash_bank *bank)
-{
- struct target *target = bank->target;
- int i;
- int retval = ERROR_OK;
- uint32_t blank;
-
- if (bank->target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- for (i = 0; i < bank->num_sectors; i++) {
- uint32_t address = bank->base + bank->sectors[i].offset;
- uint32_t size = bank->sectors[i].size;
-
- LOG_DEBUG("Erase checking 0x%08"PRIx32, address);
- retval = xmc4xxx_blank_check_memory(target, address, size, &blank);
-
- if (retval != ERROR_OK)
- break;
-
- if (blank == 0x00)
- bank->sectors[i].is_erased = 1;
- else
- bank->sectors[i].is_erased = 0;
- }
-
- return retval;
-}
-
static int xmc4xxx_write_page(struct flash_bank *bank, const uint8_t *pg_buf,
uint32_t offset, bool user_config)
{
@@ -944,6 +851,14 @@ static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_
break;
}
break;
+ case 0x300:
+ dev_str = "XMC4300";
+
+ switch (rev_id) {
+ case 0x1:
+ rev_str = "AA";
+ }
+ break;
case 0x400:
dev_str = "XMC4400";
@@ -1437,7 +1352,7 @@ struct flash_driver xmc4xxx_flash = {
.read = default_flash_read,
.probe = xmc4xxx_probe,
.auto_probe = xmc4xxx_probe,
- .erase_check = xmc4xxx_flash_blank_check,
+ .erase_check = default_flash_blank_check,
.info = xmc4xxx_get_info_command,
.protect_check = xmc4xxx_protect_check,
.protect = xmc4xxx_protect,