diff options
author | Tim Newsome <tim@sifive.com> | 2017-06-13 11:52:50 -0700 |
---|---|---|
committer | Tim Newsome <tim@sifive.com> | 2017-06-13 11:52:50 -0700 |
commit | 845c2f6b692736d3f6ee113908b98cb60ec60119 (patch) | |
tree | 32b9315ff67d97c397184dfe98b7523fed95dcb1 /src/flash | |
parent | 7af58e6283c8e7d350b6b55c93a1d326326ed831 (diff) | |
parent | 1025be363e2bf42f1613083223a2322cc3a9bd4c (diff) | |
download | riscv-openocd-845c2f6b692736d3f6ee113908b98cb60ec60119.zip riscv-openocd-845c2f6b692736d3f6ee113908b98cb60ec60119.tar.gz riscv-openocd-845c2f6b692736d3f6ee113908b98cb60ec60119.tar.bz2 |
Merge branch 'remotes/openocd/master' into riscv64
Merged 1025be363e2bf42f1613083223a2322cc3a9bd4c
Conflicts:
src/flash/nor/Makefile.am
src/rtos/Makefile.am
src/rtos/rtos.c
src/target/Makefile.am
src/target/target.c
src/target/target_type.h
Doesn't build yet, but I fixed the conflicts that git pointed out.
Diffstat (limited to 'src/flash')
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(®_params[0], "r0", 32, PARAM_OUT); /* *pLW (*buffer) */ - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* faddr */ - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of words to program */ + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* address */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* word count */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_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(®_params[0], "r0", 32, PARAM_OUT); - buf_set_u32(reg_params[0].value, 0, 32, address); - - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - buf_set_u32(reg_params[1].value, 0, 32, count); - - init_reg_param(®_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(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_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, |