Merge branch 'remotes/openocd/master' into riscv64
Merged 1025be363e
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.
This commit is contained in:
+10
-20
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+38
-41
@@ -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
|
||||
%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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+64
-66
@@ -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
|
||||
%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
|
||||
|
||||
noinst_HEADERS = \
|
||||
core.h \
|
||||
cfi.h \
|
||||
driver.h \
|
||||
imp.h \
|
||||
non_cfi.h \
|
||||
ocl.h \
|
||||
spi.h
|
||||
|
||||
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
|
||||
|
||||
+542
-23
@@ -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,10 +881,10 @@ static const struct sam4_chip_details all_sam4_details[] = {
|
||||
},
|
||||
},
|
||||
|
||||
/*atsam4s4a - LQFP48/BGA48*/
|
||||
/*atsam4s4c - LQFP100/BGA100*/
|
||||
{
|
||||
.chipid_cidr = 0x288b09e0,
|
||||
.name = "at91sam4s4a",
|
||||
.chipid_cidr = 0x28ab09e0,
|
||||
.name = "at91sam4s4c",
|
||||
.total_flash_size = 256 * 1024,
|
||||
.total_sram_size = 64 * 1024,
|
||||
.n_gpnvms = 2,
|
||||
@@ -711,7 +898,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 +915,177 @@ static const struct sam4_chip_details all_sam4_details[] = {
|
||||
},
|
||||
},
|
||||
|
||||
/*at91sam4sd32c*/
|
||||
/*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",
|
||||
.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,
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/*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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+61
-47
@@ -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);
|
||||
|
||||
res = samd_check_error(bank->target);
|
||||
}
|
||||
|
||||
/* Access through AHB is stalled while flash is being programmed */
|
||||
usleep(200);
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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},
|
||||
|
||||
+30
-30
@@ -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_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(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_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(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, 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;
|
||||
|
||||
+14
-7
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+76
-120
@@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
buffer += thisrun_count * 4;
|
||||
address += thisrun_count * 4;
|
||||
wcount -= thisrun_count;
|
||||
}
|
||||
} 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:
|
||||
|
||||
+13
-4
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+61
-15
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
* RM0394 (STM32L43x/44x/45x/46x)
|
||||
* http://www.st.com/resource/en/reference_manual/dm00151940.pdf
|
||||
*
|
||||
* STM32L476RG Datasheet (for erase timing)
|
||||
* http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00108832.pdf
|
||||
* 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:
|
||||
|
||||
+73
-116
@@ -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;
|
||||
for (unsigned int i = 0; i < info->num_revs; i++)
|
||||
if (rev_id == info->revs[i].rev)
|
||||
rev_str = info->revs[i].str;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+32
-23
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+13
-98
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user