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:
+49
-80
@@ -1,60 +1,41 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libopenocd.la
|
||||
bin_PROGRAMS += %D%/openocd
|
||||
|
||||
SUBDIRS = \
|
||||
jtag \
|
||||
helper \
|
||||
target \
|
||||
transport \
|
||||
flash \
|
||||
svf \
|
||||
xsvf \
|
||||
pld \
|
||||
server \
|
||||
rtos
|
||||
%C%_openocd_SOURCES = \
|
||||
%D%/main.c
|
||||
|
||||
noinst_LTLIBRARIES = libopenocd.la
|
||||
bin_PROGRAMS = openocd
|
||||
%C%_libopenocd_la_SOURCES = \
|
||||
%D%/hello.c %D%/hello.h \
|
||||
%D%/openocd.c %D%/openocd.h
|
||||
|
||||
MAINFILE = main.c
|
||||
%C%_openocd_LDADD = %D%/libopenocd.la
|
||||
|
||||
openocd_SOURCES = $(MAINFILE)
|
||||
openocd_LDADD = libopenocd.la
|
||||
%C%_openocd_LDADD += $(MINGWLDADD)
|
||||
|
||||
if INTERNAL_JIMTCL
|
||||
openocd_LDADD += $(top_builddir)/jimtcl/libjim.a
|
||||
%C%_openocd_LDADD += $(top_builddir)/jimtcl/libjim.a
|
||||
else
|
||||
openocd_LDADD += -ljim
|
||||
%C%_openocd_LDADD += -ljim
|
||||
endif
|
||||
|
||||
if ULINK
|
||||
openocd_LDADD += -lm
|
||||
endif
|
||||
|
||||
libopenocd_la_SOURCES = \
|
||||
hello.c \
|
||||
openocd.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
hello.h \
|
||||
openocd.h
|
||||
|
||||
libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
|
||||
%C%_libopenocd_la_CPPFLAGS =
|
||||
|
||||
# banner output includes RELSTR appended to $VERSION from the configure script
|
||||
# guess-rev.sh returns either a repository version ID or "-snapshot"
|
||||
if RELEASE
|
||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
||||
libopenocd_la_CPPFLAGS += -DGITVERSION=\"\"
|
||||
%C%_libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
||||
%C%_libopenocd_la_CPPFLAGS += -DGITVERSION=\"\"
|
||||
else
|
||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
||||
libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
|
||||
%C%_libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
||||
%C%_libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
|
||||
%C%_libopenocd_la_CPPFLAGS += -DPKGBLDDATE=\"`date +%F-%R`\"
|
||||
endif
|
||||
|
||||
# add default CPPFLAGS
|
||||
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
||||
%C%_libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
||||
|
||||
# the library search path.
|
||||
libopenocd_la_LDFLAGS = $(all_libraries)
|
||||
%C%_libopenocd_la_LDFLAGS = $(all_libraries)
|
||||
|
||||
if IS_MINGW
|
||||
MINGWLDADD = -lws2_32
|
||||
@@ -62,55 +43,43 @@ else
|
||||
MINGWLDADD =
|
||||
endif
|
||||
|
||||
libopenocd_la_LIBADD = \
|
||||
$(top_builddir)/src/xsvf/libxsvf.la \
|
||||
$(top_builddir)/src/svf/libsvf.la \
|
||||
$(top_builddir)/src/pld/libpld.la \
|
||||
$(top_builddir)/src/jtag/libjtag.la \
|
||||
$(top_builddir)/src/transport/libtransport.la \
|
||||
$(top_builddir)/src/flash/libflash.la \
|
||||
$(top_builddir)/src/target/libtarget.la \
|
||||
$(top_builddir)/src/server/libserver.la \
|
||||
$(top_builddir)/src/rtos/librtos.la \
|
||||
$(top_builddir)/src/helper/libhelper.la \
|
||||
$(LIBFTDI_LIBS) $(MINGWLDADD) \
|
||||
$(HIDAPI_LIBS) $(LIBUSB0_LIBS) $(LIBUSB1_LIBS)
|
||||
%C%_libopenocd_la_LIBADD = \
|
||||
%D%/xsvf/libxsvf.la \
|
||||
%D%/svf/libsvf.la \
|
||||
%D%/pld/libpld.la \
|
||||
%D%/jtag/libjtag.la \
|
||||
%D%/transport/libtransport.la \
|
||||
%D%/flash/libflash.la \
|
||||
%D%/target/libtarget.la \
|
||||
%D%/server/libserver.la \
|
||||
%D%/rtos/librtos.la \
|
||||
%D%/helper/libhelper.la
|
||||
|
||||
STARTUP_TCL_SRCS = \
|
||||
$(srcdir)/helper/startup.tcl \
|
||||
$(srcdir)/jtag/startup.tcl \
|
||||
$(srcdir)/target/startup.tcl \
|
||||
$(srcdir)/flash/startup.tcl \
|
||||
$(srcdir)/server/startup.tcl
|
||||
BIN2C = $(srcdir)/%D%/helper/bin2char.sh
|
||||
|
||||
EXTRA_DIST = $(STARTUP_TCL_SRCS)
|
||||
STARTUP_TCL_SRCS =
|
||||
EXTRA_DIST += $(STARTUP_TCL_SRCS)
|
||||
|
||||
BUILT_SOURCES = startup_tcl.inc
|
||||
|
||||
startup.tcl: $(STARTUP_TCL_SRCS)
|
||||
cat $^ > $@
|
||||
|
||||
BIN2C = $(top_srcdir)/src/helper/bin2char.sh
|
||||
BUILT_SOURCES += %D%/startup_tcl.inc
|
||||
|
||||
# Convert .tcl to c-array
|
||||
startup_tcl.inc: startup.tcl $(BIN2C)
|
||||
$(BIN2C) < $< > $@ || { rm -f $@; false; }
|
||||
%D%/startup_tcl.inc: $(STARTUP_TCL_SRCS)
|
||||
cat $^ | $(BIN2C) > $@ || { rm -f $@; false; }
|
||||
|
||||
# add generated files to make clean list
|
||||
CLEANFILES = startup.tcl startup_tcl.inc
|
||||
CLEANFILES += %D%/startup_tcl.inc
|
||||
|
||||
# we do not want generated file in the dist
|
||||
dist-hook:
|
||||
rm -f $(distdir)/startup_tcl.inc
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
# The "quick" target builds executables & reinstalls the executables
|
||||
# Primary use: developer types to quicken the edit/compile/debug
|
||||
# cycle. by not requiring a "full build and full install". Note the
|
||||
# assumption is: You are only rebuilding the EXE.... and everything
|
||||
# else is/was previously installed.
|
||||
#
|
||||
# use at your own risk
|
||||
quick: all install-binPROGRAMS
|
||||
#dist-hook:
|
||||
# rm -f $(distdir)/%D%/startup_tcl.inc
|
||||
|
||||
include %D%/helper/Makefile.am
|
||||
include %D%/jtag/Makefile.am
|
||||
include %D%/transport/Makefile.am
|
||||
include %D%/xsvf/Makefile.am
|
||||
include %D%/svf/Makefile.am
|
||||
include %D%/target/Makefile.am
|
||||
include %D%/rtos/Makefile.am
|
||||
include %D%/server/Makefile.am
|
||||
include %D%/flash/Makefile.am
|
||||
include %D%/pld/Makefile.am
|
||||
|
||||
+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,
|
||||
|
||||
+38
-45
@@ -1,56 +1,49 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libhelper.la
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libhelper.la
|
||||
%C%_libhelper_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS)
|
||||
|
||||
CONFIGFILES = options.c time_support_common.c
|
||||
|
||||
libhelper_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS)
|
||||
|
||||
libhelper_la_SOURCES = \
|
||||
binarybuffer.c \
|
||||
$(CONFIGFILES) \
|
||||
configuration.c \
|
||||
log.c \
|
||||
command.c \
|
||||
time_support.c \
|
||||
replacements.c \
|
||||
fileio.c \
|
||||
util.c \
|
||||
jep106.c \
|
||||
jim-nvp.c
|
||||
%C%_libhelper_la_SOURCES = \
|
||||
%D%/binarybuffer.c \
|
||||
%D%/options.c \
|
||||
%D%/time_support_common.c \
|
||||
%D%/configuration.c \
|
||||
%D%/log.c \
|
||||
%D%/command.c \
|
||||
%D%/time_support.c \
|
||||
%D%/replacements.c \
|
||||
%D%/fileio.c \
|
||||
%D%/util.c \
|
||||
%D%/jep106.c \
|
||||
%D%/jim-nvp.c \
|
||||
%D%/binarybuffer.h \
|
||||
%D%/configuration.h \
|
||||
%D%/ioutil.h \
|
||||
%D%/list.h \
|
||||
%D%/util.h \
|
||||
%D%/types.h \
|
||||
%D%/log.h \
|
||||
%D%/command.h \
|
||||
%D%/time_support.h \
|
||||
%D%/replacements.h \
|
||||
%D%/fileio.h \
|
||||
%D%/system.h \
|
||||
%D%/jep106.h \
|
||||
%D%/jep106.inc \
|
||||
%D%/jim-nvp.h
|
||||
|
||||
if IOUTIL
|
||||
libhelper_la_SOURCES += ioutil.c
|
||||
%C%_libhelper_la_SOURCES += %D%/ioutil.c
|
||||
else
|
||||
libhelper_la_SOURCES += ioutil_stubs.c
|
||||
%C%_libhelper_la_SOURCES += %D%/ioutil_stubs.c
|
||||
endif
|
||||
|
||||
libhelper_la_CFLAGS =
|
||||
%C%_libhelper_la_CFLAGS = $(AM_CFLAGS)
|
||||
if IS_MINGW
|
||||
# FD_* macros are sloppy with their signs on MinGW32 platform
|
||||
libhelper_la_CFLAGS += -Wno-sign-compare
|
||||
%C%_libhelper_la_CFLAGS += -Wno-sign-compare
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
binarybuffer.h \
|
||||
configuration.h \
|
||||
ioutil.h \
|
||||
list.h \
|
||||
util.h \
|
||||
types.h \
|
||||
log.h \
|
||||
command.h \
|
||||
time_support.h \
|
||||
replacements.h \
|
||||
fileio.h \
|
||||
system.h \
|
||||
bin2char.sh \
|
||||
jep106.h \
|
||||
jep106.inc \
|
||||
update_jep106.pl \
|
||||
jim-nvp.h
|
||||
|
||||
EXTRA_DIST = startup.tcl
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
STARTUP_TCL_SRCS += %D%/startup.tcl
|
||||
EXTRA_DIST += \
|
||||
%D%/bin2char.sh \
|
||||
%D%/update_jep106.pl
|
||||
|
||||
+61
-15
@@ -45,6 +45,11 @@ static const unsigned char bit_reverse_table256[] = {
|
||||
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
||||
};
|
||||
|
||||
static const char hex_digits[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
void *buf_cpy(const void *from, void *_to, unsigned size)
|
||||
{
|
||||
if (NULL == from || NULL == _to)
|
||||
@@ -369,31 +374,72 @@ void bit_copy_discard(struct bit_copy_queue *q)
|
||||
}
|
||||
}
|
||||
|
||||
int unhexify(char *bin, const char *hex, int count)
|
||||
/**
|
||||
* Convert a string of hexadecimal pairs into its binary
|
||||
* representation.
|
||||
*
|
||||
* @param[out] bin Buffer to store binary representation. The buffer size must
|
||||
* be at least @p count.
|
||||
* @param[in] hex String with hexadecimal pairs to convert into its binary
|
||||
* representation.
|
||||
* @param[in] count Number of hexadecimal pairs to convert.
|
||||
*
|
||||
* @return The number of converted hexadecimal pairs.
|
||||
*/
|
||||
size_t unhexify(uint8_t *bin, const char *hex, size_t count)
|
||||
{
|
||||
int i, tmp;
|
||||
size_t i;
|
||||
char tmp;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (sscanf(hex + (2 * i), "%02x", &tmp) != 1)
|
||||
return i;
|
||||
bin[i] = tmp;
|
||||
if (!bin || !hex)
|
||||
return 0;
|
||||
|
||||
memset(bin, 0, count);
|
||||
|
||||
for (i = 0; i < 2 * count; i++) {
|
||||
if (hex[i] >= 'a' && hex[i] <= 'f')
|
||||
tmp = hex[i] - 'a' + 10;
|
||||
else if (hex[i] >= 'A' && hex[i] <= 'F')
|
||||
tmp = hex[i] - 'A' + 10;
|
||||
else if (hex[i] >= '0' && hex[i] <= '9')
|
||||
tmp = hex[i] - '0';
|
||||
else
|
||||
return i / 2;
|
||||
|
||||
bin[i / 2] |= tmp << (4 * ((i + 1) % 2));
|
||||
}
|
||||
|
||||
return i;
|
||||
return i / 2;
|
||||
}
|
||||
|
||||
int hexify(char *hex, const char *bin, int count, int out_maxlen)
|
||||
/**
|
||||
* Convert binary data into a string of hexadecimal pairs.
|
||||
*
|
||||
* @param[out] hex Buffer to store string of hexadecimal pairs. The buffer size
|
||||
* must be at least @p length.
|
||||
* @param[in] bin Buffer with binary data to convert into hexadecimal pairs.
|
||||
* @param[in] count Number of bytes to convert.
|
||||
* @param[in] length Maximum number of characters, including null-terminator,
|
||||
* to store into @p hex.
|
||||
*
|
||||
* @returns The length of the converted string excluding null-terminator.
|
||||
*/
|
||||
size_t hexify(char *hex, const uint8_t *bin, size_t count, size_t length)
|
||||
{
|
||||
int i, cmd_len = 0;
|
||||
size_t i;
|
||||
uint8_t tmp;
|
||||
|
||||
/* May use a length, or a null-terminated string as input. */
|
||||
if (count == 0)
|
||||
count = strlen(bin);
|
||||
if (!length)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
cmd_len += snprintf(hex + cmd_len, out_maxlen - cmd_len, "%02x", bin[i] & 0xff);
|
||||
for (i = 0; i < length - 1 && i < 2 * count; i++) {
|
||||
tmp = (bin[i / 2] >> (4 * ((i + 1) % 2))) & 0x0f;
|
||||
hex[i] = hex_digits[tmp];
|
||||
}
|
||||
|
||||
return cmd_len;
|
||||
hex[i] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void buffer_shr(void *_buf, unsigned buf_len, unsigned count)
|
||||
|
||||
@@ -234,8 +234,8 @@ void bit_copy_discard(struct bit_copy_queue *q);
|
||||
|
||||
/* functions to convert to/from hex encoded buffer
|
||||
* used in ti-icdi driver and gdb server */
|
||||
int unhexify(char *bin, const char *hex, int count);
|
||||
int hexify(char *hex, const char *bin, int count, int out_maxlen);
|
||||
size_t unhexify(uint8_t *bin, const char *hex, size_t count);
|
||||
size_t hexify(char *hex, const uint8_t *bin, size_t count, size_t out_maxlen);
|
||||
void buffer_shr(void *_buf, unsigned buf_len, unsigned count);
|
||||
|
||||
#endif /* OPENOCD_HELPER_BINARYBUFFER_H */
|
||||
|
||||
@@ -1410,6 +1410,8 @@ DEFINE_PARSE_ULONGLONG(_u32, uint32_t, 0, UINT32_MAX)
|
||||
DEFINE_PARSE_ULONGLONG(_u16, uint16_t, 0, UINT16_MAX)
|
||||
DEFINE_PARSE_ULONGLONG(_u8, uint8_t, 0, UINT8_MAX)
|
||||
|
||||
DEFINE_PARSE_ULONGLONG(_target_addr, target_addr_t, 0, TARGET_ADDR_MAX)
|
||||
|
||||
#define DEFINE_PARSE_LONGLONG(name, type, min, max) \
|
||||
DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong)
|
||||
DEFINE_PARSE_LONGLONG(_int, int, n < INT_MIN, INT_MAX)
|
||||
|
||||
@@ -357,10 +357,13 @@ DECLARE_PARSE_WRAPPER(_u16, uint16_t);
|
||||
DECLARE_PARSE_WRAPPER(_u8, uint8_t);
|
||||
|
||||
DECLARE_PARSE_WRAPPER(_int, int);
|
||||
DECLARE_PARSE_WRAPPER(_s64, int64_t);
|
||||
DECLARE_PARSE_WRAPPER(_s32, int32_t);
|
||||
DECLARE_PARSE_WRAPPER(_s16, int16_t);
|
||||
DECLARE_PARSE_WRAPPER(_s8, int8_t);
|
||||
|
||||
DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t);
|
||||
|
||||
/**
|
||||
* @brief parses the string @a in into @a out as a @a type, or prints
|
||||
* a command error and passes the error code to the caller. If an error
|
||||
@@ -382,6 +385,9 @@ DECLARE_PARSE_WRAPPER(_s8, int8_t);
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define COMMAND_PARSE_ADDRESS(in, out) \
|
||||
COMMAND_PARSE_NUMBER(target_addr, in, out)
|
||||
|
||||
/**
|
||||
* Parse the string @c as a binary parameter, storing the boolean value
|
||||
* in @c out. The strings @c on and @c off are used to match different
|
||||
|
||||
+41
-4
@@ -884,7 +884,7 @@
|
||||
[7][0x01 - 1] = "Siklu Communication Ltd.",
|
||||
[7][0x02 - 1] = "A Force Manufacturing Ltd.",
|
||||
[7][0x03 - 1] = "Strontium",
|
||||
[7][0x04 - 1] = "Abilis Systems",
|
||||
[7][0x04 - 1] = "ALi Corp (Abilis Systems)",
|
||||
[7][0x05 - 1] = "Siglead, Inc.",
|
||||
[7][0x06 - 1] = "Ubicom, Inc.",
|
||||
[7][0x07 - 1] = "Unifosa Corporation",
|
||||
@@ -893,7 +893,7 @@
|
||||
[7][0x0a - 1] = "Visipro.",
|
||||
[7][0x0b - 1] = "EKMemory",
|
||||
[7][0x0c - 1] = "Microelectronics Institute ZTE",
|
||||
[7][0x0d - 1] = "Cognovo Ltd.",
|
||||
[7][0x0d - 1] = "u-blox AG",
|
||||
[7][0x0e - 1] = "Carry Technology Co. Ltd.",
|
||||
[7][0x0f - 1] = "Nokia",
|
||||
[7][0x10 - 1] = "King Tiger Technology",
|
||||
@@ -1101,12 +1101,12 @@
|
||||
[8][0x5c - 1] = "Vitesse Enterprise Co.",
|
||||
[8][0x5d - 1] = "Foxtronn International Corporation",
|
||||
[8][0x5e - 1] = "Bretelon Inc.",
|
||||
[8][0x5f - 1] = "Zbit Semiconductor, Inc.",
|
||||
[8][0x5f - 1] = "Graphcore",
|
||||
[8][0x60 - 1] = "Eoplex Inc",
|
||||
[8][0x61 - 1] = "MaxLinear, Inc.",
|
||||
[8][0x62 - 1] = "ETA Devices",
|
||||
[8][0x63 - 1] = "LOKI",
|
||||
[8][0x64 - 1] = "IMS Semiconductor Co., Ltd",
|
||||
[8][0x64 - 1] = "IMS Electronics Co., Ltd.",
|
||||
[8][0x65 - 1] = "Dosilicon Co., Ltd.",
|
||||
[8][0x66 - 1] = "Dolphin Integration",
|
||||
[8][0x67 - 1] = "Shenzhen Mic Electronics Technology",
|
||||
@@ -1116,4 +1116,41 @@
|
||||
[8][0x6b - 1] = "Kingred Electronic Technology Ltd.",
|
||||
[8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.",
|
||||
[8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.",
|
||||
[8][0x6e - 1] = "Crocus Technology Inc.",
|
||||
[8][0x6f - 1] = "Creative Chips GmbH",
|
||||
[8][0x70 - 1] = "GE Aviation Systems LLC.",
|
||||
[8][0x71 - 1] = "Asgard",
|
||||
[8][0x72 - 1] = "Good Wealth Technology Ltd.",
|
||||
[8][0x73 - 1] = "TriCor Technologies",
|
||||
[8][0x74 - 1] = "Nova-Systems GmbH",
|
||||
[8][0x75 - 1] = "JUHOR",
|
||||
[8][0x76 - 1] = "Zhuhai Douke Commerce Co. Ltd.",
|
||||
[8][0x77 - 1] = "DSL Memory",
|
||||
[8][0x78 - 1] = "Anvo-Systems Dresden GmbH",
|
||||
[8][0x79 - 1] = "Realtek",
|
||||
[8][0x7a - 1] = "AltoBeam",
|
||||
[8][0x7b - 1] = "Wave Computing",
|
||||
[8][0x7c - 1] = "Beijing TrustNet Technology Co. Ltd.",
|
||||
[8][0x7d - 1] = "Innovium, Inc.",
|
||||
[8][0x7e - 1] = "Starsway Technology Limited",
|
||||
[9][0x01 - 1] = "Weltronics Co. LTD",
|
||||
[9][0x02 - 1] = "VMware, Inc.",
|
||||
[9][0x03 - 1] = "Hewlett Packard Enterprise",
|
||||
[9][0x04 - 1] = "INTENSO",
|
||||
[9][0x05 - 1] = "Puya Semiconductor",
|
||||
[9][0x06 - 1] = "MEMORFI",
|
||||
[9][0x07 - 1] = "MSC Technologies GmbH",
|
||||
[9][0x08 - 1] = "Txrui",
|
||||
[9][0x09 - 1] = "SiFive, Inc.",
|
||||
[9][0x0a - 1] = "Spreadtrum Communications",
|
||||
[9][0x0b - 1] = "Paragon Technology (Shenzhen) Ltd.",
|
||||
[9][0x0c - 1] = "UMAX Technology",
|
||||
[9][0x0d - 1] = "Shenzhen Yong Sheng Technology",
|
||||
[9][0x0e - 1] = "SNOAMOO (Shenzhen Kai Zhuo Yue)",
|
||||
[9][0x0f - 1] = "Daten Tecnologia LTDA",
|
||||
[9][0x10 - 1] = "Shenzhen XinRuiYan Electronics",
|
||||
[9][0x11 - 1] = "Eta Compute",
|
||||
[9][0x12 - 1] = "Energous",
|
||||
[9][0x13 - 1] = "Raspberry Pi Trading Ltd.",
|
||||
[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co. Ltd.",
|
||||
/* EOF */
|
||||
|
||||
+34
-17
@@ -191,6 +191,30 @@ void log_printf(enum log_levels level,
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_vprintf_lf(enum log_levels level, const char *file, unsigned line,
|
||||
const char *function, const char *format, va_list args)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
count++;
|
||||
|
||||
if (level > debug_level)
|
||||
return;
|
||||
|
||||
tmp = alloc_vprintf(format, args);
|
||||
|
||||
if (!tmp)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Note: alloc_vprintf() guarantees that the buffer is at least one
|
||||
* character longer.
|
||||
*/
|
||||
strcat(tmp, "\n");
|
||||
log_puts(level, file, line, function, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
void log_printf_lf(enum log_levels level,
|
||||
const char *file,
|
||||
unsigned line,
|
||||
@@ -198,23 +222,10 @@ void log_printf_lf(enum log_levels level,
|
||||
const char *format,
|
||||
...)
|
||||
{
|
||||
char *string;
|
||||
va_list ap;
|
||||
|
||||
count++;
|
||||
if (level > debug_level)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
string = alloc_vprintf(format, ap);
|
||||
if (string != NULL) {
|
||||
strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one
|
||||
*char longer */
|
||||
log_puts(level, file, line, function, string);
|
||||
free(string);
|
||||
}
|
||||
|
||||
log_vprintf_lf(level, file, line, function, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -240,9 +251,15 @@ COMMAND_HANDLER(handle_log_output_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
FILE *file = fopen(CMD_ARGV[0], "w");
|
||||
|
||||
if (file)
|
||||
log_output = file;
|
||||
if (file == NULL) {
|
||||
LOG_ERROR("failed to open output log '%s'", CMD_ARGV[0]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (log_output != stderr && log_output != NULL) {
|
||||
/* Close previous log file, if it was open and wasn't stderr. */
|
||||
fclose(log_output);
|
||||
}
|
||||
log_output = file;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -60,6 +60,8 @@ enum log_levels {
|
||||
void log_printf(enum log_levels level, const char *file, unsigned line,
|
||||
const char *function, const char *format, ...)
|
||||
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6)));
|
||||
void log_vprintf_lf(enum log_levels level, const char *file, unsigned line,
|
||||
const char *function, const char *format, va_list args);
|
||||
void log_printf_lf(enum log_levels level, const char *file, unsigned line,
|
||||
const char *function, const char *format, ...)
|
||||
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6)));
|
||||
|
||||
+139
-38
@@ -29,6 +29,15 @@
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#if IS_DARWIN
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSCTL_H
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
static int help_flag, version_flag;
|
||||
|
||||
static const struct option long_options[] = {
|
||||
@@ -50,52 +59,129 @@ int configuration_output_handler(struct command_context *context, const char *li
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static char *find_suffix(const char *text, const char *suffix)
|
||||
/* Return the canonical path to the directory the openocd executable is in.
|
||||
* The path should be absolute, use / as path separator and have all symlinks
|
||||
* resolved. The returned string is malloc'd. */
|
||||
static char *find_exe_path(void)
|
||||
{
|
||||
size_t text_len = strlen(text);
|
||||
size_t suffix_len = strlen(suffix);
|
||||
char *exepath = NULL;
|
||||
|
||||
if (suffix_len == 0)
|
||||
return (char *)text + text_len;
|
||||
do {
|
||||
#if IS_WIN32 && !IS_CYGWIN
|
||||
exepath = malloc(MAX_PATH);
|
||||
if (exepath == NULL)
|
||||
break;
|
||||
GetModuleFileName(NULL, exepath, MAX_PATH);
|
||||
|
||||
if (suffix_len > text_len || strncmp(text + text_len - suffix_len, suffix, suffix_len) != 0)
|
||||
return NULL; /* Not a suffix of text */
|
||||
/* Convert path separators to UNIX style, should work on Windows also. */
|
||||
for (char *p = exepath; *p; p++) {
|
||||
if (*p == '\\')
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
return (char *)text + text_len - suffix_len;
|
||||
}
|
||||
#elif IS_DARWIN
|
||||
exepath = malloc(PROC_PIDPATHINFO_MAXSIZE);
|
||||
if (exepath == NULL)
|
||||
break;
|
||||
if (proc_pidpath(getpid(), exepath, PROC_PIDPATHINFO_MAXSIZE) <= 0) {
|
||||
free(exepath);
|
||||
exepath = NULL;
|
||||
}
|
||||
|
||||
#elif defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PATHNAME) /* *BSD */
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
char *path = malloc(PATH_MAX);
|
||||
if (path == NULL)
|
||||
break;
|
||||
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
||||
size_t size = PATH_MAX;
|
||||
|
||||
if (sysctl(mib, (u_int)ARRAY_SIZE(mib), path, &size, NULL, 0) != 0)
|
||||
break;
|
||||
|
||||
#ifdef HAVE_REALPATH
|
||||
exepath = realpath(path, NULL);
|
||||
free(path);
|
||||
#else
|
||||
exepath = path;
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_REALPATH) /* Assume POSIX.1-2008 */
|
||||
/* Try Unices in order of likelihood. */
|
||||
exepath = realpath("/proc/self/exe", NULL); /* Linux/Cygwin */
|
||||
if (exepath == NULL)
|
||||
exepath = realpath("/proc/self/path/a.out", NULL); /* Solaris */
|
||||
if (exepath == NULL)
|
||||
exepath = realpath("/proc/curproc/file", NULL); /* FreeBSD (Should be covered above) */
|
||||
#endif
|
||||
} while (0);
|
||||
|
||||
if (exepath != NULL) {
|
||||
/* Strip executable file name, leaving path */
|
||||
*strrchr(exepath, '/') = '\0';
|
||||
} else {
|
||||
LOG_WARNING("Could not determine executable path, using configured BINDIR.");
|
||||
LOG_DEBUG("BINDIR = %s", BINDIR);
|
||||
#ifdef HAVE_REALPATH
|
||||
exepath = realpath(BINDIR, NULL);
|
||||
#else
|
||||
exepath = strdup(BINDIR);
|
||||
#endif
|
||||
}
|
||||
|
||||
return exepath;
|
||||
}
|
||||
|
||||
static char *find_relative_path(const char *from, const char *to)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Skip common /-separated parts of from and to */
|
||||
i = 0;
|
||||
for (size_t n = 0; from[n] == to[n]; n++) {
|
||||
if (from[n] == '\0') {
|
||||
i = n;
|
||||
break;
|
||||
}
|
||||
if (from[n] == '/')
|
||||
i = n + 1;
|
||||
}
|
||||
from += i;
|
||||
to += i;
|
||||
|
||||
/* Count number of /-separated non-empty parts of from */
|
||||
i = 0;
|
||||
while (from[0] != '\0') {
|
||||
if (from[0] != '/')
|
||||
i++;
|
||||
char *next = strchr(from, '/');
|
||||
if (next == NULL)
|
||||
break;
|
||||
from = next + 1;
|
||||
}
|
||||
|
||||
/* Prepend that number of ../ in front of to */
|
||||
char *relpath = malloc(i * 3 + strlen(to) + 1);
|
||||
relpath[0] = '\0';
|
||||
for (size_t n = 0; n < i; n++)
|
||||
strcat(relpath, "../");
|
||||
strcat(relpath, to);
|
||||
|
||||
return relpath;
|
||||
}
|
||||
|
||||
static void add_default_dirs(void)
|
||||
{
|
||||
const char *run_prefix;
|
||||
char *path;
|
||||
|
||||
#ifdef _WIN32
|
||||
char strExePath[MAX_PATH];
|
||||
GetModuleFileName(NULL, strExePath, MAX_PATH);
|
||||
|
||||
/* Strip executable file name, leaving path */
|
||||
*strrchr(strExePath, '\\') = '\0';
|
||||
|
||||
/* Convert path separators to UNIX style, should work on Windows also. */
|
||||
for (char *p = strExePath; *p; p++) {
|
||||
if (*p == '\\')
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
char *end_of_prefix = find_suffix(strExePath, BINDIR);
|
||||
if (end_of_prefix != NULL)
|
||||
*end_of_prefix = '\0';
|
||||
|
||||
run_prefix = strExePath;
|
||||
#else
|
||||
run_prefix = "";
|
||||
#endif
|
||||
char *exepath = find_exe_path();
|
||||
char *bin2data = find_relative_path(BINDIR, PKGDATADIR);
|
||||
|
||||
LOG_DEBUG("bindir=%s", BINDIR);
|
||||
LOG_DEBUG("pkgdatadir=%s", PKGDATADIR);
|
||||
LOG_DEBUG("run_prefix=%s", run_prefix);
|
||||
LOG_DEBUG("exepath=%s", exepath);
|
||||
LOG_DEBUG("bin2data=%s", bin2data);
|
||||
|
||||
/*
|
||||
* The directory containing OpenOCD-supplied scripts should be
|
||||
@@ -129,17 +215,20 @@ static void add_default_dirs(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
path = alloc_printf("%s%s%s", run_prefix, PKGDATADIR, "/site");
|
||||
path = alloc_printf("%s/%s/%s", exepath, bin2data, "site");
|
||||
if (path) {
|
||||
add_script_search_dir(path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
path = alloc_printf("%s%s%s", run_prefix, PKGDATADIR, "/scripts");
|
||||
path = alloc_printf("%s/%s/%s", exepath, bin2data, "scripts");
|
||||
if (path) {
|
||||
add_script_search_dir(path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
free(exepath);
|
||||
free(bin2data);
|
||||
}
|
||||
|
||||
int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
|
||||
@@ -178,8 +267,10 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
|
||||
case 'd': /* --debug | -d */
|
||||
{
|
||||
char *command = alloc_printf("debug_level %s", optarg ? optarg : "3");
|
||||
command_run_line(cmd_ctx, command);
|
||||
int retval = command_run_line(cmd_ctx, command);
|
||||
free(command);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
break;
|
||||
}
|
||||
case 'l': /* --log_output | -l */
|
||||
@@ -200,16 +291,26 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
|
||||
LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; "
|
||||
"log_output openocd.log\"' instead.");
|
||||
break;
|
||||
default: /* '?' */
|
||||
/* getopt will emit an error message, all we have to do is bail. */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
/* Catch extra arguments on the command line. */
|
||||
LOG_OUTPUT("Unexpected command line argument: %s\n", argv[optind]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (help_flag) {
|
||||
LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n");
|
||||
LOG_OUTPUT("--help | -h\tdisplay this help\n");
|
||||
LOG_OUTPUT("--version | -v\tdisplay OpenOCD version\n");
|
||||
LOG_OUTPUT("--file | -f\tuse configuration file <name>\n");
|
||||
LOG_OUTPUT("--search | -s\tdir to search for config files and scripts\n");
|
||||
LOG_OUTPUT("--debug | -d\tset debug level <0-3>\n");
|
||||
LOG_OUTPUT("--debug | -d\tset debug level to 3\n");
|
||||
LOG_OUTPUT(" | -d<n>\tset debug level to <level>\n");
|
||||
LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
|
||||
LOG_OUTPUT("--command | -c\trun <command>\n");
|
||||
exit(-1);
|
||||
|
||||
+28
-2
@@ -296,14 +296,21 @@ static inline int parity_u32(uint32_t x)
|
||||
*/
|
||||
|
||||
#if !defined(_STDINT_H)
|
||||
#define PRIx32 "x"
|
||||
#define PRId32 "d"
|
||||
#define SCNx32 "x"
|
||||
#define PRIi32 "i"
|
||||
#define PRIo32 "o"
|
||||
#define PRIu32 "u"
|
||||
#define PRIx32 "x"
|
||||
#define PRIX32 "X"
|
||||
#define SCNx32 "x"
|
||||
#define PRId8 PRId32
|
||||
#define SCNx64 "llx"
|
||||
#define PRId64 "lld"
|
||||
#define PRIi64 "lli"
|
||||
#define PRIo64 "llo"
|
||||
#define PRIu64 "llu"
|
||||
#define PRIx64 "llx"
|
||||
#define PRIX64 "llX"
|
||||
|
||||
typedef CYG_ADDRWORD intptr_t;
|
||||
typedef int64_t intmax_t;
|
||||
@@ -337,4 +344,23 @@ typedef uint64_t uintmax_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if BUILD_TARGET64
|
||||
typedef uint64_t target_addr_t;
|
||||
#define TARGET_ADDR_MAX UINT64_MAX
|
||||
#define TARGET_PRIdADDR PRId64
|
||||
#define TARGET_PRIuADDR PRIu64
|
||||
#define TARGET_PRIoADDR PRIo64
|
||||
#define TARGET_PRIxADDR PRIx64
|
||||
#define TARGET_PRIXADDR PRIX64
|
||||
#else
|
||||
typedef uint32_t target_addr_t;
|
||||
#define TARGET_ADDR_MAX UINT32_MAX
|
||||
#define TARGET_PRIdADDR PRId32
|
||||
#define TARGET_PRIuADDR PRIu32
|
||||
#define TARGET_PRIoADDR PRIo32
|
||||
#define TARGET_PRIxADDR PRIx32
|
||||
#define TARGET_PRIXADDR PRIX32
|
||||
#endif
|
||||
#define TARGET_ADDR_FMT "0x%8.8" TARGET_PRIxADDR
|
||||
|
||||
#endif /* OPENOCD_HELPER_TYPES_H */
|
||||
|
||||
+40
-54
@@ -1,86 +1,72 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libjtag.la
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libjtag.la
|
||||
JTAG_SRCS =
|
||||
%C%_libjtag_la_LIBADD =
|
||||
|
||||
SUBDIRS =
|
||||
DRIVERFILES =
|
||||
libjtag_la_LIBADD =
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
BUILT_SOURCES =
|
||||
|
||||
BUILT_SOURCES += minidriver_imp.h
|
||||
CLEANFILES += minidriver_imp.h
|
||||
BUILT_SOURCES += %D%/minidriver_imp.h
|
||||
CLEANFILES += %D%/minidriver_imp.h
|
||||
|
||||
if MINIDRIVER
|
||||
|
||||
if ZY1000
|
||||
DRIVERFILES += zy1000/zy1000.c
|
||||
JTAG_MINIDRIVER_DIR = $(srcdir)/zy1000
|
||||
JTAG_SRCS += %D%/zy1000/zy1000.c
|
||||
JTAG_MINIDRIVER_DIR = %D%/zy1000
|
||||
endif
|
||||
if MINIDRIVER_DUMMY
|
||||
DRIVERFILES += minidummy/minidummy.c commands.c
|
||||
JTAG_MINIDRIVER_DIR = $(srcdir)/minidummy
|
||||
JTAG_SRCS += %D%/minidummy/minidummy.c %D%/commands.c
|
||||
JTAG_MINIDRIVER_DIR = %D%/minidummy
|
||||
endif
|
||||
|
||||
MINIDRIVER_IMP_DIR = $(srcdir)/minidriver
|
||||
MINIDRIVER_IMP_DIR = %D%/minidriver
|
||||
|
||||
jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h
|
||||
%D%/jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h
|
||||
cp $< $@
|
||||
|
||||
BUILT_SOURCES += jtag_minidriver.h
|
||||
BUILT_SOURCES += %D%/jtag_minidriver.h
|
||||
|
||||
CLEANFILES += jtag_minidriver.h
|
||||
CLEANFILES += %D%/jtag_minidriver.h
|
||||
|
||||
else
|
||||
|
||||
MINIDRIVER_IMP_DIR = $(srcdir)/drivers
|
||||
DRIVERFILES += commands.c
|
||||
MINIDRIVER_IMP_DIR = %D%/drivers
|
||||
JTAG_SRCS += %D%/commands.c
|
||||
|
||||
if HLADAPTER
|
||||
SUBDIRS += hla
|
||||
libjtag_la_LIBADD += $(top_builddir)/src/jtag/hla/libocdhla.la
|
||||
include %D%/hla/Makefile.am
|
||||
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la
|
||||
endif
|
||||
|
||||
if AICE
|
||||
SUBDIRS += aice
|
||||
libjtag_la_LIBADD += $(top_builddir)/src/jtag/aice/libocdaice.la
|
||||
include %D%/aice/Makefile.am
|
||||
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/aice/libocdaice.la
|
||||
endif
|
||||
|
||||
SUBDIRS += drivers
|
||||
libjtag_la_LIBADD += $(top_builddir)/src/jtag/drivers/libocdjtagdrivers.la
|
||||
|
||||
include %D%/drivers/Makefile.am
|
||||
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la
|
||||
|
||||
endif
|
||||
|
||||
# endif // MINIDRIVER
|
||||
|
||||
minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h
|
||||
%D%/minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h
|
||||
cp $< $@
|
||||
|
||||
|
||||
libjtag_la_SOURCES = \
|
||||
adapter.c \
|
||||
core.c \
|
||||
interface.c \
|
||||
interfaces.c \
|
||||
tcl.c \
|
||||
$(DRIVERFILES)
|
||||
%C%_libjtag_la_SOURCES = \
|
||||
%D%/adapter.c \
|
||||
%D%/core.c \
|
||||
%D%/interface.c \
|
||||
%D%/interfaces.c \
|
||||
%D%/tcl.c \
|
||||
%D%/commands.h \
|
||||
%D%/driver.h \
|
||||
%D%/interface.h \
|
||||
%D%/interfaces.h \
|
||||
%D%/minidriver.h \
|
||||
%D%/jtag.h \
|
||||
%D%/minidriver/minidriver_imp.h \
|
||||
%D%/minidummy/jtag_minidriver.h \
|
||||
%D%/swd.h \
|
||||
%D%/tcl.h \
|
||||
$(JTAG_SRCS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
commands.h \
|
||||
driver.h \
|
||||
interface.h \
|
||||
interfaces.h \
|
||||
minidriver.h \
|
||||
jtag.h \
|
||||
minidriver/minidriver_imp.h \
|
||||
minidummy/jtag_minidriver.h \
|
||||
swd.h \
|
||||
tcl.h
|
||||
|
||||
EXTRA_DIST = startup.tcl
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
STARTUP_TCL_SRCS += %D%/startup.tcl
|
||||
|
||||
+13
-26
@@ -1,27 +1,14 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libocdaice.la
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src/jtag/drivers $(LIBUSB1_CFLAGS) $(LIBUSB0_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libocdaice.la
|
||||
|
||||
libocdaice_la_SOURCES = \
|
||||
$(AICEFILES)
|
||||
|
||||
AICEFILES =
|
||||
|
||||
if AICE
|
||||
AICEFILES += aice_transport.c
|
||||
AICEFILES += aice_interface.c
|
||||
AICEFILES += aice_port.c
|
||||
AICEFILES += aice_usb.c
|
||||
AICEFILES += aice_pipe.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
aice_transport.h \
|
||||
aice_interface.h \
|
||||
aice_port.h \
|
||||
aice_usb.h \
|
||||
aice_pipe.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) $(LIBUSB0_CFLAGS)
|
||||
%C%_libocdaice_la_SOURCES = \
|
||||
%D%/aice_transport.c \
|
||||
%D%/aice_interface.c \
|
||||
%D%/aice_port.c \
|
||||
%D%/aice_usb.c \
|
||||
%D%/aice_pipe.c \
|
||||
%D%/aice_transport.h \
|
||||
%D%/aice_interface.h \
|
||||
%D%/aice_port.h \
|
||||
%D%/aice_usb.h \
|
||||
%D%/aice_pipe.h
|
||||
|
||||
@@ -786,8 +786,8 @@ static int aice_pipe_memory_mode(uint32_t coreid, enum nds_memory_select mem_sel
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int aice_pipe_read_tlb(uint32_t coreid, uint32_t virtual_address,
|
||||
uint32_t *physical_address)
|
||||
static int aice_pipe_read_tlb(uint32_t coreid, target_addr_t virtual_address,
|
||||
target_addr_t *physical_address)
|
||||
{
|
||||
char line[AICE_PIPE_MAXLINE];
|
||||
char command[AICE_PIPE_MAXLINE];
|
||||
|
||||
@@ -180,7 +180,7 @@ struct aice_port_api_s {
|
||||
int (*memory_mode)(uint32_t coreid, enum nds_memory_select mem_select);
|
||||
|
||||
/** */
|
||||
int (*read_tlb)(uint32_t coreid, uint32_t virtual_address, uint32_t *physical_address);
|
||||
int (*read_tlb)(uint32_t coreid, target_addr_t virtual_address, target_addr_t *physical_address);
|
||||
|
||||
/** */
|
||||
int (*cache_ctl)(uint32_t coreid, uint32_t subtype, uint32_t address);
|
||||
|
||||
@@ -2135,10 +2135,16 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
||||
|
||||
/* usb_set_configuration required under win32 */
|
||||
jtag_libusb_set_configuration(devh, 0);
|
||||
jtag_libusb_claim_interface(devh, 0);
|
||||
|
||||
unsigned int aice_read_ep;
|
||||
unsigned int aice_write_ep;
|
||||
jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1);
|
||||
#ifdef HAVE_LIBUSB1
|
||||
jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, LIBUSB_TRANSFER_TYPE_BULK);
|
||||
#else
|
||||
jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, USB_ENDPOINT_TYPE_BULK);
|
||||
#endif
|
||||
LOG_DEBUG("aice_read_ep=0x%x, aice_write_ep=0x%x", aice_read_ep, aice_write_ep);
|
||||
|
||||
aice_handler.usb_read_ep = aice_read_ep;
|
||||
aice_handler.usb_write_ep = aice_write_ep;
|
||||
@@ -3424,10 +3430,10 @@ static int aice_usb_memory_mode(uint32_t coreid, enum nds_memory_select mem_sele
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aice_usb_read_tlb(uint32_t coreid, uint32_t virtual_address,
|
||||
uint32_t *physical_address)
|
||||
static int aice_usb_read_tlb(uint32_t coreid, target_addr_t virtual_address,
|
||||
target_addr_t *physical_address)
|
||||
{
|
||||
LOG_DEBUG("aice_usb_read_tlb, virtual address: 0x%08" PRIx32, virtual_address);
|
||||
LOG_DEBUG("aice_usb_read_tlb, virtual address: 0x%08" TARGET_PRIxADDR, virtual_address);
|
||||
|
||||
uint32_t instructions[4];
|
||||
uint32_t probe_result;
|
||||
|
||||
+2
-2
@@ -1831,11 +1831,11 @@ void jtag_set_reset_config(enum reset_types type)
|
||||
|
||||
int jtag_get_trst(void)
|
||||
{
|
||||
return jtag_trst;
|
||||
return jtag_trst == 1;
|
||||
}
|
||||
int jtag_get_srst(void)
|
||||
{
|
||||
return jtag_srst;
|
||||
return jtag_srst == 1;
|
||||
}
|
||||
|
||||
void jtag_set_nsrst_delay(unsigned delay)
|
||||
|
||||
+106
-100
@@ -1,173 +1,179 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libocdjtagdrivers.la
|
||||
%C%_libocdjtagdrivers_la_LIBADD =
|
||||
|
||||
noinst_LTLIBRARIES = libocdjtagdrivers.la
|
||||
libocdjtagdrivers_la_LIBADD =
|
||||
%C%_libocdjtagdrivers_la_SOURCES = \
|
||||
$(DRIVERFILES) \
|
||||
$(DRIVERHEADERS)
|
||||
|
||||
libocdjtagdrivers_la_SOURCES = \
|
||||
$(DRIVERFILES)
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
libocdjtagdrivers_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) \
|
||||
$(LIBUSB0_CFLAGS) $(HIDAPI_CFLAGS) $(LIBFTDI_CFLAGS)
|
||||
ULINK_FIRMWARE = %D%/OpenULINK
|
||||
|
||||
ULINK_FIRMWARE = $(srcdir)/OpenULINK
|
||||
|
||||
EXTRA_DIST = $(ULINK_FIRMWARE) \
|
||||
usb_blaster/README.CheapClone \
|
||||
Makefile.rlink \
|
||||
rlink_call.m4 \
|
||||
rlink_init.m4
|
||||
EXTRA_DIST += $(ULINK_FIRMWARE) \
|
||||
%D%/usb_blaster/README.CheapClone \
|
||||
%D%/Makefile.rlink \
|
||||
%D%/rlink_call.m4 \
|
||||
%D%/rlink_init.m4
|
||||
|
||||
DRIVERFILES =
|
||||
SUBDIRS=
|
||||
|
||||
if JLINK
|
||||
if INTERNAL_LIBJAYLINK
|
||||
SUBDIRS += libjaylink
|
||||
|
||||
libjaylink_internal_la_SOURCES = jlink.c
|
||||
libjaylink_internal_la_LIBADD = libjaylink/libjaylink/libjaylink.la
|
||||
libjaylink_internal_la_CPPFLAGS = -I$(builddir)/libjaylink/libjaylink \
|
||||
-I$(srcdir)/libjaylink $(AM_CPPFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES += libjaylink_internal.la
|
||||
libocdjtagdrivers_la_LIBADD += libjaylink_internal.la
|
||||
else
|
||||
DRIVERFILES += jlink.c
|
||||
endif
|
||||
endif
|
||||
|
||||
# Standard Driver: common files
|
||||
DRIVERFILES += driver.c
|
||||
DRIVERFILES += %D%/driver.c
|
||||
|
||||
if USE_LIBUSB1
|
||||
DRIVERFILES += libusb1_common.c
|
||||
DRIVERFILES += %D%/libusb1_common.c
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB1_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS)
|
||||
endif
|
||||
|
||||
if USE_LIBUSB0
|
||||
DRIVERFILES += usb_common.c
|
||||
DRIVERFILES += %D%/usb_common.c
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS)
|
||||
if !USE_LIBUSB1
|
||||
DRIVERFILES += libusb0_common.c
|
||||
DRIVERFILES += %D%/libusb0_common.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_LIBFTDI
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBFTDI_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(LIBFTDI_LIBS)
|
||||
endif
|
||||
|
||||
if USE_HIDAPI
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(HIDAPI_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(HIDAPI_LIBS)
|
||||
endif
|
||||
|
||||
if USE_LIBJAYLINK
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBJAYLINK_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(LIBJAYLINK_LIBS)
|
||||
endif
|
||||
|
||||
if JLINK
|
||||
DRIVERFILES += %D%/jlink.c
|
||||
if INTERNAL_LIBJAYLINK
|
||||
SUBDIRS += %D%/libjaylink
|
||||
DIST_SUBDIRS += %D%/libjaylink
|
||||
|
||||
%C%_libocdjtagdrivers_la_LIBADD += %D%/libjaylink/libjaylink/libjaylink.la
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += -I$(builddir)/%D%/libjaylink/libjaylink -I$(srcdir)/%D%/libjaylink
|
||||
endif
|
||||
endif
|
||||
|
||||
if BITBANG
|
||||
DRIVERFILES += bitbang.c
|
||||
DRIVERFILES += %D%/bitbang.c
|
||||
endif
|
||||
if PARPORT
|
||||
DRIVERFILES += parport.c
|
||||
DRIVERFILES += %D%/parport.c
|
||||
endif
|
||||
if DUMMY
|
||||
DRIVERFILES += dummy.c
|
||||
endif
|
||||
if FT2232_DRIVER
|
||||
DRIVERFILES += ft2232.c
|
||||
DRIVERFILES += %D%/dummy.c
|
||||
endif
|
||||
if FTDI
|
||||
DRIVERFILES += ftdi.c mpsse.c
|
||||
DRIVERFILES += %D%/ftdi.c %D%/mpsse.c
|
||||
endif
|
||||
if JTAG_VPI
|
||||
DRIVERFILES += jtag_vpi.c
|
||||
DRIVERFILES += %D%/jtag_vpi.c
|
||||
endif
|
||||
if USB_BLASTER_DRIVER
|
||||
SUBDIRS += usb_blaster
|
||||
libocdjtagdrivers_la_LIBADD += $(top_builddir)/src/jtag/drivers/usb_blaster/libocdusbblaster.la
|
||||
%C%_libocdjtagdrivers_la_LIBADD += %D%/usb_blaster/libocdusbblaster.la
|
||||
include %D%/usb_blaster/Makefile.am
|
||||
endif
|
||||
if AMTJTAGACCEL
|
||||
DRIVERFILES += amt_jtagaccel.c
|
||||
DRIVERFILES += %D%/amt_jtagaccel.c
|
||||
endif
|
||||
if EP93XX
|
||||
DRIVERFILES += ep93xx.c
|
||||
DRIVERFILES += %D%/ep93xx.c
|
||||
endif
|
||||
if AT91RM9200
|
||||
DRIVERFILES += at91rm9200.c
|
||||
DRIVERFILES += %D%/at91rm9200.c
|
||||
endif
|
||||
if GW16012
|
||||
DRIVERFILES += gw16012.c
|
||||
DRIVERFILES += %D%/gw16012.c
|
||||
endif
|
||||
if BITQ
|
||||
DRIVERFILES += bitq.c
|
||||
DRIVERFILES += %D%/bitq.c
|
||||
endif
|
||||
if PRESTO_DRIVER
|
||||
DRIVERFILES += presto.c
|
||||
if PRESTO
|
||||
DRIVERFILES += %D%/presto.c
|
||||
endif
|
||||
if USBPROG
|
||||
DRIVERFILES += usbprog.c
|
||||
DRIVERFILES += %D%/usbprog.c
|
||||
endif
|
||||
if RLINK
|
||||
DRIVERFILES += rlink.c rlink_speed_table.c
|
||||
DRIVERFILES += %D%/rlink.c %D%/rlink_speed_table.c
|
||||
endif
|
||||
if ULINK
|
||||
DRIVERFILES += ulink.c
|
||||
DRIVERFILES += %D%/ulink.c
|
||||
ulinkdir = $(pkgdatadir)/OpenULINK
|
||||
dist_ulink_DATA = $(ULINK_FIRMWARE)/ulink_firmware.hex
|
||||
%C%_libocdjtagdrivers_la_LIBADD += -lm
|
||||
endif
|
||||
if VSLLINK
|
||||
DRIVERFILES += versaloon/usbtoxxx/usbtogpio.c
|
||||
DRIVERFILES += versaloon/usbtoxxx/usbtojtagraw.c
|
||||
DRIVERFILES += versaloon/usbtoxxx/usbtoswd.c
|
||||
DRIVERFILES += versaloon/usbtoxxx/usbtopwr.c
|
||||
DRIVERFILES += versaloon/usbtoxxx/usbtoxxx.c
|
||||
DRIVERFILES += versaloon/versaloon.c
|
||||
DRIVERFILES += vsllink.c
|
||||
DRIVERFILES += %D%/versaloon/usbtoxxx/usbtogpio.c
|
||||
DRIVERFILES += %D%/versaloon/usbtoxxx/usbtojtagraw.c
|
||||
DRIVERFILES += %D%/versaloon/usbtoxxx/usbtoswd.c
|
||||
DRIVERFILES += %D%/versaloon/usbtoxxx/usbtopwr.c
|
||||
DRIVERFILES += %D%/versaloon/usbtoxxx/usbtoxxx.c
|
||||
DRIVERFILES += %D%/versaloon/versaloon.c
|
||||
DRIVERFILES += %D%/vsllink.c
|
||||
endif
|
||||
if ARMJTAGEW
|
||||
DRIVERFILES += arm-jtag-ew.c
|
||||
DRIVERFILES += %D%/arm-jtag-ew.c
|
||||
endif
|
||||
if BUSPIRATE
|
||||
DRIVERFILES += buspirate.c
|
||||
DRIVERFILES += %D%/buspirate.c
|
||||
endif
|
||||
if REMOTE_BITBANG
|
||||
DRIVERFILES += remote_bitbang.c
|
||||
DRIVERFILES += %D%/remote_bitbang.c
|
||||
endif
|
||||
if HLADAPTER
|
||||
DRIVERFILES += stlink_usb.c
|
||||
DRIVERFILES += ti_icdi_usb.c
|
||||
DRIVERFILES += %D%/stlink_usb.c
|
||||
DRIVERFILES += %D%/ti_icdi_usb.c
|
||||
endif
|
||||
if OSBDM
|
||||
DRIVERFILES += osbdm.c
|
||||
DRIVERFILES += %D%/osbdm.c
|
||||
endif
|
||||
if OPENDOUS
|
||||
DRIVERFILES += opendous.c
|
||||
DRIVERFILES += %D%/opendous.c
|
||||
endif
|
||||
if SYSFSGPIO
|
||||
DRIVERFILES += sysfsgpio.c
|
||||
DRIVERFILES += %D%/sysfsgpio.c
|
||||
endif
|
||||
if BCM2835GPIO
|
||||
DRIVERFILES += bcm2835gpio.c
|
||||
DRIVERFILES += %D%/bcm2835gpio.c
|
||||
endif
|
||||
|
||||
if OPENJTAG
|
||||
DRIVERFILES += openjtag.c
|
||||
DRIVERFILES += %D%/openjtag.c
|
||||
endif
|
||||
|
||||
if CMSIS_DAP
|
||||
DRIVERFILES += cmsis_dap_usb.c
|
||||
DRIVERFILES += %D%/cmsis_dap_usb.c
|
||||
endif
|
||||
if IMX_GPIO
|
||||
DRIVERFILES += %D%/imx_gpio.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
bitbang.h \
|
||||
bitq.h \
|
||||
ftd2xx_common.h \
|
||||
libusb0_common.h \
|
||||
libusb1_common.h \
|
||||
libusb_common.h \
|
||||
minidriver_imp.h \
|
||||
mpsse.h \
|
||||
rlink.h \
|
||||
rlink_dtc_cmd.h \
|
||||
rlink_ep1_cmd.h \
|
||||
rlink_st7.h \
|
||||
usb_common.h \
|
||||
versaloon/usbtoxxx/usbtoxxx.h \
|
||||
versaloon/usbtoxxx/usbtoxxx_internal.h \
|
||||
versaloon/versaloon.h \
|
||||
versaloon/versaloon_include.h \
|
||||
versaloon/versaloon_internal.h
|
||||
|
||||
DIST_SUBDIRS = usb_blaster
|
||||
|
||||
if INTERNAL_LIBJAYLINK
|
||||
DIST_SUBDIRS += libjaylink
|
||||
if KITPROG
|
||||
DRIVERFILES += %D%/kitprog.c
|
||||
endif
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
DRIVERHEADERS = \
|
||||
%D%/bitbang.h \
|
||||
%D%/bitq.h \
|
||||
%D%/libusb0_common.h \
|
||||
%D%/libusb1_common.h \
|
||||
%D%/libusb_common.h \
|
||||
%D%/minidriver_imp.h \
|
||||
%D%/mpsse.h \
|
||||
%D%/rlink.h \
|
||||
%D%/rlink_dtc_cmd.h \
|
||||
%D%/rlink_ep1_cmd.h \
|
||||
%D%/rlink_st7.h \
|
||||
%D%/usb_common.h \
|
||||
%D%/versaloon/usbtoxxx/usbtoxxx.h \
|
||||
%D%/versaloon/usbtoxxx/usbtoxxx_internal.h \
|
||||
%D%/versaloon/versaloon.h \
|
||||
%D%/versaloon/versaloon_include.h \
|
||||
%D%/versaloon/versaloon_internal.h
|
||||
|
||||
|
||||
@@ -468,8 +468,8 @@ static int bcm2835gpio_init(void)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* set 16mA drive strength */
|
||||
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000018 + 7;
|
||||
/* set 4mA drive strength, slew rate limited, hysteresis on */
|
||||
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
|
||||
|
||||
tdo_gpio_mode = MODE_GPIO(tdo_gpio);
|
||||
tdi_gpio_mode = MODE_GPIO(tdi_gpio);
|
||||
|
||||
@@ -118,6 +118,13 @@ static bool swd_mode;
|
||||
* Bit 7: nRESET
|
||||
*/
|
||||
|
||||
#define SWJ_PIN_TCK (1<<0)
|
||||
#define SWJ_PIN_TMS (1<<1)
|
||||
#define SWJ_PIN_TDI (1<<2)
|
||||
#define SWJ_PIN_TDO (1<<3)
|
||||
#define SWJ_PIN_TRST (1<<5)
|
||||
#define SWJ_PIN_SRST (1<<7)
|
||||
|
||||
/* CMSIS-DAP SWD Commands */
|
||||
#define CMD_DAP_SWD_CONFIGURE 0x13
|
||||
|
||||
@@ -309,9 +316,11 @@ static int cmsis_dap_usb_open(void)
|
||||
int packet_size = PACKET_SIZE;
|
||||
|
||||
/* atmel cmsis-dap uses 512 byte reports */
|
||||
/* except when it doesn't e.g. with mEDBG on SAMD10 Xplained
|
||||
* board */
|
||||
/* TODO: HID report descriptor should be parsed instead of
|
||||
* hardcoding a match by VID */
|
||||
if (target_vid == 0x03eb)
|
||||
if (target_vid == 0x03eb && target_pid != 0x2145)
|
||||
packet_size = 512 + 1;
|
||||
|
||||
cmsis_dap_handle->packet_buffer = malloc(packet_size);
|
||||
@@ -764,12 +773,12 @@ static int cmsis_dap_get_status(void)
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
LOG_INFO("SWCLK/TCK = %d SWDIO/TMS = %d TDI = %d TDO = %d nTRST = %d nRESET = %d",
|
||||
(d & (0x01 << 0)) ? 1 : 0, /* Bit 0: SWCLK/TCK */
|
||||
(d & (0x01 << 1)) ? 1 : 0, /* Bit 1: SWDIO/TMS */
|
||||
(d & (0x01 << 2)) ? 1 : 0, /* Bit 2: TDI */
|
||||
(d & (0x01 << 3)) ? 1 : 0, /* Bit 3: TDO */
|
||||
(d & (0x01 << 5)) ? 1 : 0, /* Bit 5: nTRST */
|
||||
(d & (0x01 << 7)) ? 1 : 0); /* Bit 7: nRESET */
|
||||
(d & SWJ_PIN_TCK) ? 1 : 0,
|
||||
(d & SWJ_PIN_TMS) ? 1 : 0,
|
||||
(d & SWJ_PIN_TDI) ? 1 : 0,
|
||||
(d & SWJ_PIN_TDO) ? 1 : 0,
|
||||
(d & SWJ_PIN_TRST) ? 1 : 0,
|
||||
(d & SWJ_PIN_SRST) ? 1 : 0);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -812,7 +821,13 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s);
|
||||
retval = cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Atmel EDBG needs renew clock setting after SWJ_Sequence
|
||||
* otherwise default frequency is used */
|
||||
return cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz());
|
||||
}
|
||||
|
||||
static int cmsis_dap_swd_open(void)
|
||||
@@ -990,8 +1005,17 @@ static int cmsis_dap_quit(void)
|
||||
|
||||
static void cmsis_dap_execute_reset(struct jtag_command *cmd)
|
||||
{
|
||||
int retval = cmsis_dap_cmd_DAP_SWJ_Pins(cmd->cmd.reset->srst ? 0 : (1 << 7), \
|
||||
(1 << 7), 0, NULL);
|
||||
/* Set both TRST and SRST even if they're not enabled as
|
||||
* there's no way to tristate them */
|
||||
uint8_t pins = 0;
|
||||
|
||||
if (!cmd->cmd.reset->srst)
|
||||
pins |= SWJ_PIN_SRST;
|
||||
if (!cmd->cmd.reset->trst)
|
||||
pins |= SWJ_PIN_TRST;
|
||||
|
||||
int retval = cmsis_dap_cmd_DAP_SWJ_Pins(pins,
|
||||
SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("CMSIS-DAP: Interface reset failed");
|
||||
}
|
||||
@@ -1475,13 +1499,11 @@ static int cmsis_dap_execute_queue(void)
|
||||
|
||||
static int cmsis_dap_speed(int speed)
|
||||
{
|
||||
if (speed > DAP_MAX_CLOCK) {
|
||||
LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", speed, DAP_MAX_CLOCK);
|
||||
speed = DAP_MAX_CLOCK;
|
||||
}
|
||||
if (speed > DAP_MAX_CLOCK)
|
||||
LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed);
|
||||
|
||||
if (speed == 0) {
|
||||
LOG_INFO("RTCK not supported");
|
||||
LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
|
||||
return ERROR_JTAG_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||
* *
|
||||
* Written by Arnim Laeuger, 2008 (from urjtag) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_JTAG_DRIVERS_FTD2XX_COMMON_H
|
||||
#define OPENOCD_JTAG_DRIVERS_FTD2XX_COMMON_H
|
||||
|
||||
#if ((BUILD_FT2232_FTD2XX == 1) || (BUILD_PRESTO_FTD2XX == 1) || (BUILD_USB_BLASTER_FTD2XX == 1))
|
||||
#include <ftd2xx.h>
|
||||
|
||||
static const char *ftd2xx_status_string(FT_STATUS status)
|
||||
{
|
||||
switch (status) {
|
||||
case FT_OK: return "OK";
|
||||
case FT_INVALID_HANDLE: return "invalid handle";
|
||||
case FT_DEVICE_NOT_FOUND: return "device not found";
|
||||
case FT_DEVICE_NOT_OPENED: return "device not opened";
|
||||
case FT_IO_ERROR: return "io error";
|
||||
case FT_INSUFFICIENT_RESOURCES: return "insufficient resources";
|
||||
case FT_INVALID_PARAMETER: return "invalid parameter";
|
||||
case FT_INVALID_BAUD_RATE: return "invalid baud rate";
|
||||
|
||||
case FT_DEVICE_NOT_OPENED_FOR_ERASE: return "device not opened for erase";
|
||||
case FT_DEVICE_NOT_OPENED_FOR_WRITE: return "device not opened for write";
|
||||
case FT_FAILED_TO_WRITE_DEVICE: return "failed to write device";
|
||||
case FT_EEPROM_READ_FAILED: return "eeprom read failed";
|
||||
case FT_EEPROM_WRITE_FAILED: return "eeprom write failed";
|
||||
case FT_EEPROM_ERASE_FAILED: return "eeprom erase failed";
|
||||
case FT_EEPROM_NOT_PRESENT: return "eeprom not present";
|
||||
case FT_EEPROM_NOT_PROGRAMMED: return "eeprom not programmed";
|
||||
case FT_INVALID_ARGS: return "invalid args";
|
||||
case FT_NOT_SUPPORTED: return "not supported";
|
||||
case FT_OTHER_ERROR: return "other error";
|
||||
}
|
||||
|
||||
return "undefined FTD2xx error";
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_FTD2XX_COMMON_H */
|
||||
@@ -0,0 +1,552 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2017 by Grzegorz Kostka, kostka.grzegorz@gmail.com *
|
||||
* *
|
||||
* Based on bcm2835gpio.c *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/interface.h>
|
||||
#include "bitbang.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define IMX_GPIO_BASE 0x0209c000
|
||||
#define IMX_GPIO_SIZE 0x00004000
|
||||
#define IMX_GPIO_REGS_COUNT 8
|
||||
|
||||
static uint32_t imx_gpio_peri_base = IMX_GPIO_BASE;
|
||||
|
||||
struct imx_gpio_regs {
|
||||
uint32_t dr;
|
||||
uint32_t gdir;
|
||||
uint32_t psr;
|
||||
uint32_t icr1;
|
||||
uint32_t icr2;
|
||||
uint32_t imr;
|
||||
uint32_t isr;
|
||||
uint32_t edge_sel;
|
||||
} __attribute__((aligned(IMX_GPIO_SIZE)));
|
||||
|
||||
static int dev_mem_fd;
|
||||
static volatile struct imx_gpio_regs *pio_base;
|
||||
|
||||
/* GPIO setup functions */
|
||||
static inline bool gpio_mode_get(int g)
|
||||
{
|
||||
return pio_base[g / 32].gdir >> (g & 0x1F) & 1;
|
||||
}
|
||||
|
||||
static inline void gpio_mode_input_set(int g)
|
||||
{
|
||||
pio_base[g / 32].gdir &= ~(1u << (g & 0x1F));
|
||||
}
|
||||
|
||||
static inline void gpio_mode_output_set(int g)
|
||||
{
|
||||
pio_base[g / 32].gdir |= (1u << (g & 0x1F));
|
||||
}
|
||||
|
||||
static inline void gpio_mode_set(int g, int m)
|
||||
{
|
||||
(m) ? gpio_mode_output_set(g) : gpio_mode_input_set(g);
|
||||
}
|
||||
|
||||
static inline void gpio_set(int g)
|
||||
{
|
||||
pio_base[g / 32].dr |= (1u << (g & 0x1F));
|
||||
}
|
||||
|
||||
static inline void gpio_clear(int g)
|
||||
{
|
||||
pio_base[g / 32].dr &= ~(1u << (g & 0x1F));
|
||||
}
|
||||
|
||||
static inline bool gpio_level(int g)
|
||||
{
|
||||
return pio_base[g / 32].dr >> (g & 0x1F) & 1;
|
||||
}
|
||||
|
||||
static int imx_gpio_read(void);
|
||||
static void imx_gpio_write(int tck, int tms, int tdi);
|
||||
static void imx_gpio_reset(int trst, int srst);
|
||||
|
||||
static int imx_gpio_swdio_read(void);
|
||||
static void imx_gpio_swdio_drive(bool is_output);
|
||||
|
||||
static int imx_gpio_init(void);
|
||||
static int imx_gpio_quit(void);
|
||||
|
||||
static struct bitbang_interface imx_gpio_bitbang = {
|
||||
.read = imx_gpio_read,
|
||||
.write = imx_gpio_write,
|
||||
.reset = imx_gpio_reset,
|
||||
.swdio_read = imx_gpio_swdio_read,
|
||||
.swdio_drive = imx_gpio_swdio_drive,
|
||||
.blink = NULL
|
||||
};
|
||||
|
||||
/* GPIO numbers for each signal. Negative values are invalid */
|
||||
static int tck_gpio = -1;
|
||||
static int tck_gpio_mode;
|
||||
static int tms_gpio = -1;
|
||||
static int tms_gpio_mode;
|
||||
static int tdi_gpio = -1;
|
||||
static int tdi_gpio_mode;
|
||||
static int tdo_gpio = -1;
|
||||
static int tdo_gpio_mode;
|
||||
static int trst_gpio = -1;
|
||||
static int trst_gpio_mode;
|
||||
static int srst_gpio = -1;
|
||||
static int srst_gpio_mode;
|
||||
static int swclk_gpio = -1;
|
||||
static int swclk_gpio_mode;
|
||||
static int swdio_gpio = -1;
|
||||
static int swdio_gpio_mode;
|
||||
|
||||
/* Transition delay coefficients. Tuned for IMX6UL 528MHz. Adjusted
|
||||
* experimentally for:10kHz, 100Khz, 500KHz. Speeds above 800Khz are impossible
|
||||
* to reach via memory mapped method (at least for IMX6UL@528MHz).
|
||||
* Measured mmap raw GPIO toggling speed on IMX6UL@528MHz: 1.3MHz.
|
||||
*/
|
||||
static int speed_coeff = 50000;
|
||||
static int speed_offset = 100;
|
||||
static unsigned int jtag_delay;
|
||||
|
||||
static int imx_gpio_read(void)
|
||||
{
|
||||
return gpio_level(tdo_gpio);
|
||||
}
|
||||
|
||||
static void imx_gpio_write(int tck, int tms, int tdi)
|
||||
{
|
||||
tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio);
|
||||
tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio);
|
||||
tck ? gpio_set(tck_gpio) : gpio_clear(tck_gpio);
|
||||
|
||||
for (unsigned int i = 0; i < jtag_delay; i++)
|
||||
asm volatile ("");
|
||||
}
|
||||
|
||||
static void imx_gpio_swd_write(int tck, int tms, int tdi)
|
||||
{
|
||||
tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio);
|
||||
tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio);
|
||||
|
||||
for (unsigned int i = 0; i < jtag_delay; i++)
|
||||
asm volatile ("");
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void imx_gpio_reset(int trst, int srst)
|
||||
{
|
||||
if (trst_gpio != -1)
|
||||
trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio);
|
||||
|
||||
if (srst_gpio != -1)
|
||||
srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio);
|
||||
}
|
||||
|
||||
static void imx_gpio_swdio_drive(bool is_output)
|
||||
{
|
||||
if (is_output)
|
||||
gpio_mode_output_set(swdio_gpio);
|
||||
else
|
||||
gpio_mode_input_set(swdio_gpio);
|
||||
}
|
||||
|
||||
static int imx_gpio_swdio_read(void)
|
||||
{
|
||||
return gpio_level(swdio_gpio);
|
||||
}
|
||||
|
||||
static int imx_gpio_khz(int khz, int *jtag_speed)
|
||||
{
|
||||
if (!khz) {
|
||||
LOG_DEBUG("RCLK not supported");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
*jtag_speed = speed_coeff/khz - speed_offset;
|
||||
if (*jtag_speed < 0)
|
||||
*jtag_speed = 0;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx_gpio_speed_div(int speed, int *khz)
|
||||
{
|
||||
*khz = speed_coeff/(speed + speed_offset);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx_gpio_speed(int speed)
|
||||
{
|
||||
jtag_delay = speed;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int is_gpio_valid(int gpio)
|
||||
{
|
||||
return gpio >= 0 && gpio < 32 * IMX_GPIO_REGS_COUNT;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionums)
|
||||
{
|
||||
if (CMD_ARGC == 4) {
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
|
||||
} else if (CMD_ARGC != 0) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
command_print(CMD_CTX,
|
||||
"imx_gpio GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
|
||||
tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tck)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio GPIO config: tck = %d", tck_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tms)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio GPIO config: tms = %d", tms_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdo)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio GPIO config: tdo = %d", tdo_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdi)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio GPIO config: tdi = %d", tdi_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_srst)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio GPIO config: srst = %d", srst_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_trst)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio GPIO config: trst = %d", trst_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_swd_gpionums)
|
||||
{
|
||||
if (CMD_ARGC == 2) {
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
|
||||
} else if (CMD_ARGC != 0) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
command_print(CMD_CTX,
|
||||
"imx_gpio GPIO nums: swclk = %d, swdio = %d",
|
||||
swclk_gpio, swdio_gpio);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swclk)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio num: swclk = %d", swclk_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swdio)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
|
||||
|
||||
command_print(CMD_CTX, "imx_gpio num: swdio = %d", swdio_gpio);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_speed_coeffs)
|
||||
{
|
||||
if (CMD_ARGC == 2) {
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(imx_gpio_handle_peripheral_base)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], imx_gpio_peri_base);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration imx_gpio_command_handlers[] = {
|
||||
{
|
||||
.name = "imx_gpio_jtag_nums",
|
||||
.handler = &imx_gpio_handle_jtag_gpionums,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
|
||||
.usage = "(tck tms tdi tdo)* ",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_tck_num",
|
||||
.handler = &imx_gpio_handle_jtag_gpionum_tck,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for tck.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_tms_num",
|
||||
.handler = &imx_gpio_handle_jtag_gpionum_tms,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for tms.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_tdo_num",
|
||||
.handler = &imx_gpio_handle_jtag_gpionum_tdo,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for tdo.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_tdi_num",
|
||||
.handler = &imx_gpio_handle_jtag_gpionum_tdi,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for tdi.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_swd_nums",
|
||||
.handler = &imx_gpio_handle_swd_gpionums,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio numbers for swclk, swdio. (in that order)",
|
||||
.usage = "(swclk swdio)* ",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_swclk_num",
|
||||
.handler = &imx_gpio_handle_swd_gpionum_swclk,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for swclk.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_swdio_num",
|
||||
.handler = &imx_gpio_handle_swd_gpionum_swdio,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for swdio.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_srst_num",
|
||||
.handler = &imx_gpio_handle_jtag_gpionum_srst,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for srst.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_trst_num",
|
||||
.handler = &imx_gpio_handle_jtag_gpionum_trst,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "gpio number for trst.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_speed_coeffs",
|
||||
.handler = &imx_gpio_handle_speed_coeffs,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
|
||||
},
|
||||
{
|
||||
.name = "imx_gpio_peripheral_base",
|
||||
.handler = &imx_gpio_handle_peripheral_base,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "peripheral base to access GPIOs (0x0209c000 for most IMX).",
|
||||
},
|
||||
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface imx_gpio_interface = {
|
||||
.name = "imx_gpio",
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
.transports = imx_gpio_transports,
|
||||
.swd = &bitbang_swd,
|
||||
.speed = imx_gpio_speed,
|
||||
.khz = imx_gpio_khz,
|
||||
.speed_div = imx_gpio_speed_div,
|
||||
.commands = imx_gpio_command_handlers,
|
||||
.init = imx_gpio_init,
|
||||
.quit = imx_gpio_quit,
|
||||
};
|
||||
|
||||
static bool imx_gpio_jtag_mode_possible(void)
|
||||
{
|
||||
if (!is_gpio_valid(tck_gpio))
|
||||
return 0;
|
||||
if (!is_gpio_valid(tms_gpio))
|
||||
return 0;
|
||||
if (!is_gpio_valid(tdi_gpio))
|
||||
return 0;
|
||||
if (!is_gpio_valid(tdo_gpio))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool imx_gpio_swd_mode_possible(void)
|
||||
{
|
||||
if (!is_gpio_valid(swclk_gpio))
|
||||
return 0;
|
||||
if (!is_gpio_valid(swdio_gpio))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int imx_gpio_init(void)
|
||||
{
|
||||
bitbang_interface = &imx_gpio_bitbang;
|
||||
|
||||
LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver");
|
||||
|
||||
if (imx_gpio_jtag_mode_possible()) {
|
||||
if (imx_gpio_swd_mode_possible())
|
||||
LOG_INFO("JTAG and SWD modes enabled");
|
||||
else
|
||||
LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
|
||||
} else if (imx_gpio_swd_mode_possible()) {
|
||||
LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
|
||||
} else {
|
||||
LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (dev_mem_fd < 0) {
|
||||
perror("open");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
|
||||
LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u",
|
||||
sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE);
|
||||
pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, dev_mem_fd, imx_gpio_peri_base);
|
||||
|
||||
if (pio_base == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(dev_mem_fd);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
|
||||
* as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
|
||||
*/
|
||||
if (imx_gpio_jtag_mode_possible()) {
|
||||
tdo_gpio_mode = gpio_mode_get(tdo_gpio);
|
||||
tdi_gpio_mode = gpio_mode_get(tdi_gpio);
|
||||
tck_gpio_mode = gpio_mode_get(tck_gpio);
|
||||
tms_gpio_mode = gpio_mode_get(tms_gpio);
|
||||
|
||||
gpio_clear(tdi_gpio);
|
||||
gpio_clear(tck_gpio);
|
||||
gpio_set(tms_gpio);
|
||||
|
||||
gpio_mode_input_set(tdo_gpio);
|
||||
gpio_mode_output_set(tdi_gpio);
|
||||
gpio_mode_output_set(tck_gpio);
|
||||
gpio_mode_output_set(tms_gpio);
|
||||
}
|
||||
if (imx_gpio_swd_mode_possible()) {
|
||||
swclk_gpio_mode = gpio_mode_get(swclk_gpio);
|
||||
swdio_gpio_mode = gpio_mode_get(swdio_gpio);
|
||||
|
||||
gpio_clear(swdio_gpio);
|
||||
gpio_clear(swclk_gpio);
|
||||
gpio_mode_output_set(swclk_gpio);
|
||||
gpio_mode_output_set(swdio_gpio);
|
||||
}
|
||||
if (trst_gpio != -1) {
|
||||
trst_gpio_mode = gpio_mode_get(trst_gpio);
|
||||
gpio_set(trst_gpio);
|
||||
gpio_mode_output_set(trst_gpio);
|
||||
}
|
||||
if (srst_gpio != -1) {
|
||||
srst_gpio_mode = gpio_mode_get(srst_gpio);
|
||||
gpio_set(srst_gpio);
|
||||
gpio_mode_output_set(srst_gpio);
|
||||
}
|
||||
|
||||
LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
|
||||
"tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
|
||||
tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
|
||||
|
||||
if (swd_mode) {
|
||||
imx_gpio_bitbang.write = imx_gpio_swd_write;
|
||||
bitbang_switch_to_swd();
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx_gpio_quit(void)
|
||||
{
|
||||
if (imx_gpio_jtag_mode_possible()) {
|
||||
gpio_mode_set(tdo_gpio, tdo_gpio_mode);
|
||||
gpio_mode_set(tdi_gpio, tdi_gpio_mode);
|
||||
gpio_mode_set(tck_gpio, tck_gpio_mode);
|
||||
gpio_mode_set(tms_gpio, tms_gpio_mode);
|
||||
}
|
||||
if (imx_gpio_swd_mode_possible()) {
|
||||
gpio_mode_set(swclk_gpio, swclk_gpio_mode);
|
||||
gpio_mode_set(swdio_gpio, swdio_gpio_mode);
|
||||
}
|
||||
if (trst_gpio != -1)
|
||||
gpio_mode_set(trst_gpio, trst_gpio_mode);
|
||||
if (srst_gpio != -1)
|
||||
gpio_mode_set(srst_gpio, srst_gpio_mode);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
+226
-23
@@ -314,12 +314,11 @@ static int jlink_execute_queue(void)
|
||||
static int jlink_speed(int speed)
|
||||
{
|
||||
int ret;
|
||||
uint32_t freq;
|
||||
uint16_t divider;
|
||||
struct jaylink_speed tmp;
|
||||
int max_speed;
|
||||
|
||||
if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) {
|
||||
ret = jaylink_get_speeds(devh, &freq, ÷r);
|
||||
ret = jaylink_get_speeds(devh, &tmp);
|
||||
|
||||
if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("jaylink_get_speeds() failed: %s.",
|
||||
@@ -327,8 +326,8 @@ static int jlink_speed(int speed)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
freq = freq / 1000;
|
||||
max_speed = freq / divider;
|
||||
tmp.freq /= 1000;
|
||||
max_speed = tmp.freq / tmp.div;
|
||||
} else {
|
||||
max_speed = JLINK_MAX_SPEED;
|
||||
}
|
||||
@@ -433,15 +432,16 @@ static int select_interface(void)
|
||||
static int jlink_register(void)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
size_t i;
|
||||
bool handle_found;
|
||||
size_t count;
|
||||
|
||||
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER))
|
||||
return ERROR_OK;
|
||||
|
||||
ret = jaylink_register(devh, &conn, connlist, NULL, NULL);
|
||||
ret = jaylink_register(devh, &conn, connlist, &count);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("jaylink_register() failed: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
return ERROR_FAIL;
|
||||
@@ -449,7 +449,7 @@ static int jlink_register(void)
|
||||
|
||||
handle_found = false;
|
||||
|
||||
for (i = 0; i < ret; i++) {
|
||||
for (i = 0; i < count; i++) {
|
||||
if (connlist[i].handle == conn.handle) {
|
||||
handle_found = true;
|
||||
break;
|
||||
@@ -502,6 +502,36 @@ static bool adjust_swd_buffer_size(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int jaylink_log_handler(const struct jaylink_context *ctx,
|
||||
enum jaylink_log_level level, const char *format, va_list args,
|
||||
void *user_data)
|
||||
{
|
||||
enum log_levels tmp;
|
||||
|
||||
switch (level) {
|
||||
case JAYLINK_LOG_LEVEL_ERROR:
|
||||
tmp = LOG_LVL_ERROR;
|
||||
break;
|
||||
case JAYLINK_LOG_LEVEL_WARNING:
|
||||
tmp = LOG_LVL_WARNING;
|
||||
break;
|
||||
/*
|
||||
* Forward info messages to the debug output because they are more verbose
|
||||
* than info messages of OpenOCD.
|
||||
*/
|
||||
case JAYLINK_LOG_LEVEL_INFO:
|
||||
case JAYLINK_LOG_LEVEL_DEBUG:
|
||||
tmp = LOG_LVL_DEBUG;
|
||||
break;
|
||||
default:
|
||||
tmp = LOG_LVL_WARNING;
|
||||
}
|
||||
|
||||
log_vprintf_lf(tmp, __FILE__, __LINE__, __func__, format, args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jlink_init(void)
|
||||
{
|
||||
int ret;
|
||||
@@ -515,6 +545,9 @@ static int jlink_init(void)
|
||||
enum jaylink_usb_address address;
|
||||
size_t length;
|
||||
|
||||
LOG_DEBUG("Using libjaylink %s (compiled with %s).",
|
||||
jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING);
|
||||
|
||||
ret = jaylink_init(&jayctx);
|
||||
|
||||
if (ret != JAYLINK_OK) {
|
||||
@@ -523,10 +556,28 @@ static int jlink_init(void)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = jaylink_get_device_list(jayctx, &devs);
|
||||
ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("jaylink_get_device_list() failed: %s.",
|
||||
if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("jaylink_log_set_callback() failed: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
jaylink_exit(jayctx);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = jaylink_discovery_scan(jayctx, 0);
|
||||
|
||||
if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("jaylink_discovery_scan() failed: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
jaylink_exit(jayctx);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = jaylink_get_devices(jayctx, &devs, NULL);
|
||||
|
||||
if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("jaylink_get_devices() failed: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
jaylink_exit(jayctx);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
@@ -576,7 +627,7 @@ static int jlink_init(void)
|
||||
LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret));
|
||||
}
|
||||
|
||||
jaylink_free_device_list(devs, 1);
|
||||
jaylink_free_devices(devs, true);
|
||||
|
||||
if (!found_device) {
|
||||
LOG_ERROR("No J-Link device found.");
|
||||
@@ -626,7 +677,7 @@ static int jlink_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
jtag_command_version = JAYLINK_JTAG_V2;
|
||||
jtag_command_version = JAYLINK_JTAG_VERSION_2;
|
||||
|
||||
if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_HW_VERSION)) {
|
||||
ret = jaylink_get_hardware_version(devh, &hwver);
|
||||
@@ -642,7 +693,7 @@ static int jlink_init(void)
|
||||
LOG_INFO("Hardware version: %u.%02u", hwver.major, hwver.minor);
|
||||
|
||||
if (hwver.major >= 5)
|
||||
jtag_command_version = JAYLINK_JTAG_V3;
|
||||
jtag_command_version = JAYLINK_JTAG_VERSION_3;
|
||||
}
|
||||
|
||||
if (iface == JAYLINK_TIF_SWD) {
|
||||
@@ -685,7 +736,7 @@ static int jlink_init(void)
|
||||
|
||||
conn.handle = 0;
|
||||
conn.pid = 0;
|
||||
conn.hid = 0;
|
||||
strcpy(conn.hid, "0.0.0.0");
|
||||
conn.iid = 0;
|
||||
conn.cid = 0;
|
||||
|
||||
@@ -729,6 +780,7 @@ static int jlink_init(void)
|
||||
static int jlink_quit(void)
|
||||
{
|
||||
int ret;
|
||||
size_t count;
|
||||
|
||||
if (trace_enabled) {
|
||||
ret = jaylink_swo_stop(devh);
|
||||
@@ -739,9 +791,9 @@ static int jlink_quit(void)
|
||||
}
|
||||
|
||||
if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) {
|
||||
ret = jaylink_unregister(devh, &conn, connlist, NULL, NULL);
|
||||
ret = jaylink_unregister(devh, &conn, connlist, &count);
|
||||
|
||||
if (ret < 0)
|
||||
if (ret != JAYLINK_OK)
|
||||
LOG_ERROR("jaylink_unregister() failed: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
}
|
||||
@@ -878,14 +930,22 @@ COMMAND_HANDLER(jlink_usb_command)
|
||||
|
||||
COMMAND_HANDLER(jlink_serial_command)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (CMD_ARGC != 1) {
|
||||
command_print(CMD_CTX, "Need exactly one argument for jlink serial.");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (sscanf(CMD_ARGV[0], "%" SCNd32, &serial_number) != 1) {
|
||||
ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number);
|
||||
|
||||
if (ret == JAYLINK_ERR) {
|
||||
command_print(CMD_CTX, "Invalid serial number: %s.", CMD_ARGV[0]);
|
||||
return ERROR_FAIL;
|
||||
} else if (ret != JAYLINK_OK) {
|
||||
command_print(CMD_CTX, "jaylink_parse_serial_number() failed: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
use_serial_number = true;
|
||||
@@ -951,10 +1011,10 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command)
|
||||
|
||||
if (!CMD_ARGC) {
|
||||
switch (jtag_command_version) {
|
||||
case JAYLINK_JTAG_V2:
|
||||
case JAYLINK_JTAG_VERSION_2:
|
||||
version = 2;
|
||||
break;
|
||||
case JAYLINK_JTAG_V3:
|
||||
case JAYLINK_JTAG_VERSION_3:
|
||||
version = 3;
|
||||
break;
|
||||
default:
|
||||
@@ -970,10 +1030,10 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command)
|
||||
|
||||
switch (tmp) {
|
||||
case 2:
|
||||
jtag_command_version = JAYLINK_JTAG_V2;
|
||||
jtag_command_version = JAYLINK_JTAG_VERSION_2;
|
||||
break;
|
||||
case 3:
|
||||
jtag_command_version = JAYLINK_JTAG_V3;
|
||||
jtag_command_version = JAYLINK_JTAG_VERSION_3;
|
||||
break;
|
||||
default:
|
||||
command_print(CMD_CTX, "Invalid argument: %s.", CMD_ARGV[0]);
|
||||
@@ -1545,6 +1605,125 @@ COMMAND_HANDLER(jlink_handle_config_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jlink_handle_emucom_write_command)
|
||||
{
|
||||
int ret;
|
||||
size_t tmp;
|
||||
uint32_t channel;
|
||||
uint32_t length;
|
||||
uint8_t *buf;
|
||||
size_t dummy;
|
||||
|
||||
if (CMD_ARGC != 2)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
|
||||
LOG_ERROR("Device does not support EMUCOM.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel);
|
||||
|
||||
tmp = strlen(CMD_ARGV[1]);
|
||||
|
||||
if (tmp % 2 != 0) {
|
||||
LOG_ERROR("Data must be encoded as hexadecimal pairs.");
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
buf = malloc(tmp / 2);
|
||||
|
||||
if (!buf) {
|
||||
LOG_ERROR("Failed to allocate buffer.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
dummy = unhexify(buf, CMD_ARGV[1], tmp / 2);
|
||||
|
||||
if (dummy != (tmp / 2)) {
|
||||
LOG_ERROR("Data must be encoded as hexadecimal pairs.");
|
||||
free(buf);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
length = tmp / 2;
|
||||
ret = jaylink_emucom_write(devh, channel, buf, &length);
|
||||
|
||||
free(buf);
|
||||
|
||||
if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
|
||||
LOG_ERROR("Channel not supported by the device.");
|
||||
return ERROR_FAIL;
|
||||
} else if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("Failed to write to channel: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (length != (tmp / 2))
|
||||
LOG_WARNING("Only %" PRIu32 " bytes written to the channel.", length);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jlink_handle_emucom_read_command)
|
||||
{
|
||||
int ret;
|
||||
uint32_t channel;
|
||||
uint32_t length;
|
||||
uint8_t *buf;
|
||||
size_t tmp;
|
||||
|
||||
if (CMD_ARGC != 2)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
|
||||
LOG_ERROR("Device does not support EMUCOM.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
|
||||
|
||||
buf = malloc(length * 3 + 1);
|
||||
|
||||
if (!buf) {
|
||||
LOG_ERROR("Failed to allocate buffer.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
ret = jaylink_emucom_read(devh, channel, buf, &length);
|
||||
|
||||
if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
|
||||
LOG_ERROR("Channel is not supported by the device.");
|
||||
free(buf);
|
||||
return ERROR_FAIL;
|
||||
} else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) {
|
||||
LOG_ERROR("Channel is not available for the requested amount of data. "
|
||||
"%" PRIu32 " bytes are avilable.", length);
|
||||
free(buf);
|
||||
return ERROR_FAIL;
|
||||
} else if (ret != JAYLINK_OK) {
|
||||
LOG_ERROR("Failed to read from channel: %s.",
|
||||
jaylink_strerror_name(ret));
|
||||
free(buf);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
tmp = hexify((char *)buf + length, buf, length, 2 * length + 1);
|
||||
|
||||
if (tmp != 2 * length) {
|
||||
LOG_ERROR("Failed to convert data into hexadecimal string.");
|
||||
free(buf);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "%s", buf + length);
|
||||
free(buf);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration jlink_config_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "usb",
|
||||
@@ -1590,6 +1769,24 @@ static const struct command_registration jlink_config_subcommand_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration jlink_emucom_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "write",
|
||||
.handler = &jlink_handle_emucom_write_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "write to a channel",
|
||||
.usage = "<channel> <data>",
|
||||
},
|
||||
{
|
||||
.name = "read",
|
||||
.handler = &jlink_handle_emucom_read_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "read from a channel",
|
||||
.usage = "<channel> <length>"
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration jlink_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "jtag",
|
||||
@@ -1639,6 +1836,12 @@ static const struct command_registration jlink_subcommand_handlers[] = {
|
||||
"this will show the device configuration",
|
||||
.chain = jlink_config_subcommand_handlers,
|
||||
},
|
||||
{
|
||||
.name = "emucom",
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "access EMUCOM channel",
|
||||
.chain = jlink_emucom_subcommand_handlers
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,967 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> *
|
||||
* based on Dominic Rath's and Benedikt Sauter's usbprog.c *
|
||||
* *
|
||||
* Copyright (C) 2008 by Spencer Oliver *
|
||||
* spen@spen-soft.co.uk *
|
||||
* *
|
||||
* Copyright (C) 2011 by Jean-Christophe PLAGNIOL-VIILARD *
|
||||
* plagnioj@jcrosoft.com *
|
||||
* *
|
||||
* Copyright (C) 2015 by Marc Schink *
|
||||
* openocd-dev@marcschink.de *
|
||||
* *
|
||||
* Copyright (C) 2015 by Paul Fertser *
|
||||
* fercerpav@gmail.com *
|
||||
* *
|
||||
* Copyright (C) 2015-2017 by Forest Crossman *
|
||||
* cyrozap@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, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <hidapi.h>
|
||||
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/commands.h>
|
||||
|
||||
#include "libusb_common.h"
|
||||
|
||||
#define VID 0x04b4
|
||||
#define PID 0xf139
|
||||
|
||||
#define BULK_EP_IN 1
|
||||
#define BULK_EP_OUT 2
|
||||
|
||||
#define CONTROL_TYPE_READ 0x01
|
||||
#define CONTROL_TYPE_WRITE 0x02
|
||||
|
||||
#define CONTROL_COMMAND_PROGRAM 0x07
|
||||
|
||||
#define CONTROL_MODE_POLL_PROGRAMMER_STATUS 0x01
|
||||
#define CONTROL_MODE_RESET_TARGET 0x04
|
||||
#define CONTROL_MODE_SET_PROGRAMMER_PROTOCOL 0x40
|
||||
#define CONTROL_MODE_SYNCHRONIZE_TRANSFER 0x41
|
||||
#define CONTROL_MODE_ACQUIRE_SWD_TARGET 0x42
|
||||
#define CONTROL_MODE_SEND_SWD_SEQUENCE 0x43
|
||||
|
||||
#define PROTOCOL_JTAG 0x00
|
||||
#define PROTOCOL_SWD 0x01
|
||||
|
||||
#define DEVICE_PSOC4 0x00
|
||||
#define DEVICE_PSOC3 0x01
|
||||
#define DEVICE_UNKNOWN 0x02
|
||||
#define DEVICE_PSOC5 0x03
|
||||
|
||||
#define ACQUIRE_MODE_RESET 0x00
|
||||
#define ACQUIRE_MODE_POWER_CYCLE 0x01
|
||||
|
||||
#define SEQUENCE_LINE_RESET 0x00
|
||||
#define SEQUENCE_JTAG_TO_SWD 0x01
|
||||
|
||||
#define PROGRAMMER_NOK_NACK 0x00
|
||||
#define PROGRAMMER_OK_ACK 0x01
|
||||
|
||||
#define HID_TYPE_WRITE 0x00
|
||||
#define HID_TYPE_READ 0x01
|
||||
#define HID_TYPE_START 0x02
|
||||
|
||||
#define HID_COMMAND_POWER 0x80
|
||||
#define HID_COMMAND_VERSION 0x81
|
||||
#define HID_COMMAND_RESET 0x82
|
||||
#define HID_COMMAND_CONFIGURE 0x8f
|
||||
#define HID_COMMAND_BOOTLOADER 0xa0
|
||||
|
||||
/* 512 bytes seems to work reliably */
|
||||
#define SWD_MAX_BUFFER_LENGTH 512
|
||||
|
||||
struct kitprog {
|
||||
hid_device *hid_handle;
|
||||
struct jtag_libusb_device_handle *usb_handle;
|
||||
uint16_t packet_size;
|
||||
uint16_t packet_index;
|
||||
uint8_t *packet_buffer;
|
||||
char *serial;
|
||||
uint8_t hardware_version;
|
||||
uint8_t minor_version;
|
||||
uint8_t major_version;
|
||||
uint16_t millivolts;
|
||||
|
||||
bool supports_jtag_to_swd;
|
||||
};
|
||||
|
||||
struct pending_transfer_result {
|
||||
uint8_t cmd;
|
||||
uint32_t data;
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
static char *kitprog_serial;
|
||||
static bool kitprog_init_acquire_psoc;
|
||||
|
||||
static int pending_transfer_count, pending_queue_len;
|
||||
static struct pending_transfer_result *pending_transfers;
|
||||
|
||||
static int queued_retval;
|
||||
|
||||
static struct kitprog *kitprog_handle;
|
||||
|
||||
static int kitprog_usb_open(void);
|
||||
static void kitprog_usb_close(void);
|
||||
|
||||
static int kitprog_hid_command(uint8_t *command, size_t command_length,
|
||||
uint8_t *data, size_t data_length);
|
||||
static int kitprog_get_version(void);
|
||||
static int kitprog_get_millivolts(void);
|
||||
static int kitprog_get_info(void);
|
||||
static int kitprog_set_protocol(uint8_t protocol);
|
||||
static int kitprog_get_status(void);
|
||||
static int kitprog_set_unknown(void);
|
||||
static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode,
|
||||
uint8_t max_attempts);
|
||||
static int kitprog_reset_target(void);
|
||||
static int kitprog_swd_sync(void);
|
||||
static int kitprog_swd_seq(uint8_t seq_type);
|
||||
|
||||
static int kitprog_generic_acquire(void);
|
||||
|
||||
static int kitprog_swd_run_queue(void);
|
||||
static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data);
|
||||
static int kitprog_swd_switch_seq(enum swd_special_seq seq);
|
||||
|
||||
|
||||
static inline int mm_to_version(uint8_t major, uint8_t minor)
|
||||
{
|
||||
return (major << 8) | minor;
|
||||
}
|
||||
|
||||
static int kitprog_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
kitprog_handle = malloc(sizeof(struct kitprog));
|
||||
if (kitprog_handle == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (kitprog_usb_open() != ERROR_OK) {
|
||||
LOG_ERROR("Can't find a KitProg device! Please check device connections and permissions.");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* Get the current KitProg version and target voltage */
|
||||
if (kitprog_get_info() != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* Compatibility check */
|
||||
kitprog_handle->supports_jtag_to_swd = true;
|
||||
int kitprog_version = mm_to_version(kitprog_handle->major_version, kitprog_handle->minor_version);
|
||||
if (kitprog_version < mm_to_version(2, 14)) {
|
||||
LOG_WARNING("KitProg firmware versions below v2.14 do not support sending JTAG to SWD sequences. These sequences will be substituted with SWD line resets.");
|
||||
kitprog_handle->supports_jtag_to_swd = false;
|
||||
}
|
||||
|
||||
/* I have no idea what this does */
|
||||
if (kitprog_set_unknown() != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* SWD won't work unless we do this */
|
||||
if (kitprog_swd_sync() != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* Set the protocol to SWD */
|
||||
if (kitprog_set_protocol(PROTOCOL_SWD) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* Reset the SWD bus */
|
||||
if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (kitprog_init_acquire_psoc) {
|
||||
/* Try to acquire any device that will respond */
|
||||
retval = kitprog_generic_acquire();
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("No PSoC devices found");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate packet buffers and queues */
|
||||
kitprog_handle->packet_size = SWD_MAX_BUFFER_LENGTH;
|
||||
kitprog_handle->packet_buffer = malloc(SWD_MAX_BUFFER_LENGTH);
|
||||
if (kitprog_handle->packet_buffer == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory for the packet buffer");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
pending_queue_len = SWD_MAX_BUFFER_LENGTH / 5;
|
||||
pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers));
|
||||
if (pending_transfers == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory for the SWD transfer queue");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_quit(void)
|
||||
{
|
||||
kitprog_usb_close();
|
||||
|
||||
if (kitprog_handle->packet_buffer != NULL)
|
||||
free(kitprog_handle->packet_buffer);
|
||||
if (kitprog_handle->serial != NULL)
|
||||
free(kitprog_handle->serial);
|
||||
if (kitprog_handle != NULL)
|
||||
free(kitprog_handle);
|
||||
|
||||
if (kitprog_serial != NULL)
|
||||
free(kitprog_serial);
|
||||
|
||||
if (pending_transfers != NULL)
|
||||
free(pending_transfers);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*************** kitprog usb functions *********************/
|
||||
|
||||
static int kitprog_get_usb_serial(void)
|
||||
{
|
||||
int retval;
|
||||
const uint8_t str_index = 128; /* This seems to be a constant */
|
||||
char desc_string[256+1]; /* Max size of string descriptor */
|
||||
|
||||
retval = libusb_get_string_descriptor_ascii(kitprog_handle->usb_handle,
|
||||
str_index, (unsigned char *)desc_string, sizeof(desc_string)-1);
|
||||
if (retval < 0) {
|
||||
LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Null terminate descriptor string */
|
||||
desc_string[retval] = '\0';
|
||||
|
||||
/* Allocate memory for the serial number */
|
||||
kitprog_handle->serial = calloc(retval + 1, sizeof(char));
|
||||
if (kitprog_handle->serial == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory for the serial number");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Store the serial number */
|
||||
strncpy(kitprog_handle->serial, desc_string, retval + 1);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_usb_open(void)
|
||||
{
|
||||
const uint16_t vids[] = { VID, 0 };
|
||||
const uint16_t pids[] = { PID, 0 };
|
||||
|
||||
if (jtag_libusb_open(vids, pids, kitprog_serial,
|
||||
&kitprog_handle->usb_handle) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to open or find the device");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Get the serial number for the device */
|
||||
if (kitprog_get_usb_serial() != ERROR_OK)
|
||||
LOG_WARNING("Failed to get KitProg serial number");
|
||||
|
||||
/* Convert the ASCII serial number into a (wchar_t *) */
|
||||
size_t len = strlen(kitprog_handle->serial);
|
||||
wchar_t *hid_serial = calloc(len + 1, sizeof(wchar_t));
|
||||
if (hid_serial == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory for the serial number");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (mbstowcs(hid_serial, kitprog_handle->serial, len + 1) == (size_t)-1) {
|
||||
free(hid_serial);
|
||||
LOG_ERROR("Failed to convert serial number");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Use HID for the KitBridge interface */
|
||||
kitprog_handle->hid_handle = hid_open(VID, PID, hid_serial);
|
||||
free(hid_serial);
|
||||
if (kitprog_handle->hid_handle == NULL) {
|
||||
LOG_ERROR("Failed to open KitBridge (HID) interface");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Claim the KitProg Programmer (bulk transfer) interface */
|
||||
if (jtag_libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to claim KitProg Programmer (bulk transfer) interface");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void kitprog_usb_close(void)
|
||||
{
|
||||
if (kitprog_handle->hid_handle != NULL) {
|
||||
hid_close(kitprog_handle->hid_handle);
|
||||
hid_exit();
|
||||
}
|
||||
|
||||
jtag_libusb_close(kitprog_handle->usb_handle);
|
||||
}
|
||||
|
||||
/*************** kitprog lowlevel functions *********************/
|
||||
|
||||
static int kitprog_hid_command(uint8_t *command, size_t command_length,
|
||||
uint8_t *data, size_t data_length)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hid_write(kitprog_handle->hid_handle, command, command_length);
|
||||
if (ret < 0) {
|
||||
LOG_DEBUG("HID write returned %i", ret);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
ret = hid_read(kitprog_handle->hid_handle, data, data_length);
|
||||
if (ret < 0) {
|
||||
LOG_DEBUG("HID read returned %i", ret);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_get_version(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
unsigned char command[3] = {HID_TYPE_START | HID_TYPE_WRITE, 0x00, HID_COMMAND_VERSION};
|
||||
unsigned char data[64];
|
||||
|
||||
ret = kitprog_hid_command(command, sizeof command, data, sizeof data);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
kitprog_handle->hardware_version = data[1];
|
||||
kitprog_handle->minor_version = data[2];
|
||||
kitprog_handle->major_version = data[3];
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_get_millivolts(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
unsigned char command[3] = {HID_TYPE_START | HID_TYPE_READ, 0x00, HID_COMMAND_POWER};
|
||||
unsigned char data[64];
|
||||
|
||||
ret = kitprog_hid_command(command, sizeof command, data, sizeof data);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
kitprog_handle->millivolts = (data[4] << 8) | data[3];
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_get_info(void)
|
||||
{
|
||||
/* Get the device version information */
|
||||
if (kitprog_get_version() == ERROR_OK) {
|
||||
LOG_INFO("KitProg v%u.%02u",
|
||||
kitprog_handle->major_version, kitprog_handle->minor_version);
|
||||
LOG_INFO("Hardware version: %u",
|
||||
kitprog_handle->hardware_version);
|
||||
} else {
|
||||
LOG_ERROR("Failed to get KitProg version");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Get the current reported target voltage */
|
||||
if (kitprog_get_millivolts() == ERROR_OK) {
|
||||
LOG_INFO("VTARG = %u.%03u V",
|
||||
kitprog_handle->millivolts / 1000, kitprog_handle->millivolts % 1000);
|
||||
} else {
|
||||
LOG_ERROR("Failed to get target voltage");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_set_protocol(uint8_t protocol)
|
||||
{
|
||||
int transferred;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_WRITE,
|
||||
(CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | CONTROL_COMMAND_PROGRAM,
|
||||
protocol, &status, 1, 0);
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_get_status(void)
|
||||
{
|
||||
int transferred = 0;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
/* Try a maximum of three times */
|
||||
for (int i = 0; (i < 3) && (transferred == 0); i++) {
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_READ,
|
||||
(CONTROL_MODE_POLL_PROGRAMMER_STATUS << 8) | CONTROL_COMMAND_PROGRAM,
|
||||
0, &status, 1, 0);
|
||||
jtag_sleep(1000);
|
||||
}
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_set_unknown(void)
|
||||
{
|
||||
int transferred;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_WRITE,
|
||||
(0x03 << 8) | 0x04,
|
||||
0, &status, 1, 0);
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode,
|
||||
uint8_t max_attempts)
|
||||
{
|
||||
int transferred;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_WRITE,
|
||||
(CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | CONTROL_COMMAND_PROGRAM,
|
||||
(max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0);
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_reset_target(void)
|
||||
{
|
||||
int transferred;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_WRITE,
|
||||
(CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM,
|
||||
0, &status, 1, 0);
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_swd_sync(void)
|
||||
{
|
||||
int transferred;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_WRITE,
|
||||
(CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | CONTROL_COMMAND_PROGRAM,
|
||||
0, &status, 1, 0);
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_swd_seq(uint8_t seq_type)
|
||||
{
|
||||
int transferred;
|
||||
char status = PROGRAMMER_NOK_NACK;
|
||||
|
||||
transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
CONTROL_TYPE_WRITE,
|
||||
(CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM,
|
||||
seq_type, &status, 1, 0);
|
||||
|
||||
if (transferred == 0) {
|
||||
LOG_DEBUG("Zero bytes transferred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status != PROGRAMMER_OK_ACK) {
|
||||
LOG_DEBUG("Programmer did not respond OK");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_generic_acquire(void)
|
||||
{
|
||||
const uint8_t devices[] = {DEVICE_PSOC4, DEVICE_PSOC3, DEVICE_PSOC5};
|
||||
|
||||
int retval;
|
||||
int acquire_count = 0;
|
||||
|
||||
/* Due to the way the SWD port is shared between the Test Controller (TC)
|
||||
* and the Cortex-M3 DAP on the PSoC 5LP, the TC is the default SWD target
|
||||
* after power is applied. To access the DAP, the PSoC 5LP requires at least
|
||||
* one acquisition sequence to be run (which switches the SWD mux from the
|
||||
* TC to the DAP). However, after the mux is switched, the Cortex-M3 will be
|
||||
* held in reset until a series of registers are written to (see section 5.2
|
||||
* of the PSoC 5LP Device Programming Specifications for details).
|
||||
*
|
||||
* Instead of writing the registers in this function, we just do what the
|
||||
* Cypress tools do and run the acquisition sequence a second time. This
|
||||
* will take the Cortex-M3 out of reset and enable debugging.
|
||||
*/
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (uint8_t j = 0; j < sizeof devices && acquire_count == i; j++) {
|
||||
retval = kitprog_acquire_psoc(devices[j], ACQUIRE_MODE_RESET, 3);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("Aquisition function failed for device 0x%02x.", devices[j]);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (kitprog_get_status() == ERROR_OK)
|
||||
acquire_count++;
|
||||
}
|
||||
|
||||
jtag_sleep(10);
|
||||
}
|
||||
|
||||
if (acquire_count < 2)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*************** swd wrapper functions *********************/
|
||||
|
||||
static int kitprog_swd_init(void)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void kitprog_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
|
||||
{
|
||||
assert(!(cmd & SWD_CMD_RnW));
|
||||
kitprog_swd_queue_cmd(cmd, NULL, value);
|
||||
}
|
||||
|
||||
static void kitprog_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
|
||||
{
|
||||
assert(cmd & SWD_CMD_RnW);
|
||||
kitprog_swd_queue_cmd(cmd, value, 0);
|
||||
}
|
||||
|
||||
/*************** swd lowlevel functions ********************/
|
||||
|
||||
static int kitprog_swd_switch_seq(enum swd_special_seq seq)
|
||||
{
|
||||
switch (seq) {
|
||||
case JTAG_TO_SWD:
|
||||
if (kitprog_handle->supports_jtag_to_swd) {
|
||||
LOG_DEBUG("JTAG to SWD");
|
||||
if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
} else {
|
||||
LOG_DEBUG("JTAG to SWD not supported");
|
||||
/* Fall through to fix target reset issue */
|
||||
}
|
||||
case LINE_RESET:
|
||||
LOG_DEBUG("SWD line reset");
|
||||
if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Sequence %d not supported.", seq);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int kitprog_swd_run_queue(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
size_t read_count = 0;
|
||||
size_t read_index = 0;
|
||||
size_t write_count = 0;
|
||||
uint8_t *buffer = kitprog_handle->packet_buffer;
|
||||
|
||||
do {
|
||||
LOG_DEBUG("Executing %d queued transactions", pending_transfer_count);
|
||||
|
||||
if (queued_retval != ERROR_OK) {
|
||||
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pending_transfer_count)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < pending_transfer_count; i++) {
|
||||
uint8_t cmd = pending_transfers[i].cmd;
|
||||
uint32_t data = pending_transfers[i].data;
|
||||
|
||||
/* When proper WAIT handling is implemented in the
|
||||
* common SWD framework, this kludge can be
|
||||
* removed. However, this might lead to minor
|
||||
* performance degradation as the adapter wouldn't be
|
||||
* able to automatically retry anything (because ARM
|
||||
* has forgotten to implement sticky error flags
|
||||
* clearing). See also comments regarding
|
||||
* cmsis_dap_cmd_DAP_TFER_Configure() and
|
||||
* cmsis_dap_cmd_DAP_SWD_Configure() in
|
||||
* cmsis_dap_init().
|
||||
*/
|
||||
if (!(cmd & SWD_CMD_RnW) &&
|
||||
!(cmd & SWD_CMD_APnDP) &&
|
||||
(cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT &&
|
||||
(data & CORUNDETECT)) {
|
||||
LOG_DEBUG("refusing to enable sticky overrun detection");
|
||||
data &= ~CORUNDETECT;
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG_DEBUG("%s %s reg %x %"PRIx32,
|
||||
cmd & SWD_CMD_APnDP ? "AP" : "DP",
|
||||
cmd & SWD_CMD_RnW ? "read" : "write",
|
||||
(cmd & SWD_CMD_A32) >> 1, data);
|
||||
#endif
|
||||
|
||||
buffer[write_count++] = (cmd | SWD_CMD_START | SWD_CMD_PARK) & ~SWD_CMD_STOP;
|
||||
read_count++;
|
||||
if (!(cmd & SWD_CMD_RnW)) {
|
||||
buffer[write_count++] = (data) & 0xff;
|
||||
buffer[write_count++] = (data >> 8) & 0xff;
|
||||
buffer[write_count++] = (data >> 16) & 0xff;
|
||||
buffer[write_count++] = (data >> 24) & 0xff;
|
||||
} else {
|
||||
read_count += 4;
|
||||
}
|
||||
}
|
||||
|
||||
ret = jtag_libusb_bulk_write(kitprog_handle->usb_handle,
|
||||
BULK_EP_OUT, (char *)buffer, write_count, 0);
|
||||
if (ret > 0) {
|
||||
queued_retval = ERROR_OK;
|
||||
} else {
|
||||
LOG_ERROR("Bulk write failed");
|
||||
queued_retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We use the maximum buffer size here because the KitProg sometimes
|
||||
* doesn't like bulk reads of fewer than 62 bytes. (?!?!)
|
||||
*/
|
||||
ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle,
|
||||
BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer,
|
||||
SWD_MAX_BUFFER_LENGTH, 0);
|
||||
if (ret > 0) {
|
||||
/* Handle garbage data by offsetting the initial read index */
|
||||
if ((unsigned int)ret > read_count)
|
||||
read_index = ret - read_count;
|
||||
queued_retval = ERROR_OK;
|
||||
} else {
|
||||
LOG_ERROR("Bulk read failed");
|
||||
queued_retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pending_transfer_count; i++) {
|
||||
if (pending_transfers[i].cmd & SWD_CMD_RnW) {
|
||||
uint32_t data = le_to_h_u32(&buffer[read_index]);
|
||||
|
||||
#if 0
|
||||
LOG_DEBUG("Read result: %"PRIx32, data);
|
||||
#endif
|
||||
|
||||
if (pending_transfers[i].buffer)
|
||||
*(uint32_t *)pending_transfers[i].buffer = data;
|
||||
|
||||
read_index += 4;
|
||||
}
|
||||
|
||||
uint8_t ack = buffer[read_index] & 0x07;
|
||||
if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) {
|
||||
LOG_DEBUG("SWD ack not OK: %d %s", i,
|
||||
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
|
||||
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
read_index++;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
pending_transfer_count = 0;
|
||||
int retval = queued_retval;
|
||||
queued_retval = ERROR_OK;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
|
||||
{
|
||||
if (pending_transfer_count == pending_queue_len) {
|
||||
/* Not enough room in the queue. Run the queue. */
|
||||
queued_retval = kitprog_swd_run_queue();
|
||||
}
|
||||
|
||||
if (queued_retval != ERROR_OK)
|
||||
return;
|
||||
|
||||
pending_transfers[pending_transfer_count].data = data;
|
||||
pending_transfers[pending_transfer_count].cmd = cmd;
|
||||
if (cmd & SWD_CMD_RnW) {
|
||||
/* Queue a read transaction */
|
||||
pending_transfers[pending_transfer_count].buffer = dst;
|
||||
}
|
||||
pending_transfer_count++;
|
||||
}
|
||||
|
||||
/*************** jtag lowlevel functions ********************/
|
||||
|
||||
static void kitprog_execute_reset(struct jtag_command *cmd)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (cmd->cmd.reset->srst == 1) {
|
||||
retval = kitprog_reset_target();
|
||||
/* Since the previous command also disables SWCLK output, we need to send an
|
||||
* SWD bus reset command to re-enable it. For some reason, running
|
||||
* kitprog_swd_seq() immediately after kitprog_reset_target() won't
|
||||
* actually fix this. Instead, kitprog_swd_seq() will be run once OpenOCD
|
||||
* tries to send a JTAG-to-SWD sequence, which should happen during
|
||||
* swd_check_reconnect (see the JTAG_TO_SWD case in kitprog_swd_switch_seq).
|
||||
*/
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("KitProg: Interface reset failed");
|
||||
}
|
||||
|
||||
static void kitprog_execute_sleep(struct jtag_command *cmd)
|
||||
{
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
}
|
||||
|
||||
static void kitprog_execute_command(struct jtag_command *cmd)
|
||||
{
|
||||
switch (cmd->type) {
|
||||
case JTAG_RESET:
|
||||
kitprog_execute_reset(cmd);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
kitprog_execute_sleep(cmd);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static int kitprog_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue;
|
||||
|
||||
while (cmd != NULL) {
|
||||
kitprog_execute_command(cmd);
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_info_command)
|
||||
{
|
||||
int retval = kitprog_get_info();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_acquire_psoc_command)
|
||||
{
|
||||
int retval = kitprog_generic_acquire();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_serial_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
size_t len = strlen(CMD_ARGV[0]);
|
||||
kitprog_serial = calloc(len + 1, sizeof(char));
|
||||
if (kitprog_serial == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory for the serial number");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
strncpy(kitprog_serial, CMD_ARGV[0], len + 1);
|
||||
} else {
|
||||
LOG_ERROR("expected exactly one argument to kitprog_serial <serial-number>");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_init_acquire_psoc_command)
|
||||
{
|
||||
kitprog_init_acquire_psoc = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration kitprog_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "info",
|
||||
.handler = &kitprog_handle_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "",
|
||||
.help = "show KitProg info",
|
||||
},
|
||||
{
|
||||
.name = "acquire_psoc",
|
||||
.handler = &kitprog_handle_acquire_psoc_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "",
|
||||
.help = "try to acquire a PSoC",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration kitprog_command_handlers[] = {
|
||||
{
|
||||
.name = "kitprog",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "perform KitProg management",
|
||||
.usage = "<cmd>",
|
||||
.chain = kitprog_subcommand_handlers,
|
||||
},
|
||||
{
|
||||
.name = "kitprog_serial",
|
||||
.handler = &kitprog_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the adapter",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "kitprog_init_acquire_psoc",
|
||||
.handler = &kitprog_handle_init_acquire_psoc_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "try to acquire a PSoC during init",
|
||||
.usage = "",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct swd_driver kitprog_swd = {
|
||||
.init = kitprog_swd_init,
|
||||
.switch_seq = kitprog_swd_switch_seq,
|
||||
.read_reg = kitprog_swd_read_reg,
|
||||
.write_reg = kitprog_swd_write_reg,
|
||||
.run = kitprog_swd_run_queue,
|
||||
};
|
||||
|
||||
static const char * const kitprog_transports[] = { "swd", NULL };
|
||||
|
||||
struct jtag_interface kitprog_interface = {
|
||||
.name = "kitprog",
|
||||
.commands = kitprog_command_handlers,
|
||||
.transports = kitprog_transports,
|
||||
.swd = &kitprog_swd,
|
||||
.execute_queue = kitprog_execute_queue,
|
||||
.init = kitprog_init,
|
||||
.quit = kitprog_quit
|
||||
};
|
||||
Submodule src/jtag/drivers/libjaylink updated: d57dee67bc...699b7001d3
@@ -146,7 +146,7 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol)
|
||||
int bclass, int subclass, int protocol, int trans_type)
|
||||
{
|
||||
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
|
||||
struct usb_interface *iface = udev->config->interface;
|
||||
@@ -157,7 +157,8 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
for (int i = 0; i < desc->bNumEndpoints; i++) {
|
||||
if ((bclass > 0 && desc->bInterfaceClass != bclass) ||
|
||||
(subclass > 0 && desc->bInterfaceSubClass != subclass) ||
|
||||
(protocol > 0 && desc->bInterfaceProtocol != protocol))
|
||||
(protocol > 0 && desc->bInterfaceProtocol != protocol) ||
|
||||
(trans_type > 0 && (desc->endpoint[i].bmAttributes & 0x3) != trans_type))
|
||||
continue;
|
||||
|
||||
uint8_t epnum = desc->endpoint[i].bEndpointAddress;
|
||||
|
||||
@@ -67,7 +67,7 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol);
|
||||
int bclass, int subclass, int protocol, int trans_type);
|
||||
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H */
|
||||
|
||||
@@ -187,7 +187,7 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol)
|
||||
int bclass, int subclass, int protocol, int trans_type)
|
||||
{
|
||||
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
|
||||
const struct libusb_interface *inter;
|
||||
@@ -210,6 +210,8 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
continue;
|
||||
|
||||
epdesc = &interdesc->endpoint[k];
|
||||
if (trans_type > 0 && (epdesc->bmAttributes & 0x3) != trans_type)
|
||||
continue;
|
||||
|
||||
uint8_t epnum = epdesc->bEndpointAddress;
|
||||
bool is_input = epnum & 0x80;
|
||||
|
||||
@@ -69,12 +69,13 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
* @param bclass `bInterfaceClass` to match, or -1 to ignore this field.
|
||||
* @param subclass `bInterfaceSubClass` to match, or -1 to ignore this field.
|
||||
* @param protocol `bInterfaceProtocol` to match, or -1 to ignore this field.
|
||||
* @param trans_type `bmAttributes Bits 0..1 Transfer type` to match, or -1 to ignore this field.
|
||||
* @returns Returns ERROR_OK on success, ERROR_FAIL otherwise.
|
||||
*/
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol);
|
||||
int bclass, int subclass, int protocol, int trans_type);
|
||||
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H */
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#define OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H
|
||||
|
||||
#ifdef HAVE_LIBUSB1
|
||||
#include <libusb1_common.h>
|
||||
#include "libusb1_common.h"
|
||||
#else
|
||||
#include <libusb0_common.h>
|
||||
#include "libusb0_common.h"
|
||||
#endif
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H */
|
||||
|
||||
@@ -247,8 +247,8 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
|
||||
err = libusb_detach_kernel_driver(ctx->usb_dev, ctx->interface);
|
||||
if (err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_NOT_FOUND
|
||||
&& err != LIBUSB_ERROR_NOT_SUPPORTED) {
|
||||
LOG_ERROR("libusb_detach_kernel_driver() failed with %s", libusb_error_name(err));
|
||||
goto error;
|
||||
LOG_WARNING("libusb_detach_kernel_driver() failed with %s, trying to continue anyway",
|
||||
libusb_error_name(err));
|
||||
}
|
||||
|
||||
err = libusb_claim_interface(ctx->usb_dev, ctx->interface);
|
||||
@@ -872,6 +872,8 @@ int mpsse_flush(struct mpsse_ctx *ctx)
|
||||
libusb_fill_bulk_transfer(write_transfer, ctx->usb_dev, ctx->out_ep, ctx->write_buffer,
|
||||
ctx->write_count, write_cb, &write_result, ctx->usb_write_timeout);
|
||||
retval = libusb_submit_transfer(write_transfer);
|
||||
if (retval != LIBUSB_SUCCESS)
|
||||
goto error_check;
|
||||
|
||||
if (ctx->read_count) {
|
||||
read_transfer = libusb_alloc_transfer(0);
|
||||
@@ -879,22 +881,36 @@ int mpsse_flush(struct mpsse_ctx *ctx)
|
||||
ctx->read_chunk_size, read_cb, &read_result,
|
||||
ctx->usb_read_timeout);
|
||||
retval = libusb_submit_transfer(read_transfer);
|
||||
if (retval != LIBUSB_SUCCESS)
|
||||
goto error_check;
|
||||
}
|
||||
|
||||
/* Polling loop, more or less taken from libftdi */
|
||||
while (!write_result.done || !read_result.done) {
|
||||
retval = libusb_handle_events(ctx->usb_ctx);
|
||||
struct timeval timeout_usb;
|
||||
|
||||
timeout_usb.tv_sec = 1;
|
||||
timeout_usb.tv_usec = 0;
|
||||
|
||||
retval = libusb_handle_events_timeout_completed(ctx->usb_ctx, &timeout_usb, NULL);
|
||||
keep_alive();
|
||||
if (retval != LIBUSB_SUCCESS && retval != LIBUSB_ERROR_INTERRUPTED) {
|
||||
if (retval == LIBUSB_ERROR_NO_DEVICE || retval == LIBUSB_ERROR_INTERRUPTED)
|
||||
break;
|
||||
|
||||
if (retval != LIBUSB_SUCCESS) {
|
||||
libusb_cancel_transfer(write_transfer);
|
||||
if (read_transfer)
|
||||
libusb_cancel_transfer(read_transfer);
|
||||
while (!write_result.done || !read_result.done)
|
||||
if (libusb_handle_events(ctx->usb_ctx) != LIBUSB_SUCCESS)
|
||||
while (!write_result.done || !read_result.done) {
|
||||
retval = libusb_handle_events_timeout_completed(ctx->usb_ctx,
|
||||
&timeout_usb, NULL);
|
||||
if (retval != LIBUSB_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_check:
|
||||
if (retval != LIBUSB_SUCCESS) {
|
||||
LOG_ERROR("libusb_handle_events() failed with %s", libusb_error_name(retval));
|
||||
retval = ERROR_FAIL;
|
||||
|
||||
+248
-184
@@ -2,6 +2,10 @@
|
||||
* Driver for OpenJTAG Project (www.openjtag.org) *
|
||||
* Compatible with libftdi and ftd2xx drivers. *
|
||||
* *
|
||||
* Cypress CY7C65215 support *
|
||||
* Copyright (C) 2015 Vianney le Clément de Saint-Marcq, Essensium NV *
|
||||
* <vianney.leclement@essensium.com> *
|
||||
* *
|
||||
* Copyright (C) 2010 by Ivan Meleca <mileca@gmail.com> *
|
||||
* *
|
||||
* Copyright (C) 2013 by Ryan Corbin, GlueLogix Inc. <corbin.ryan@gmail.com> *
|
||||
@@ -41,7 +45,18 @@
|
||||
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include "usb_common.h"
|
||||
#include "libusb_common.h"
|
||||
|
||||
static enum {
|
||||
OPENJTAG_VARIANT_STANDARD,
|
||||
OPENJTAG_VARIANT_CY7C65215,
|
||||
} openjtag_variant = OPENJTAG_VARIANT_STANDARD;
|
||||
|
||||
static const char * const openjtag_variant_names[] = {
|
||||
"standard",
|
||||
"cy7c65215",
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* OpenJTAG-OpenOCD state conversion
|
||||
@@ -66,19 +81,8 @@ typedef enum openjtag_tap_state {
|
||||
OPENJTAG_TAP_UPDATE_IR = 15,
|
||||
} openjtag_tap_state_t;
|
||||
|
||||
#if (BUILD_OPENJTAG_FTD2XX == 1 && BUILD_OPENJTAG_LIBFTDI == 1)
|
||||
#error "BUILD_OPENJTAG_FTD2XX && BUILD_OPENJTAG_LIBFTDI "
|
||||
"are mutually exclusive"
|
||||
#elif (BUILD_OPENJTAG_FTD2XX != 1 && BUILD_OPENJTAG_LIBFTDI != 1)
|
||||
#error "BUILD_OPENJTAG_FTD2XX || BUILD_OPENJTAG_LIBFTDI must be chosen"
|
||||
#endif
|
||||
|
||||
/* OPENJTAG access library includes */
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
#include <ftd2xx.h>
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
#include <ftdi.h>
|
||||
#endif
|
||||
|
||||
/* OpenJTAG vid/pid */
|
||||
static uint16_t openjtag_vid = 0x0403;
|
||||
@@ -86,12 +90,7 @@ static uint16_t openjtag_pid = 0x6001;
|
||||
|
||||
static char *openjtag_device_desc;
|
||||
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
static FT_HANDLE ftdih;
|
||||
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
static struct ftdi_context ftdic;
|
||||
#endif
|
||||
|
||||
#define OPENJTAG_BUFFER_SIZE 504
|
||||
#define OPENJTAG_MAX_PENDING_RESULTS 256
|
||||
@@ -112,10 +111,24 @@ static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE];
|
||||
static struct openjtag_scan_result openjtag_scan_result_buffer[OPENJTAG_MAX_PENDING_RESULTS];
|
||||
static int openjtag_scan_result_count;
|
||||
|
||||
/* Openocd usb handler */
|
||||
struct openocd {
|
||||
struct usb_dev_handle *usb_handle;
|
||||
};
|
||||
static jtag_libusb_device_handle *usbh;
|
||||
|
||||
/* CY7C65215 model only */
|
||||
#define CY7C65215_JTAG_REQUEST 0x40 /* bmRequestType: vendor host-to-device */
|
||||
#define CY7C65215_JTAG_ENABLE 0xD0 /* bRequest: enable JTAG */
|
||||
#define CY7C65215_JTAG_DISABLE 0xD1 /* bRequest: disable JTAG */
|
||||
#define CY7C65215_JTAG_READ 0xD2 /* bRequest: read buffer */
|
||||
#define CY7C65215_JTAG_WRITE 0xD3 /* bRequest: write buffer */
|
||||
|
||||
#define CY7C65215_USB_TIMEOUT 100
|
||||
|
||||
static const uint16_t cy7c65215_vids[] = {0x04b4, 0};
|
||||
static const uint16_t cy7c65215_pids[] = {0x0007, 0};
|
||||
|
||||
#define CY7C65215_JTAG_CLASS 0xff
|
||||
#define CY7C65215_JTAG_SUBCLASS 0x04
|
||||
|
||||
static unsigned int ep_in, ep_out;
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
|
||||
@@ -201,26 +214,9 @@ static int8_t openjtag_get_tap_state(int8_t state)
|
||||
}
|
||||
}
|
||||
|
||||
static int openjtag_buf_write(
|
||||
static int openjtag_buf_write_standard(
|
||||
uint8_t *buf, int size, uint32_t *bytes_written)
|
||||
{
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
FT_STATUS status;
|
||||
DWORD dw_bytes_written;
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE);
|
||||
#endif
|
||||
|
||||
status = FT_Write(ftdih, buf, size, &dw_bytes_written);
|
||||
if (status != FT_OK) {
|
||||
*bytes_written = dw_bytes_written;
|
||||
LOG_ERROR("FT_Write returned: %u", status);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_written = dw_bytes_written;
|
||||
return ERROR_OK;
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
int retval;
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE);
|
||||
@@ -236,36 +232,56 @@ static int openjtag_buf_write(
|
||||
*bytes_written += retval;
|
||||
|
||||
return ERROR_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read)
|
||||
static int openjtag_buf_write_cy7c65215(
|
||||
uint8_t *buf, int size, uint32_t *bytes_written)
|
||||
{
|
||||
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
DWORD dw_bytes_read;
|
||||
FT_STATUS status;
|
||||
int timeout = 50;
|
||||
|
||||
*bytes_read = 0;
|
||||
while (qty && (*bytes_read < qty) && timeout--) {
|
||||
|
||||
status = FT_Read(ftdih, buf + *bytes_read,
|
||||
qty - *bytes_read, &dw_bytes_read);
|
||||
if (status != FT_OK) {
|
||||
*bytes_read = dw_bytes_read;
|
||||
LOG_ERROR("FT_Read returned: %u", status);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_read += dw_bytes_read;
|
||||
}
|
||||
int ret;
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ);
|
||||
openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE);
|
||||
#endif
|
||||
|
||||
if (size == 0) {
|
||||
*bytes_written = 0;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST,
|
||||
CY7C65215_JTAG_WRITE, size, 0,
|
||||
NULL, 0, CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("vendor command failed, error %d", ret);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
|
||||
CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("bulk write failed, error %d", ret);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_written = ret;
|
||||
|
||||
return ERROR_OK;
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
}
|
||||
|
||||
static int openjtag_buf_write(
|
||||
uint8_t *buf, int size, uint32_t *bytes_written)
|
||||
{
|
||||
switch (openjtag_variant) {
|
||||
case OPENJTAG_VARIANT_CY7C65215:
|
||||
return openjtag_buf_write_cy7c65215(buf, size, bytes_written);
|
||||
default:
|
||||
return openjtag_buf_write_standard(buf, size, bytes_written);
|
||||
}
|
||||
}
|
||||
|
||||
static int openjtag_buf_read_standard(
|
||||
uint8_t *buf, uint32_t qty, uint32_t *bytes_read)
|
||||
{
|
||||
|
||||
int retval;
|
||||
int timeout = 5;
|
||||
|
||||
@@ -287,10 +303,53 @@ static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read)
|
||||
openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int openjtag_buf_read_cy7c65215(
|
||||
uint8_t *buf, uint32_t qty, uint32_t *bytes_read)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (qty == 0) {
|
||||
*bytes_read = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST,
|
||||
CY7C65215_JTAG_READ, qty, 0,
|
||||
NULL, 0, CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("vendor command failed, error %d", ret);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
|
||||
CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("bulk read failed, error %d", ret);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_read = ret;
|
||||
|
||||
out:
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ);
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read)
|
||||
{
|
||||
switch (openjtag_variant) {
|
||||
case OPENJTAG_VARIANT_CY7C65215:
|
||||
return openjtag_buf_read_cy7c65215(buf, qty, bytes_read);
|
||||
default:
|
||||
return openjtag_buf_read_standard(buf, qty, bytes_read);
|
||||
}
|
||||
}
|
||||
|
||||
static int openjtag_sendcommand(uint8_t cmd)
|
||||
{
|
||||
uint32_t written;
|
||||
@@ -335,109 +394,17 @@ static int openjtag_speed(int speed)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int openjtag_init(void)
|
||||
static int openjtag_init_standard(void)
|
||||
{
|
||||
uint8_t latency_timer;
|
||||
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
FT_STATUS status;
|
||||
#endif
|
||||
|
||||
usb_tx_buf_offs = 0;
|
||||
usb_rx_buf_len = 0;
|
||||
openjtag_scan_result_count = 0;
|
||||
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
LOG_DEBUG("'openjtag' interface using FTD2XX");
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
LOG_DEBUG("'openjtag' interface using libftdi");
|
||||
#endif
|
||||
|
||||
/* Open by device description */
|
||||
if (openjtag_device_desc == NULL) {
|
||||
LOG_WARNING("no openjtag device description specified, "
|
||||
/* Open by device description */
|
||||
if (openjtag_device_desc == NULL) {
|
||||
LOG_WARNING("no openjtag device description specified, "
|
||||
"using default 'Open JTAG Project'");
|
||||
openjtag_device_desc = "Open JTAG Project";
|
||||
}
|
||||
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
|
||||
#if IS_WIN32 == 0
|
||||
/* Add non-standard Vid/Pid to the linux driver */
|
||||
status = FT_SetVIDPID(openjtag_vid, openjtag_pid);
|
||||
if (status != FT_OK) {
|
||||
LOG_WARNING("couldn't add %4.4x:%4.4x",
|
||||
openjtag_vid, openjtag_pid);
|
||||
}
|
||||
#endif
|
||||
|
||||
status = FT_OpenEx(openjtag_device_desc, FT_OPEN_BY_DESCRIPTION,
|
||||
&ftdih);
|
||||
if (status != FT_OK) {
|
||||
DWORD num_devices;
|
||||
|
||||
LOG_ERROR("unable to open ftdi device: %u", status);
|
||||
status = FT_ListDevices(&num_devices, NULL,
|
||||
FT_LIST_NUMBER_ONLY);
|
||||
if (status == FT_OK) {
|
||||
char **desc_array = malloc(sizeof(char *)
|
||||
* (num_devices + 1));
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_devices; i++)
|
||||
desc_array[i] = malloc(64);
|
||||
desc_array[num_devices] = NULL;
|
||||
|
||||
status = FT_ListDevices(desc_array, &num_devices,
|
||||
FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
|
||||
|
||||
if (status == FT_OK) {
|
||||
LOG_ERROR("ListDevices: %u\n", num_devices);
|
||||
for (i = 0; i < num_devices; i++)
|
||||
LOG_ERROR("%i: %s", i, desc_array[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devices; i++)
|
||||
free(desc_array[i]);
|
||||
free(desc_array);
|
||||
} else {
|
||||
LOG_ERROR("ListDevices: NONE\n");
|
||||
}
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
openjtag_device_desc = "Open JTAG Project";
|
||||
}
|
||||
|
||||
status = FT_SetLatencyTimer(ftdih, 2);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to set latency timer: %u", status);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
status = FT_GetLatencyTimer(ftdih, &latency_timer);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to get latency timer: %u", status);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
LOG_DEBUG("current latency timer: %i", latency_timer);
|
||||
|
||||
status = FT_SetBitMode(ftdih, 0x00, 0x40);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to disable bit i/o mode: %u", status);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
status = FT_SetTimeouts(ftdih, 50, 0);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to set timeouts: %u", status);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to FT_Purge() %u", status);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
if (ftdi_init(&ftdic) < 0)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
@@ -470,38 +437,107 @@ if (openjtag_device_desc == NULL) {
|
||||
ftdi_get_error_string(&ftdic));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX);
|
||||
if (status != FT_OK)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
if (ftdi_usb_purge_buffers(&ftdic) < 0) {
|
||||
LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* OpenJTAG speed */
|
||||
openjtag_sendcommand(0xE0); /*Start at slowest adapter speed*/
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* MSB */
|
||||
openjtag_sendcommand(0x75);
|
||||
static int openjtag_init_cy7c65215(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
usbh = NULL;
|
||||
ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("unable to open cy7c65215 device");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_choose_interface(usbh, &ep_in, &ep_out,
|
||||
CY7C65215_JTAG_CLASS,
|
||||
CY7C65215_JTAG_SUBCLASS, -1, LIBUSB_TRANSFER_TYPE_BULK);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("unable to claim JTAG interface");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_control_transfer(usbh,
|
||||
CY7C65215_JTAG_REQUEST,
|
||||
CY7C65215_JTAG_ENABLE,
|
||||
0, 0, NULL, 0, CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("could not enable JTAG module");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
err:
|
||||
if (usbh != NULL)
|
||||
jtag_libusb_close(usbh);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
static int openjtag_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
usb_tx_buf_offs = 0;
|
||||
usb_rx_buf_len = 0;
|
||||
openjtag_scan_result_count = 0;
|
||||
|
||||
switch (openjtag_variant) {
|
||||
case OPENJTAG_VARIANT_CY7C65215:
|
||||
ret = openjtag_init_cy7c65215();
|
||||
break;
|
||||
default:
|
||||
ret = openjtag_init_standard();
|
||||
}
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
openjtag_speed(375); /* Start at slowest adapter speed */
|
||||
openjtag_sendcommand(0x75); /* MSB */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int openjtag_quit_standard(void)
|
||||
{
|
||||
ftdi_usb_close(&ftdic);
|
||||
ftdi_deinit(&ftdic);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int openjtag_quit_cy7c65215(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = jtag_libusb_control_transfer(usbh,
|
||||
CY7C65215_JTAG_REQUEST,
|
||||
CY7C65215_JTAG_DISABLE,
|
||||
0, 0, NULL, 0, CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0)
|
||||
LOG_WARNING("could not disable JTAG module");
|
||||
|
||||
jtag_libusb_close(usbh);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int openjtag_quit(void)
|
||||
{
|
||||
#if BUILD_OPENJTAG_FTD2XX == 1
|
||||
FT_Close(ftdih);
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
ftdi_usb_close(&ftdic);
|
||||
ftdi_deinit(&ftdic);
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
switch (openjtag_variant) {
|
||||
case OPENJTAG_VARIANT_CY7C65215:
|
||||
return openjtag_quit_cy7c65215();
|
||||
default:
|
||||
return openjtag_quit_standard();
|
||||
}
|
||||
}
|
||||
|
||||
static void openjtag_write_tap_buffer(void)
|
||||
@@ -536,8 +572,8 @@ static int openjtag_execute_tap_queue(void)
|
||||
|
||||
uint8_t *buffer = openjtag_scan_result_buffer[res_count].buffer;
|
||||
|
||||
while (len) {
|
||||
if (len <= 8) {
|
||||
while (len > 0) {
|
||||
if (len <= 8 && openjtag_variant != OPENJTAG_VARIANT_CY7C65215) {
|
||||
DEBUG_JTAG_IO("bits < 8 buf = 0x%X, will be 0x%X",
|
||||
usb_rx_buf[rx_offs], usb_rx_buf[rx_offs] >> (8 - len));
|
||||
buffer[count] = usb_rx_buf[rx_offs] >> (8 - len);
|
||||
@@ -724,11 +760,14 @@ static void openjtag_execute_runtest(struct jtag_command *cmd)
|
||||
if (cmd->cmd.runtest->num_cycles > 16)
|
||||
LOG_WARNING("num_cycles > 16 on run test");
|
||||
|
||||
uint8_t command;
|
||||
command = 7;
|
||||
command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4;
|
||||
if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 ||
|
||||
cmd->cmd.runtest->num_cycles) {
|
||||
uint8_t command;
|
||||
command = 7;
|
||||
command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4;
|
||||
|
||||
openjtag_add_byte(command);
|
||||
openjtag_add_byte(command);
|
||||
}
|
||||
|
||||
tap_set_end_state(end_state);
|
||||
if (tap_get_end_state() != tap_get_state()) {
|
||||
@@ -816,6 +855,24 @@ COMMAND_HANDLER(openjtag_handle_device_desc_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(openjtag_handle_variant_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
const char * const *name = openjtag_variant_names;
|
||||
int variant = 0;
|
||||
for (; *name; name++, variant++) {
|
||||
if (strcasecmp(CMD_ARGV[0], *name) == 0) {
|
||||
openjtag_variant = variant;
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
LOG_ERROR("unknown openjtag variant '%s'", CMD_ARGV[0]);
|
||||
} else {
|
||||
LOG_ERROR("require exactly one argument to "
|
||||
"openjtag_variant <variant>");
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration openjtag_command_handlers[] = {
|
||||
{
|
||||
@@ -825,6 +882,13 @@ static const struct command_registration openjtag_command_handlers[] = {
|
||||
.help = "set the USB device description of the OpenJTAG",
|
||||
.usage = "description-string",
|
||||
},
|
||||
{
|
||||
.name = "openjtag_variant",
|
||||
.handler = openjtag_handle_variant_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the OpenJTAG variant",
|
||||
.usage = "variant-string",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
|
||||
@@ -34,14 +34,7 @@
|
||||
#include "bitq.h"
|
||||
|
||||
/* PRESTO access library includes */
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
#include <ftd2xx.h>
|
||||
#include "ftd2xx_common.h"
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
#include <ftdi.h>
|
||||
#else
|
||||
#error "BUG: either FTD2XX and LIBFTDI has to be used"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@@ -55,13 +48,8 @@
|
||||
#define BUFFER_SIZE (64*62)
|
||||
|
||||
struct presto {
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
FT_HANDLE handle;
|
||||
FT_STATUS status;
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
struct ftdi_context ftdic;
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
char serial[FT_DEVICE_SERNUM_LEN];
|
||||
|
||||
@@ -95,15 +83,6 @@ static uint8_t presto_init_seq[] = {
|
||||
|
||||
static int presto_write(uint8_t *buf, uint32_t size)
|
||||
{
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
DWORD ftbytes;
|
||||
presto->status = FT_Write(presto->handle, buf, size, &ftbytes);
|
||||
if (presto->status != FT_OK) {
|
||||
LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(presto->status));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
uint32_t ftbytes;
|
||||
presto->retval = ftdi_write_data(&presto->ftdic, buf, size);
|
||||
if (presto->retval < 0) {
|
||||
@@ -111,7 +90,6 @@ static int presto_write(uint8_t *buf, uint32_t size)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
ftbytes = presto->retval;
|
||||
#endif
|
||||
|
||||
if (ftbytes != size) {
|
||||
LOG_ERROR("couldn't write the requested number of bytes to PRESTO (%u < %u)",
|
||||
@@ -124,15 +102,6 @@ static int presto_write(uint8_t *buf, uint32_t size)
|
||||
|
||||
static int presto_read(uint8_t *buf, uint32_t size)
|
||||
{
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
DWORD ftbytes;
|
||||
presto->status = FT_Read(presto->handle, buf, size, &ftbytes);
|
||||
if (presto->status != FT_OK) {
|
||||
LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(presto->status));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
uint32_t ftbytes = 0;
|
||||
|
||||
struct timeval timeout, now;
|
||||
@@ -152,7 +121,6 @@ static int presto_read(uint8_t *buf, uint32_t size)
|
||||
((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec)))
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ftbytes != size) {
|
||||
/* this is just a warning, there might have been timeout when detecting PRESTO,
|
||||
@@ -165,150 +133,6 @@ static int presto_read(uint8_t *buf, uint32_t size)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
static int presto_open_ftd2xx(char *req_serial)
|
||||
{
|
||||
uint32_t i;
|
||||
DWORD numdevs;
|
||||
DWORD vidpid;
|
||||
char devname[FT_DEVICE_NAME_LEN];
|
||||
FT_DEVICE device;
|
||||
|
||||
BYTE presto_data;
|
||||
DWORD ftbytes;
|
||||
|
||||
presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE;
|
||||
|
||||
#if IS_WIN32 == 0
|
||||
/* Add non-standard Vid/Pid to the linux driver */
|
||||
presto->status = FT_SetVIDPID(PRESTO_VID, PRESTO_PID);
|
||||
if (presto->status != FT_OK) {
|
||||
LOG_ERROR("couldn't add PRESTO VID/PID");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
presto->status = FT_ListDevices(&numdevs, NULL, FT_LIST_NUMBER_ONLY);
|
||||
if (presto->status != FT_OK) {
|
||||
LOG_ERROR("FT_ListDevices failed: %s", ftd2xx_status_string(presto->status));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
LOG_DEBUG("FTDI devices available: %" PRIu32, (uint32_t)numdevs);
|
||||
for (i = 0; i < numdevs; i++) {
|
||||
presto->status = FT_Open(i, &(presto->handle));
|
||||
if (presto->status != FT_OK) {
|
||||
/* this is not fatal, the device may be legitimately open by other process,
|
||||
*hence debug message only */
|
||||
LOG_DEBUG("FT_Open failed: %s", ftd2xx_status_string(presto->status));
|
||||
continue;
|
||||
}
|
||||
LOG_DEBUG("FTDI device %i open", (int)i);
|
||||
|
||||
presto->status = FT_GetDeviceInfo(presto->handle, &device,
|
||||
&vidpid, presto->serial, devname, NULL);
|
||||
if (presto->status == FT_OK) {
|
||||
if (vidpid == PRESTO_VID_PID && (req_serial == NULL ||
|
||||
!strcmp(presto->serial, req_serial)))
|
||||
break;
|
||||
} else
|
||||
LOG_DEBUG("FT_GetDeviceInfo failed: %s", ftd2xx_status_string(
|
||||
presto->status));
|
||||
|
||||
LOG_DEBUG("FTDI device %i does not match, closing", (int)i);
|
||||
FT_Close(presto->handle);
|
||||
presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (presto->handle == (FT_HANDLE)INVALID_HANDLE_VALUE)
|
||||
return ERROR_JTAG_DEVICE_ERROR; /* presto not open, return */
|
||||
|
||||
presto->status = FT_SetLatencyTimer(presto->handle, 1);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_SetTimeouts(presto->handle, 100, 0);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0xD0;
|
||||
presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
/* delay between first write/read turnaround (after purge?) necessary
|
||||
* under Linux for unknown reason,
|
||||
* probably a bug in library threading */
|
||||
usleep(100000);
|
||||
presto->status = FT_Read(presto->handle, &presto_data, 1, &ftbytes);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if (ftbytes != 1) {
|
||||
LOG_DEBUG("PRESTO reset");
|
||||
|
||||
presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
presto->status = FT_SetBitMode(presto->handle, 0x80, 1);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
presto->status = FT_SetBaudRate(presto->handle, 9600);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0;
|
||||
for (i = 0; i < 4 * 62; i++) {
|
||||
presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
usleep(100000);
|
||||
|
||||
presto->status = FT_SetBitMode(presto->handle, 0x00, 0);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0xD0;
|
||||
presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
/* delay between first write/read turnaround (after purge?) necessary under Linux for unknown reason,
|
||||
probably a bug in library threading */
|
||||
usleep(100000);
|
||||
presto->status = FT_Read(presto->handle, &presto_data, 1, &ftbytes);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if (ftbytes != 1) {
|
||||
LOG_DEBUG("PRESTO not responding");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
presto->status = FT_SetTimeouts(presto->handle, 0, 0);
|
||||
if (presto->status != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_Write(presto->handle, &presto_init_seq,
|
||||
sizeof(presto_init_seq), &ftbytes);
|
||||
|
||||
if (presto->status != FT_OK || ftbytes != sizeof(presto_init_seq))
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
static int presto_open_libftdi(char *req_serial)
|
||||
{
|
||||
uint8_t presto_data;
|
||||
@@ -371,7 +195,6 @@ static int presto_open_libftdi(char *req_serial)
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif /* BUILD_PRESTO_LIBFTDI == 1 */
|
||||
|
||||
static int presto_open(char *req_serial)
|
||||
{
|
||||
@@ -391,11 +214,7 @@ static int presto_open(char *req_serial)
|
||||
|
||||
presto->jtag_speed = 0;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
return presto_open_ftd2xx(req_serial);
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
return presto_open_libftdi(req_serial);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int presto_close(void)
|
||||
@@ -403,35 +222,6 @@ static int presto_close(void)
|
||||
|
||||
int result = ERROR_OK;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
DWORD ftbytes;
|
||||
|
||||
if (presto->handle == (FT_HANDLE)INVALID_HANDLE_VALUE)
|
||||
return result;
|
||||
|
||||
presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX);
|
||||
if (presto->status != FT_OK)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_Write(presto->handle,
|
||||
&presto_init_seq,
|
||||
sizeof(presto_init_seq),
|
||||
&ftbytes);
|
||||
if (presto->status != FT_OK || ftbytes != sizeof(presto_init_seq))
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_SetLatencyTimer(presto->handle, 16);
|
||||
if (presto->status != FT_OK)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_Close(presto->handle);
|
||||
if (presto->status != FT_OK)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
else
|
||||
presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE;
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
|
||||
presto->retval = ftdi_write_data(&presto->ftdic, presto_init_seq, sizeof(presto_init_seq));
|
||||
if (presto->retval != sizeof(presto_init_seq))
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
@@ -445,7 +235,6 @@ static int presto_close(void)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
else
|
||||
ftdi_deinit(&presto->ftdic);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -455,11 +244,7 @@ static int presto_flush(void)
|
||||
if (presto->buff_out_pos == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
if (presto->status != FT_OK) {
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
if (presto->retval < 0) {
|
||||
#endif
|
||||
LOG_DEBUG("error in previous communication, canceling I/O operation");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
@@ -502,13 +287,9 @@ static int presto_sendbyte(int data)
|
||||
} else
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
if (presto->buff_out_pos >= BUFFER_SIZE)
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
/* libftdi does not do background read, be sure that USB IN buffer does not overflow (128
|
||||
*bytes only!) */
|
||||
if (presto->buff_out_pos >= BUFFER_SIZE || presto->buff_in_exp == 128)
|
||||
#endif
|
||||
return presto_flush();
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -216,7 +216,7 @@ struct stlink_usb_handle_s {
|
||||
#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01
|
||||
#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02
|
||||
|
||||
#define STLINK_TRACE_SIZE 1024
|
||||
#define STLINK_TRACE_SIZE 4096
|
||||
#define STLINK_TRACE_MAX_HZ 2000000
|
||||
#define STLINK_TRACE_MIN_VERSION 13
|
||||
|
||||
|
||||
@@ -242,7 +242,8 @@ static int icdi_send_remote_cmd(void *handle, const char *data)
|
||||
struct icdi_usb_handle_s *h = handle;
|
||||
|
||||
size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,");
|
||||
cmd_len += hexify(h->write_buffer + cmd_len, data, 0, h->max_packet - cmd_len);
|
||||
cmd_len += hexify(h->write_buffer + cmd_len, (const uint8_t *)data,
|
||||
strlen(data), h->max_packet - cmd_len);
|
||||
|
||||
return icdi_send_packet(handle, cmd_len);
|
||||
}
|
||||
@@ -266,7 +267,7 @@ static int icdi_get_cmd_result(void *handle)
|
||||
|
||||
if (h->read_buffer[offset] == 'E') {
|
||||
/* get error code */
|
||||
char result;
|
||||
uint8_t result;
|
||||
if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1)
|
||||
return ERROR_FAIL;
|
||||
return result;
|
||||
@@ -328,7 +329,7 @@ static int icdi_usb_version(void *handle)
|
||||
}
|
||||
|
||||
/* convert reply */
|
||||
if (unhexify(version, h->read_buffer + 2, 4) != 4) {
|
||||
if (unhexify((uint8_t *)version, h->read_buffer + 2, 4) != 4) {
|
||||
LOG_WARNING("unable to get ICDI version");
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -495,7 +496,7 @@ static int icdi_usb_read_reg(void *handle, int num, uint32_t *val)
|
||||
|
||||
/* convert result */
|
||||
uint8_t buf[4];
|
||||
if (unhexify((char *)buf, h->read_buffer + 2, 4) != 4) {
|
||||
if (unhexify(buf, h->read_buffer + 2, 4) != 4) {
|
||||
LOG_ERROR("failed to convert result");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -512,7 +513,7 @@ static int icdi_usb_write_reg(void *handle, int num, uint32_t val)
|
||||
h_u32_to_le(buf, val);
|
||||
|
||||
int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num);
|
||||
hexify(cmd + cmd_len, (const char *)buf, 4, sizeof(cmd));
|
||||
hexify(cmd + cmd_len, buf, 4, sizeof(cmd));
|
||||
|
||||
result = icdi_send_cmd(handle, cmd);
|
||||
if (result != ERROR_OK)
|
||||
|
||||
@@ -2066,7 +2066,7 @@ static int ulink_khz(int khz, int *jtag_speed)
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
long f_tck, f_tms, f_scan_in, f_scan_out, f_scan_io;
|
||||
long f_tck = 0, f_tms = 0, f_scan_in = 0, f_scan_out = 0, f_scan_io = 0;
|
||||
|
||||
ulink_calculate_frequency(DELAY_CLOCK_TCK, ulink_handle->delay_clock_tck,
|
||||
&f_tck);
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libocdusbblaster.la
|
||||
%C%_libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC)
|
||||
%C%_libocdusbblaster_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) $(LIBFTDI_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src/jtag/drivers $(LIBUSB1_CFLAGS) $(LIBFTDI_CFLAGS)
|
||||
USB_BLASTER_SRC = %D%/usb_blaster.c %D%/ublast_access.h
|
||||
|
||||
noinst_LTLIBRARIES = libocdusbblaster.la
|
||||
libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC)
|
||||
|
||||
USB_BLASTER_SRC = usb_blaster.c
|
||||
|
||||
if USB_BLASTER_LIBFTDI
|
||||
USB_BLASTER_SRC += ublast_access_ftdi.c
|
||||
endif
|
||||
|
||||
if USB_BLASTER_FTD2XX
|
||||
USB_BLASTER_SRC += ublast_access_ftd2xx.c
|
||||
if USB_BLASTER
|
||||
USB_BLASTER_SRC += %D%/ublast_access_ftdi.c
|
||||
endif
|
||||
|
||||
if USB_BLASTER_2
|
||||
USB_BLASTER_SRC += ublast2_access_libusb.c
|
||||
USB_BLASTER_SRC += %D%/ublast2_access_libusb.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = ublast_access.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
@@ -56,19 +56,16 @@ struct ublast_lowlevel {
|
||||
|
||||
/**
|
||||
* ublast_register_ftdi - get a lowlevel USB Blaster driver
|
||||
* ublast_register_ftd2xx - get a lowlevel USB Blaster driver
|
||||
* ublast2_register_libusb - get a lowlevel USB Blaster II driver
|
||||
*
|
||||
* Get a lowlevel USB-Blaster driver. In the current implementation, there are 3
|
||||
* Get a lowlevel USB-Blaster driver. In the current implementation, there are 2
|
||||
* possible lowlevel drivers :
|
||||
* - one based on libftdi from ftdichip.com
|
||||
* - one based on libftdxx, the free alternative
|
||||
* - one based on libftdi,
|
||||
* - one based on libusb, specific to the USB-Blaster II
|
||||
*
|
||||
* Returns the lowlevel driver structure.
|
||||
*/
|
||||
extern struct ublast_lowlevel *ublast_register_ftdi(void);
|
||||
extern struct ublast_lowlevel *ublast_register_ftd2xx(void);
|
||||
extern struct ublast_lowlevel *ublast2_register_libusb(void);
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H */
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Driver for USB-JTAG, Altera USB-Blaster and compatibles
|
||||
*
|
||||
* Inspired from original code from Kolja Waschk's USB-JTAG project
|
||||
* (http://www.ixo.de/info/usb_jtag/), and from openocd project.
|
||||
*
|
||||
* Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr
|
||||
* Copyright (C) 2011 Ali Lown ali@lown.me.uk
|
||||
* Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca
|
||||
* Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
|
||||
#include "ublast_access.h"
|
||||
|
||||
#include <ftd2xx.h>
|
||||
#include "jtag/drivers/ftd2xx_common.h"
|
||||
|
||||
static FT_HANDLE *ublast_getftdih(struct ublast_lowlevel *low)
|
||||
{
|
||||
return low->priv;
|
||||
}
|
||||
|
||||
static int ublast_ftd2xx_write(struct ublast_lowlevel *low, uint8_t *buf, int size,
|
||||
uint32_t *bytes_written)
|
||||
{
|
||||
FT_STATUS status;
|
||||
DWORD dw_bytes_written;
|
||||
FT_HANDLE *ftdih = ublast_getftdih(low);
|
||||
|
||||
status = FT_Write(*ftdih, buf, size, &dw_bytes_written);
|
||||
if (status != FT_OK) {
|
||||
*bytes_written = dw_bytes_written;
|
||||
LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(status));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_written = dw_bytes_written;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ublast_ftd2xx_read(struct ublast_lowlevel *low, uint8_t *buf,
|
||||
unsigned size, uint32_t *bytes_read)
|
||||
{
|
||||
DWORD dw_bytes_read;
|
||||
FT_STATUS status;
|
||||
FT_HANDLE *ftdih = ublast_getftdih(low);
|
||||
|
||||
status = FT_Read(*ftdih, buf, size, &dw_bytes_read);
|
||||
if (status != FT_OK) {
|
||||
*bytes_read = dw_bytes_read;
|
||||
LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(status));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_read = dw_bytes_read;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ublast_ftd2xx_init(struct ublast_lowlevel *low)
|
||||
{
|
||||
FT_STATUS status;
|
||||
FT_HANDLE *ftdih = ublast_getftdih(low);
|
||||
uint8_t latency_timer;
|
||||
|
||||
LOG_INFO("usb blaster interface using FTD2XX");
|
||||
/* Open by device description */
|
||||
if (low->ublast_device_desc == NULL) {
|
||||
LOG_WARNING("no usb blaster device description specified, "
|
||||
"using default 'USB-Blaster'");
|
||||
low->ublast_device_desc = "USB-Blaster";
|
||||
}
|
||||
|
||||
#if IS_WIN32 == 0
|
||||
/* Add non-standard Vid/Pid to the linux driver */
|
||||
status = FT_SetVIDPID(low->ublast_vid, low->ublast_pid);
|
||||
if (status != FT_OK) {
|
||||
LOG_WARNING("couldn't add %4.4x:%4.4x",
|
||||
low->ublast_vid, low->ublast_pid);
|
||||
}
|
||||
#endif
|
||||
status = FT_OpenEx(low->ublast_device_desc, FT_OPEN_BY_DESCRIPTION,
|
||||
ftdih);
|
||||
if (status != FT_OK) {
|
||||
DWORD num_devices;
|
||||
|
||||
LOG_ERROR("unable to open ftdi device: %s",
|
||||
ftd2xx_status_string(status));
|
||||
status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
|
||||
if (status == FT_OK) {
|
||||
char **desc_array =
|
||||
malloc(sizeof(char *) * (num_devices + 1));
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_devices; i++)
|
||||
desc_array[i] = malloc(64);
|
||||
desc_array[num_devices] = NULL;
|
||||
|
||||
status = FT_ListDevices(desc_array, &num_devices,
|
||||
FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
|
||||
|
||||
if (status == FT_OK) {
|
||||
LOG_ERROR("ListDevices: %" PRIu32, (uint32_t)num_devices);
|
||||
for (i = 0; i < num_devices; i++)
|
||||
LOG_ERROR("%i: %s", i, desc_array[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devices; i++)
|
||||
free(desc_array[i]);
|
||||
free(desc_array);
|
||||
} else {
|
||||
printf("ListDevices: NONE\n");
|
||||
}
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
status = FT_SetLatencyTimer(*ftdih, 2);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to set latency timer: %s",
|
||||
ftd2xx_status_string(status));
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
status = FT_GetLatencyTimer(*ftdih, &latency_timer);
|
||||
if (status != FT_OK)
|
||||
LOG_ERROR("unable to get latency timer: %s",
|
||||
ftd2xx_status_string(status));
|
||||
else
|
||||
LOG_DEBUG("current latency timer: %i", latency_timer);
|
||||
|
||||
status = FT_SetBitMode(*ftdih, 0x00, 0);
|
||||
if (status != FT_OK) {
|
||||
LOG_ERROR("unable to disable bit i/o mode: %s",
|
||||
ftd2xx_status_string(status));
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ublast_ftd2xx_quit(struct ublast_lowlevel *low)
|
||||
{
|
||||
FT_HANDLE *ftdih = ublast_getftdih(low);
|
||||
|
||||
FT_Close(*ftdih);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static struct ublast_lowlevel_priv {
|
||||
FT_HANDLE ftdih;
|
||||
} info;
|
||||
|
||||
static struct ublast_lowlevel low = {
|
||||
.open = ublast_ftd2xx_init,
|
||||
.close = ublast_ftd2xx_quit,
|
||||
.read = ublast_ftd2xx_read,
|
||||
.write = ublast_ftd2xx_write,
|
||||
.priv = &info,
|
||||
};
|
||||
|
||||
struct ublast_lowlevel *ublast_register_ftd2xx(void)
|
||||
{
|
||||
return &low;
|
||||
}
|
||||
@@ -147,12 +147,9 @@ struct drvs_map {
|
||||
};
|
||||
|
||||
static struct drvs_map lowlevel_drivers_map[] = {
|
||||
#if BUILD_USB_BLASTER_LIBFTDI
|
||||
#if BUILD_USB_BLASTER
|
||||
{ .name = "ftdi", .drv_register = ublast_register_ftdi },
|
||||
#endif
|
||||
#if BUILD_USB_BLASTER_FTD2XX
|
||||
{ .name = "ftd2xx", .drv_register = ublast_register_ftd2xx },
|
||||
#endif
|
||||
#if BUILD_USB_BLASTER_2
|
||||
{ .name = "ublast2", .drv_register = ublast2_register_libusb },
|
||||
#endif
|
||||
@@ -1048,8 +1045,8 @@ static const struct command_registration ublast_command_handlers[] = {
|
||||
.name = "usb_blaster_lowlevel_driver",
|
||||
.handler = ublast_handle_lowlevel_drv_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the lowlevel access for the USB Blaster (ftdi, ftd2xx, ublast2)",
|
||||
.usage = "(ftdi|ftd2xx|ublast2)",
|
||||
.help = "set the lowlevel access for the USB Blaster (ftdi, ublast2)",
|
||||
.usage = "(ftdi|ublast2)",
|
||||
},
|
||||
{
|
||||
.name = "usb_blaster_pin",
|
||||
|
||||
+10
-22
@@ -1,23 +1,11 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libocdhla.la
|
||||
|
||||
noinst_LTLIBRARIES = libocdhla.la
|
||||
|
||||
libocdhla_la_SOURCES = \
|
||||
$(HLFILES)
|
||||
|
||||
HLFILES =
|
||||
|
||||
if HLADAPTER
|
||||
HLFILES += hla_transport.c
|
||||
HLFILES += hla_tcl.c
|
||||
HLFILES += hla_interface.c
|
||||
HLFILES += hla_layout.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
hla_interface.h \
|
||||
hla_layout.h \
|
||||
hla_tcl.h \
|
||||
hla_transport.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
%C%_libocdhla_la_SOURCES = \
|
||||
%D%/hla_transport.c \
|
||||
%D%/hla_tcl.c \
|
||||
%D%/hla_interface.c \
|
||||
%D%/hla_layout.c \
|
||||
%D%/hla_transport.h \
|
||||
%D%/hla_interface.h \
|
||||
%D%/hla_layout.h \
|
||||
%D%/hla_tcl.h
|
||||
|
||||
+16
-16
@@ -51,16 +51,10 @@ extern struct jtag_interface parport_interface;
|
||||
#if BUILD_DUMMY == 1
|
||||
extern struct jtag_interface dummy_interface;
|
||||
#endif
|
||||
#if BUILD_FT2232_FTD2XX == 1
|
||||
extern struct jtag_interface ft2232_interface;
|
||||
#endif
|
||||
#if BUILD_FT2232_LIBFTDI == 1
|
||||
extern struct jtag_interface ft2232_interface;
|
||||
#endif
|
||||
#if BUILD_FTDI == 1
|
||||
extern struct jtag_interface ftdi_interface;
|
||||
#endif
|
||||
#if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1 || BUILD_USB_BLASTER_2 == 1
|
||||
#if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1
|
||||
extern struct jtag_interface usb_blaster_interface;
|
||||
#endif
|
||||
#if BUILD_JTAG_VPI == 1
|
||||
@@ -78,7 +72,7 @@ extern struct jtag_interface at91rm9200_interface;
|
||||
#if BUILD_GW16012 == 1
|
||||
extern struct jtag_interface gw16012_interface;
|
||||
#endif
|
||||
#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
|
||||
#if BUILD_PRESTO
|
||||
extern struct jtag_interface presto_interface;
|
||||
#endif
|
||||
#if BUILD_USBPROG == 1
|
||||
@@ -129,6 +123,12 @@ extern struct jtag_interface bcm2835gpio_interface;
|
||||
#if BUILD_CMSIS_DAP == 1
|
||||
extern struct jtag_interface cmsis_dap_interface;
|
||||
#endif
|
||||
#if BUILD_KITPROG == 1
|
||||
extern struct jtag_interface kitprog_interface;
|
||||
#endif
|
||||
#if BUILD_IMX_GPIO == 1
|
||||
extern struct jtag_interface imx_gpio_interface;
|
||||
#endif
|
||||
#endif /* standard drivers */
|
||||
|
||||
/**
|
||||
@@ -150,16 +150,10 @@ struct jtag_interface *jtag_interfaces[] = {
|
||||
#if BUILD_DUMMY == 1
|
||||
&dummy_interface,
|
||||
#endif
|
||||
#if BUILD_FT2232_FTD2XX == 1
|
||||
&ft2232_interface,
|
||||
#endif
|
||||
#if BUILD_FT2232_LIBFTDI == 1
|
||||
&ft2232_interface,
|
||||
#endif
|
||||
#if BUILD_FTDI == 1
|
||||
&ftdi_interface,
|
||||
#endif
|
||||
#if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1 || BUILD_USB_BLASTER_2 == 1
|
||||
#if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1
|
||||
&usb_blaster_interface,
|
||||
#endif
|
||||
#if BUILD_JTAG_VPI == 1
|
||||
@@ -177,7 +171,7 @@ struct jtag_interface *jtag_interfaces[] = {
|
||||
#if BUILD_GW16012 == 1
|
||||
&gw16012_interface,
|
||||
#endif
|
||||
#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
|
||||
#if BUILD_PRESTO
|
||||
&presto_interface,
|
||||
#endif
|
||||
#if BUILD_USBPROG == 1
|
||||
@@ -228,6 +222,12 @@ struct jtag_interface *jtag_interfaces[] = {
|
||||
#if BUILD_CMSIS_DAP == 1
|
||||
&cmsis_dap_interface,
|
||||
#endif
|
||||
#if BUILD_KITPROG == 1
|
||||
&kitprog_interface,
|
||||
#endif
|
||||
#if BUILD_IMX_GPIO == 1
|
||||
&imx_gpio_interface,
|
||||
#endif
|
||||
#endif /* standard drivers */
|
||||
NULL,
|
||||
};
|
||||
|
||||
+8
-1
@@ -45,8 +45,13 @@
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef PKGBLDDATE
|
||||
#define OPENOCD_VERSION \
|
||||
"Open On-Chip Debugger " VERSION RELSTR " (" PKGBLDDATE ")"
|
||||
#else
|
||||
#define OPENOCD_VERSION \
|
||||
"Open On-Chip Debugger " VERSION RELSTR
|
||||
#endif
|
||||
|
||||
static const char openocd_startup_tcl[] = {
|
||||
#include "startup_tcl.inc"
|
||||
@@ -292,8 +297,10 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct
|
||||
|
||||
if (init_at_startup) {
|
||||
ret = command_run_line(cmd_ctx, "init");
|
||||
if (ERROR_OK != ret)
|
||||
if (ERROR_OK != ret) {
|
||||
server_quit();
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = server_loop(cmd_ctx);
|
||||
|
||||
+8
-8
@@ -1,8 +1,8 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libpld.la
|
||||
noinst_HEADERS = pld.h xilinx_bit.h virtex2.h
|
||||
libpld_la_SOURCES = pld.c xilinx_bit.c virtex2.c
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
noinst_LTLIBRARIES += %D%/libpld.la
|
||||
%C%_libpld_la_SOURCES = \
|
||||
%D%/pld.c \
|
||||
%D%/xilinx_bit.c \
|
||||
%D%/virtex2.c \
|
||||
%D%/pld.h \
|
||||
%D%/xilinx_bit.h \
|
||||
%D%/virtex2.h
|
||||
|
||||
+3
-3
@@ -440,11 +440,11 @@ static int ChibiOS_update_threads(struct rtos *rtos)
|
||||
if (threadState < CHIBIOS_NUM_STATES)
|
||||
state_desc = ChibiOS_thread_states[threadState];
|
||||
else
|
||||
state_desc = "Unknown state";
|
||||
state_desc = "Unknown";
|
||||
|
||||
curr_thrd_details->extra_info_str = malloc(strlen(
|
||||
state_desc)+1);
|
||||
strcpy(curr_thrd_details->extra_info_str, state_desc);
|
||||
state_desc)+8);
|
||||
sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc);
|
||||
|
||||
curr_thrd_details->exists = true;
|
||||
|
||||
|
||||
+1
-1
@@ -362,7 +362,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
|
||||
rtos->thread_details[tasks_found].exists = true;
|
||||
|
||||
if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) {
|
||||
char running_str[] = "Running";
|
||||
char running_str[] = "State: Running";
|
||||
rtos->thread_details[tasks_found].extra_info_str = malloc(
|
||||
sizeof(running_str));
|
||||
strcpy(rtos->thread_details[tasks_found].extra_info_str,
|
||||
|
||||
+29
-27
@@ -1,32 +1,34 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (C) 2011 by Broadcom Corporation *
|
||||
# * Evan Hunter - ehunter@broadcom.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, see <http://www.gnu.org/licenses/>. *
|
||||
# ***************************************************************************
|
||||
noinst_LTLIBRARIES += %D%/librtos.la
|
||||
%C%_librtos_la_SOURCES = \
|
||||
%D%/rtos.c \
|
||||
%D%/rtos_standard_stackings.c \
|
||||
%D%/rtos_ecos_stackings.c \
|
||||
%D%/rtos_chibios_stackings.c \
|
||||
%D%/rtos_embkernel_stackings.c \
|
||||
%D%/rtos_mqx_stackings.c \
|
||||
%D%/rtos_ucos_iii_stackings.c \
|
||||
%D%/FreeRTOS.c \
|
||||
%D%/ThreadX.c \
|
||||
%D%/eCos.c \
|
||||
%D%/linux.c \
|
||||
%D%/ChibiOS.c \
|
||||
%D%/embKernel.c \
|
||||
%D%/mqx.c \
|
||||
%D%/riscv_debug.c \
|
||||
%D%/uCOS-III.c \
|
||||
%D%/rtos.h \
|
||||
%D%/rtos_standard_stackings.h \
|
||||
%D%/rtos_ecos_stackings.h \
|
||||
%D%/linux_header.h \
|
||||
%D%/rtos_chibios_stackings.h \
|
||||
%D%/rtos_embkernel_stackings.h \
|
||||
%D%/rtos_mqx_stackings.h \
|
||||
%D%/rtos_ucos_iii_stackings.h \
|
||||
%D%/riscv_debug.h
|
||||
|
||||
include $(top_srcdir)/common.mk
|
||||
%C%_librtos_la_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = librtos.la
|
||||
noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h linux_header.h rtos_chibios_stackings.h rtos_embkernel_stackings.h rtos_mqx_stackings.h riscv_debug.h
|
||||
librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c rtos_chibios_stackings.c rtos_embkernel_stackings.c rtos_mqx_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c embKernel.c mqx.c riscv_debug.c
|
||||
|
||||
librtos_la_CFLAGS =
|
||||
if IS_MINGW
|
||||
# FD_* macros are sloppy with their signs on MinGW32 platform
|
||||
librtos_la_CFLAGS += -Wno-sign-compare
|
||||
%C%_librtos_la_CFLAGS += -Wno-sign-compare
|
||||
endif
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
+2
-2
@@ -408,8 +408,8 @@ static int ThreadX_update_threads(struct rtos *rtos)
|
||||
state_desc = "Unknown state";
|
||||
|
||||
rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
|
||||
state_desc)+1);
|
||||
strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
|
||||
state_desc)+8);
|
||||
sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
|
||||
|
||||
rtos->thread_details[tasks_found].exists = true;
|
||||
|
||||
|
||||
+2
-2
@@ -261,8 +261,8 @@ static int eCos_update_threads(struct rtos *rtos)
|
||||
state_desc = "Unknown state";
|
||||
|
||||
rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
|
||||
state_desc)+1);
|
||||
strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
|
||||
state_desc)+8);
|
||||
sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
|
||||
|
||||
rtos->thread_details[tasks_found].exists = true;
|
||||
|
||||
|
||||
@@ -168,11 +168,11 @@ static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, cons
|
||||
return retval;
|
||||
details->extra_info_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
|
||||
if (task == rtos->current_thread) {
|
||||
snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, Running",
|
||||
snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: Running, Priority: %u",
|
||||
(unsigned int) priority);
|
||||
} else {
|
||||
snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, %s", (unsigned int) priority,
|
||||
state_str);
|
||||
snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: %s, Priority: %u",
|
||||
state_str, (unsigned int) priority);
|
||||
}
|
||||
|
||||
LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
|
||||
|
||||
+6
-7
@@ -105,11 +105,11 @@ static int linux_os_dummy_update(struct rtos *rtos)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linux_compute_virt2phys(struct target *target, uint32_t address)
|
||||
static int linux_compute_virt2phys(struct target *target, target_addr_t address)
|
||||
{
|
||||
struct linux_os *linux_os = (struct linux_os *)
|
||||
target->rtos->rtos_specific_params;
|
||||
uint32_t pa = 0;
|
||||
target_addr_t pa = 0;
|
||||
int retval = target->type->virt2phys(target, address, &pa);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Cannot compute linux virt2phys translation");
|
||||
@@ -1213,7 +1213,7 @@ int linux_thread_extra_info(struct target *target,
|
||||
if (temp->threadid == threadid) {
|
||||
char *pid = " PID: ";
|
||||
char *pid_current = "*PID: ";
|
||||
char *name = "NAME: ";
|
||||
char *name = "Name: ";
|
||||
int str_size = strlen(pid) + strlen(name);
|
||||
char *tmp_str = calloc(1, str_size + 50);
|
||||
char *tmp_str_ptr = tmp_str;
|
||||
@@ -1225,13 +1225,12 @@ int linux_thread_extra_info(struct target *target,
|
||||
else
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid);
|
||||
|
||||
tmp_str_ptr +=
|
||||
sprintf(tmp_str_ptr, "%d", (int)temp->pid);
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, "%s", " | ");
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, "%d, ", (int)temp->pid);
|
||||
sprintf(tmp_str_ptr, "%s", name);
|
||||
sprintf(tmp_str_ptr, "%s", temp->name);
|
||||
char *hex_str = calloc(1, strlen(tmp_str) * 2 + 1);
|
||||
int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1);
|
||||
size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str,
|
||||
strlen(tmp_str), strlen(tmp_str) * 2 + 1);
|
||||
gdb_put_packet(connection, hex_str, pkt_len);
|
||||
free(hex_str);
|
||||
free(tmp_str);
|
||||
|
||||
+5
-5
@@ -353,7 +353,7 @@ static int mqx_update_threads(
|
||||
uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
|
||||
uint32_t state_index = 0, state_max = 0;
|
||||
uint32_t extra_info_length = 0;
|
||||
char *state_name = "unknown state";
|
||||
char *state_name = "Unknown";
|
||||
|
||||
/* set current taskpool address */
|
||||
if (ERROR_OK != mqx_get_member(
|
||||
@@ -435,13 +435,13 @@ static int mqx_update_threads(
|
||||
* calculate length as:
|
||||
* state length + address length + errno length + formatter length
|
||||
*/
|
||||
extra_info_length += strlen((void *)state_name) + 8 + 8 + 8;
|
||||
extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8;
|
||||
rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
|
||||
if (NULL == rtos->thread_details[i].extra_info_str)
|
||||
return ERROR_FAIL;
|
||||
snprintf(
|
||||
rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%"PRIx32 " : %" PRIu32,
|
||||
state_name, task_addr, task_errno
|
||||
snprintf(rtos->thread_details[i].extra_info_str, extra_info_length,
|
||||
"State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32,
|
||||
state_name, task_addr, task_errno
|
||||
);
|
||||
/* set active thread */
|
||||
if (active_td_addr == task_addr)
|
||||
|
||||
+32
-13
@@ -34,6 +34,7 @@ extern struct rtos_type Linux_os;
|
||||
extern struct rtos_type ChibiOS_rtos;
|
||||
extern struct rtos_type embKernel_rtos;
|
||||
extern struct rtos_type mqx_rtos;
|
||||
extern struct rtos_type uCOS_III_rtos;
|
||||
extern struct rtos_type riscv_rtos;
|
||||
|
||||
static struct rtos_type *rtos_types[] = {
|
||||
@@ -44,6 +45,7 @@ static struct rtos_type *rtos_types[] = {
|
||||
&ChibiOS_rtos,
|
||||
&embKernel_rtos,
|
||||
&mqx_rtos,
|
||||
&uCOS_III_rtos,
|
||||
&riscv_rtos,
|
||||
NULL
|
||||
};
|
||||
@@ -107,6 +109,7 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target)
|
||||
int x;
|
||||
const char *cp;
|
||||
struct Jim_Obj *res;
|
||||
int e;
|
||||
|
||||
if (!goi->isconfigure && goi->argc != 0) {
|
||||
Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
|
||||
@@ -115,7 +118,9 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target)
|
||||
|
||||
os_free(target);
|
||||
|
||||
Jim_GetOpt_String(goi, &cp, NULL);
|
||||
e = Jim_GetOpt_String(goi, &cp, NULL);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
|
||||
if (0 == strcmp(cp, "auto")) {
|
||||
/* Auto detect tries to look up all symbols for each RTOS,
|
||||
@@ -216,7 +221,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
|
||||
goto done;
|
||||
|
||||
/* Decode any symbol name in the packet*/
|
||||
int len = unhexify(cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1));
|
||||
size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1));
|
||||
cur_sym[len] = 0;
|
||||
|
||||
if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
|
||||
@@ -264,7 +269,9 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
|
||||
}
|
||||
|
||||
reply_len = snprintf(reply, sizeof(reply), "qSymbol:");
|
||||
reply_len += hexify(reply + reply_len, next_sym->symbol_name, 0, sizeof(reply) - reply_len);
|
||||
reply_len += hexify(reply + reply_len,
|
||||
(const uint8_t *)next_sym->symbol_name, strlen(next_sym->symbol_name),
|
||||
sizeof(reply) - reply_len);
|
||||
|
||||
done:
|
||||
gdb_put_packet(connection, reply, reply_len);
|
||||
@@ -304,14 +311,14 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
|
||||
if (detail->extra_info_str != NULL)
|
||||
str_size += strlen(detail->extra_info_str);
|
||||
|
||||
char *tmp_str = calloc(str_size + 4, sizeof(char));
|
||||
char *tmp_str = calloc(str_size + 9, sizeof(char));
|
||||
char *tmp_str_ptr = tmp_str;
|
||||
|
||||
if (detail->thread_name_str != NULL)
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str);
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, "Name: %s", detail->thread_name_str);
|
||||
if (detail->extra_info_str != NULL) {
|
||||
if (tmp_str_ptr != tmp_str)
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, ", ");
|
||||
tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->extra_info_str);
|
||||
}
|
||||
|
||||
@@ -319,7 +326,8 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
|
||||
(size_t) (tmp_str_ptr - tmp_str));
|
||||
|
||||
char *hex_str = malloc(strlen(tmp_str) * 2 + 1);
|
||||
int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1);
|
||||
size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str,
|
||||
strlen(tmp_str), strlen(tmp_str) * 2 + 1);
|
||||
|
||||
gdb_put_packet(connection, hex_str, pkt_len);
|
||||
free(hex_str);
|
||||
@@ -400,9 +408,14 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
|
||||
} else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
|
||||
* all other operations ) */
|
||||
if ((packet[1] == 'g') && (target->rtos != NULL)) {
|
||||
sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
|
||||
LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64 "\r\n",
|
||||
target->rtos->current_threadid);
|
||||
threadid_t threadid;
|
||||
sscanf(packet, "Hg%16" SCNx64, &threadid);
|
||||
LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64, threadid);
|
||||
/* threadid of 0 indicates target should choose */
|
||||
if (threadid == 0)
|
||||
target->rtos->current_threadid = target->rtos->current_thread;
|
||||
else
|
||||
target->rtos->current_threadid = threadid;
|
||||
}
|
||||
gdb_put_packet(connection, "OK", 2);
|
||||
return ERROR_OK;
|
||||
@@ -426,9 +439,13 @@ int rtos_get_gdb_reg_list(struct connection *connection)
|
||||
current_threadid,
|
||||
target->rtos->current_thread);
|
||||
|
||||
target->rtos->type->get_thread_reg_list(target->rtos,
|
||||
current_threadid,
|
||||
&hex_reg_list);
|
||||
int retval = target->rtos->type->get_thread_reg_list(target->rtos,
|
||||
current_threadid,
|
||||
&hex_reg_list);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("RTOS: failed to get register list");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (hex_reg_list != NULL) {
|
||||
gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
|
||||
@@ -546,5 +563,7 @@ void rtos_free_threadlist(struct rtos *rtos)
|
||||
free(rtos->thread_details);
|
||||
rtos->thread_details = NULL;
|
||||
rtos->thread_count = 0;
|
||||
rtos->current_threadid = -1;
|
||||
rtos->current_thread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2016 by Square, Inc. *
|
||||
* Steven Stallion <stallion@squareup.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, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rtos.h"
|
||||
#include "rtos_standard_stackings.h"
|
||||
#include "target/armv7m.h"
|
||||
|
||||
static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
|
||||
{ 0x20, 32 }, /* r0 */
|
||||
{ 0x24, 32 }, /* r1 */
|
||||
{ 0x28, 32 }, /* r2 */
|
||||
{ 0x2c, 32 }, /* r3 */
|
||||
{ 0x00, 32 }, /* r4 */
|
||||
{ 0x04, 32 }, /* r5 */
|
||||
{ 0x08, 32 }, /* r6 */
|
||||
{ 0x0c, 32 }, /* r7 */
|
||||
{ 0x10, 32 }, /* r8 */
|
||||
{ 0x14, 32 }, /* r9 */
|
||||
{ 0x18, 32 }, /* r10 */
|
||||
{ 0x1c, 32 }, /* r11 */
|
||||
{ 0x30, 32 }, /* r12 */
|
||||
{ -2, 32 }, /* sp */
|
||||
{ 0x34, 32 }, /* lr */
|
||||
{ 0x38, 32 }, /* pc */
|
||||
{ 0x3c, 32 }, /* xPSR */
|
||||
};
|
||||
|
||||
const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = {
|
||||
0x40, /* stack_registers_size */
|
||||
-1, /* stack_growth_direction */
|
||||
ARMV7M_NUM_CORE_REGS, /* num_output_registers */
|
||||
rtos_generic_stack_align8, /* stack_alignment */
|
||||
rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* Copyright (C) 2016 by Square, Inc. *
|
||||
* Steven Stallion <stallion@squareup.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 *
|
||||
@@ -16,53 +16,15 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#define REG_R0 0
|
||||
#define REG_R1 1
|
||||
#define REG_R2 2
|
||||
#define REG_R3 3
|
||||
#define REG_R4 4
|
||||
#define REG_R5 5
|
||||
#define REG_R6 6
|
||||
#define REG_R7 7
|
||||
#define REG_R8 8
|
||||
#define REG_R9 9
|
||||
#define REG_R10 10
|
||||
#define REG_R11 11
|
||||
#define REG_R12 12
|
||||
#define REG_R13 13
|
||||
#define REG_R14 14
|
||||
#define REG_R15 15
|
||||
#define REG_CPSR 16
|
||||
#define REG_SPSR 17
|
||||
#ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H
|
||||
#define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H
|
||||
|
||||
#define MODE_USR 0x10
|
||||
#define MODE_FIQ 0x11
|
||||
#define MODE_IRQ 0x12
|
||||
#define MODE_SVC 0x13
|
||||
#define MODE_ABT 0x17
|
||||
#define MODE_UND 0x1b
|
||||
#define MODE_SYS 0x1f
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define MODE_ANY 0x40
|
||||
#define MODE_CURRENT 0x80
|
||||
#include "rtos.h"
|
||||
|
||||
#define MODE_MASK 0x1f
|
||||
#define PSR_I 0x80
|
||||
#define PSR_F 0x40
|
||||
#define PSR_T 0x20
|
||||
extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking;
|
||||
|
||||
#define XSCALE_DBG_MAINID 0x0
|
||||
#define XSCALE_DBG_CACHETYPE 0x1
|
||||
#define XSCALE_DBG_CTRL 0x2
|
||||
#define XSCALE_DBG_AUXCTRL 0x3
|
||||
#define XSCALE_DBG_TTB 0x4
|
||||
#define XSCALE_DBG_DAC 0x5
|
||||
#define XSCALE_DBG_FSR 0x6
|
||||
#define XSCALE_DBG_FAR 0x7
|
||||
#define XSCALE_DBG_PID 0x8
|
||||
#define XSCALE_DBG_CPACCESS 0x9
|
||||
#define XSCALE_DBG_IBCR0 0xa
|
||||
#define XSCALE_DBG_IBCR1 0xb
|
||||
#define XSCALE_DBG_DBR0 0xc
|
||||
#define XSCALE_DBG_DBR1 0xd
|
||||
#define XSCALE_DBG_DBCON 0xe
|
||||
#endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */
|
||||
@@ -0,0 +1,509 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2016 by Square, Inc. *
|
||||
* Steven Stallion <stallion@squareup.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, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <helper/time_support.h>
|
||||
#include <jtag/jtag.h>
|
||||
#include "target/target.h"
|
||||
#include "target/target_type.h"
|
||||
#include "rtos.h"
|
||||
#include "helper/log.h"
|
||||
#include "helper/types.h"
|
||||
#include "rtos/rtos_ucos_iii_stackings.h"
|
||||
|
||||
#ifndef UCOS_III_MAX_STRLEN
|
||||
#define UCOS_III_MAX_STRLEN 64
|
||||
#endif
|
||||
|
||||
#ifndef UCOS_III_MAX_THREADS
|
||||
#define UCOS_III_MAX_THREADS 256
|
||||
#endif
|
||||
|
||||
struct uCOS_III_params {
|
||||
const char *target_name;
|
||||
const unsigned char pointer_width;
|
||||
symbol_address_t thread_stack_offset;
|
||||
symbol_address_t thread_name_offset;
|
||||
symbol_address_t thread_state_offset;
|
||||
symbol_address_t thread_priority_offset;
|
||||
symbol_address_t thread_prev_offset;
|
||||
symbol_address_t thread_next_offset;
|
||||
bool thread_offsets_updated;
|
||||
size_t threadid_start;
|
||||
const struct rtos_register_stacking *stacking_info;
|
||||
size_t num_threads;
|
||||
symbol_address_t threads[];
|
||||
};
|
||||
|
||||
static const struct uCOS_III_params uCOS_III_params_list[] = {
|
||||
{
|
||||
"cortex_m", /* target_name */
|
||||
sizeof(uint32_t), /* pointer_width */
|
||||
0, /* thread_stack_offset */
|
||||
0, /* thread_name_offset */
|
||||
0, /* thread_state_offset */
|
||||
0, /* thread_priority_offset */
|
||||
0, /* thread_prev_offset */
|
||||
0, /* thread_next_offset */
|
||||
false, /* thread_offsets_updated */
|
||||
1, /* threadid_start */
|
||||
&rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */
|
||||
0, /* num_threads */
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const uCOS_III_symbol_list[] = {
|
||||
"OSRunning",
|
||||
"OSTCBCurPtr",
|
||||
"OSTaskDbgListPtr",
|
||||
"OSTaskQty",
|
||||
|
||||
/* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
|
||||
"openocd_OS_TCB_StkPtr_offset",
|
||||
"openocd_OS_TCB_NamePtr_offset",
|
||||
"openocd_OS_TCB_TaskState_offset",
|
||||
"openocd_OS_TCB_Prio_offset",
|
||||
"openocd_OS_TCB_DbgPrevPtr_offset",
|
||||
"openocd_OS_TCB_DbgNextPtr_offset",
|
||||
NULL
|
||||
};
|
||||
|
||||
enum uCOS_III_symbol_values {
|
||||
uCOS_III_VAL_OSRunning,
|
||||
uCOS_III_VAL_OSTCBCurPtr,
|
||||
uCOS_III_VAL_OSTaskDbgListPtr,
|
||||
uCOS_III_VAL_OSTaskQty,
|
||||
|
||||
/* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
|
||||
uCOS_III_VAL_OS_TCB_StkPtr_offset,
|
||||
uCOS_III_VAL_OS_TCB_NamePtr_offset,
|
||||
uCOS_III_VAL_OS_TCB_TaskState_offset,
|
||||
uCOS_III_VAL_OS_TCB_Prio_offset,
|
||||
uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
|
||||
uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
|
||||
};
|
||||
|
||||
static const char * const uCOS_III_thread_state_list[] = {
|
||||
"Ready",
|
||||
"Delay",
|
||||
"Pend",
|
||||
"Pend Timeout",
|
||||
"Suspended",
|
||||
"Delay Suspended",
|
||||
"Pend Suspended",
|
||||
"Pend Timeout Suspended",
|
||||
};
|
||||
|
||||
static int uCOS_III_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
|
||||
threadid_t *threadid)
|
||||
{
|
||||
struct uCOS_III_params *params = rtos->rtos_specific_params;
|
||||
size_t thread_index;
|
||||
|
||||
for (thread_index = 0; thread_index < params->num_threads; thread_index++)
|
||||
if (params->threads[thread_index] == thread_address)
|
||||
goto found;
|
||||
|
||||
if (params->num_threads == UCOS_III_MAX_THREADS) {
|
||||
LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
params->threads[thread_index] = thread_address;
|
||||
params->num_threads++;
|
||||
found:
|
||||
*threadid = thread_index + params->threadid_start;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int uCOS_III_find_thread_address(struct rtos *rtos, threadid_t threadid,
|
||||
symbol_address_t *thread_address)
|
||||
{
|
||||
struct uCOS_III_params *params = rtos->rtos_specific_params;
|
||||
size_t thread_index;
|
||||
|
||||
thread_index = threadid - params->threadid_start;
|
||||
if (thread_index >= params->num_threads) {
|
||||
LOG_ERROR("uCOS-III: failed to find thread address");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
*thread_address = params->threads[thread_index];
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
|
||||
{
|
||||
struct uCOS_III_params *params = rtos->rtos_specific_params;
|
||||
int retval;
|
||||
|
||||
/* read the thread list head */
|
||||
symbol_address_t thread_list_address = 0;
|
||||
|
||||
retval = target_read_memory(rtos->target,
|
||||
rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)&thread_list_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read thread list address");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* advance to end of thread list */
|
||||
do {
|
||||
*thread_address = thread_list_address;
|
||||
|
||||
retval = target_read_memory(rtos->target,
|
||||
thread_list_address + params->thread_next_offset,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)&thread_list_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read next thread address");
|
||||
return retval;
|
||||
}
|
||||
} while (thread_list_address != 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int uCOS_III_update_thread_offsets(struct rtos *rtos)
|
||||
{
|
||||
struct uCOS_III_params *params = rtos->rtos_specific_params;
|
||||
|
||||
if (params->thread_offsets_updated)
|
||||
return ERROR_OK;
|
||||
|
||||
const struct thread_offset_map {
|
||||
enum uCOS_III_symbol_values symbol_value;
|
||||
symbol_address_t *thread_offset;
|
||||
} thread_offset_maps[] = {
|
||||
{
|
||||
uCOS_III_VAL_OS_TCB_StkPtr_offset,
|
||||
¶ms->thread_stack_offset,
|
||||
},
|
||||
{
|
||||
uCOS_III_VAL_OS_TCB_NamePtr_offset,
|
||||
¶ms->thread_name_offset,
|
||||
},
|
||||
{
|
||||
uCOS_III_VAL_OS_TCB_TaskState_offset,
|
||||
¶ms->thread_state_offset,
|
||||
},
|
||||
{
|
||||
uCOS_III_VAL_OS_TCB_Prio_offset,
|
||||
¶ms->thread_priority_offset,
|
||||
},
|
||||
{
|
||||
uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
|
||||
¶ms->thread_prev_offset,
|
||||
},
|
||||
{
|
||||
uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
|
||||
¶ms->thread_next_offset,
|
||||
},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) {
|
||||
const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
|
||||
|
||||
int retval = target_read_memory(rtos->target,
|
||||
rtos->symbols[thread_offset_map->symbol_value].address,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)thread_offset_map->thread_offset);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read thread offset");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
params->thread_offsets_updated = true;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int uCOS_III_detect_rtos(struct target *target)
|
||||
{
|
||||
return target->rtos->symbols != NULL &&
|
||||
target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0;
|
||||
}
|
||||
|
||||
static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
|
||||
{
|
||||
struct uCOS_III_params *params = target->rtos->rtos_specific_params;
|
||||
|
||||
params->thread_offsets_updated = false;
|
||||
params->num_threads = 0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int uCOS_III_create(struct target *target)
|
||||
{
|
||||
struct uCOS_III_params *params;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++)
|
||||
if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) {
|
||||
params = malloc(sizeof(*params) +
|
||||
UCOS_III_MAX_THREADS * sizeof(*params->threads));
|
||||
if (params == NULL) {
|
||||
LOG_ERROR("uCOS-III: out of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
memcpy(params, &uCOS_III_params_list[i], sizeof(uCOS_III_params_list[i]));
|
||||
target->rtos->rtos_specific_params = (void *)params;
|
||||
|
||||
target_register_reset_callback(uCOS_III_reset_handler, NULL);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
LOG_ERROR("uCOS-III: target not supported: %s", target->type->name);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int uCOS_III_update_threads(struct rtos *rtos)
|
||||
{
|
||||
struct uCOS_III_params *params = rtos->rtos_specific_params;
|
||||
int retval;
|
||||
|
||||
/* free previous thread details */
|
||||
rtos_free_threadlist(rtos);
|
||||
|
||||
/* verify RTOS is running */
|
||||
uint8_t rtos_running;
|
||||
|
||||
retval = target_read_u8(rtos->target,
|
||||
rtos->symbols[uCOS_III_VAL_OSRunning].address,
|
||||
&rtos_running);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read RTOS running");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!rtos_running) {
|
||||
rtos->thread_details = calloc(1, sizeof(struct thread_detail));
|
||||
if (rtos->thread_details == NULL) {
|
||||
LOG_ERROR("uCOS-III: out of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
rtos->thread_count = 1;
|
||||
rtos->thread_details->threadid = 0;
|
||||
rtos->thread_details->exists = true;
|
||||
rtos->current_thread = 0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* update thread offsets */
|
||||
retval = uCOS_III_update_thread_offsets(rtos);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to update thread offsets");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* read current thread address */
|
||||
symbol_address_t current_thread_address = 0;
|
||||
|
||||
retval = target_read_memory(rtos->target,
|
||||
rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)¤t_thread_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read current thread address");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* read number of tasks */
|
||||
retval = target_read_u16(rtos->target,
|
||||
rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
|
||||
(void *)&rtos->thread_count);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read thread count");
|
||||
return retval;
|
||||
}
|
||||
|
||||
rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
|
||||
if (rtos->thread_details == NULL) {
|
||||
LOG_ERROR("uCOS-III: out of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* uC/OS-III adds tasks in LIFO order; advance to the end of the
|
||||
* list and work backwards to preserve the intended order.
|
||||
*/
|
||||
symbol_address_t thread_address = 0;
|
||||
|
||||
retval = uCOS_III_find_last_thread_address(rtos, &thread_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to find last thread address");
|
||||
return retval;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rtos->thread_count; i++) {
|
||||
struct thread_detail *thread_detail = &rtos->thread_details[i];
|
||||
char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
|
||||
|
||||
/* find or create new threadid */
|
||||
retval = uCOS_III_find_or_create_thread(rtos,
|
||||
thread_address,
|
||||
&thread_detail->threadid);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to find or create thread");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (thread_address == current_thread_address)
|
||||
rtos->current_thread = thread_detail->threadid;
|
||||
|
||||
thread_detail->exists = true;
|
||||
|
||||
/* read thread name */
|
||||
symbol_address_t thread_name_address = 0;
|
||||
|
||||
retval = target_read_memory(rtos->target,
|
||||
thread_address + params->thread_name_offset,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)&thread_name_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to name address");
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = target_read_buffer(rtos->target,
|
||||
thread_name_address,
|
||||
sizeof(thread_str_buffer),
|
||||
(void *)thread_str_buffer);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read thread name");
|
||||
return retval;
|
||||
}
|
||||
|
||||
thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0';
|
||||
thread_detail->thread_name_str = strdup(thread_str_buffer);
|
||||
|
||||
/* read thread extra info */
|
||||
uint8_t thread_state;
|
||||
uint8_t thread_priority;
|
||||
|
||||
retval = target_read_u8(rtos->target,
|
||||
thread_address + params->thread_state_offset,
|
||||
&thread_state);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read thread state");
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = target_read_u8(rtos->target,
|
||||
thread_address + params->thread_priority_offset,
|
||||
&thread_priority);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read thread priority");
|
||||
return retval;
|
||||
}
|
||||
|
||||
const char *thread_state_str;
|
||||
|
||||
if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list))
|
||||
thread_state_str = uCOS_III_thread_state_list[thread_state];
|
||||
else
|
||||
thread_state_str = "Unknown";
|
||||
|
||||
snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d",
|
||||
thread_state_str, thread_priority);
|
||||
thread_detail->extra_info_str = strdup(thread_str_buffer);
|
||||
|
||||
/* read previous thread address */
|
||||
retval = target_read_memory(rtos->target,
|
||||
thread_address + params->thread_prev_offset,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)&thread_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read previous thread address");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, char **hex_reg_list)
|
||||
{
|
||||
struct uCOS_III_params *params = rtos->rtos_specific_params;
|
||||
int retval;
|
||||
|
||||
/* find thread address for threadid */
|
||||
symbol_address_t thread_address = 0;
|
||||
|
||||
retval = uCOS_III_find_thread_address(rtos, threadid, &thread_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to find thread address");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* read thread stack address */
|
||||
symbol_address_t stack_address = 0;
|
||||
|
||||
retval = target_read_memory(rtos->target,
|
||||
thread_address + params->thread_stack_offset,
|
||||
params->pointer_width,
|
||||
1,
|
||||
(void *)&stack_address);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("uCOS-III: failed to read stack address");
|
||||
return retval;
|
||||
}
|
||||
|
||||
return rtos_generic_stack_read(rtos->target,
|
||||
params->stacking_info,
|
||||
stack_address,
|
||||
hex_reg_list);
|
||||
}
|
||||
|
||||
static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
|
||||
{
|
||||
*symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t));
|
||||
if (*symbol_list == NULL) {
|
||||
LOG_ERROR("uCOS-III: out of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_symbol_list); i++)
|
||||
(*symbol_list)[i].symbol_name = uCOS_III_symbol_list[i];
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
const struct rtos_type uCOS_III_rtos = {
|
||||
.name = "uCOS-III",
|
||||
.detect_rtos = uCOS_III_detect_rtos,
|
||||
.create = uCOS_III_create,
|
||||
.update_threads = uCOS_III_update_threads,
|
||||
.get_thread_reg_list = uCOS_III_get_thread_reg_list,
|
||||
.get_symbol_list_to_lookup = uCOS_III_get_symbol_list_to_lookup,
|
||||
};
|
||||
+14
-18
@@ -1,23 +1,19 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
noinst_LTLIBRARIES += %D%/libserver.la
|
||||
%C%_libserver_la_SOURCES = \
|
||||
%D%/server.c \
|
||||
%D%/telnet_server.c \
|
||||
%D%/gdb_server.c \
|
||||
%D%/server.h \
|
||||
%D%/telnet_server.h \
|
||||
%D%/gdb_server.h \
|
||||
%D%/server_stubs.c \
|
||||
%D%/tcl_server.c \
|
||||
%D%/tcl_server.h
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libserver.la
|
||||
noinst_HEADERS = server.h telnet_server.h gdb_server.h
|
||||
libserver_la_SOURCES = server.c telnet_server.c gdb_server.c
|
||||
|
||||
libserver_la_SOURCES += server_stubs.c
|
||||
|
||||
libserver_la_CFLAGS =
|
||||
%C%_libserver_la_CFLAGS = $(AM_CFLAGS)
|
||||
if IS_MINGW
|
||||
# FD_* macros are sloppy with their signs on MinGW32 platform
|
||||
libserver_la_CFLAGS += -Wno-sign-compare
|
||||
%C%_libserver_la_CFLAGS += -Wno-sign-compare
|
||||
endif
|
||||
|
||||
# tcl server addons
|
||||
noinst_HEADERS += tcl_server.h
|
||||
libserver_la_SOURCES += tcl_server.c
|
||||
|
||||
EXTRA_DIST = \
|
||||
startup.tcl
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
STARTUP_TCL_SRCS += %D%/startup.tcl
|
||||
|
||||
+179
-33
@@ -90,6 +90,8 @@ struct gdb_connection {
|
||||
bool attached;
|
||||
/* temporarily used for target description support */
|
||||
struct target_desc_format target_desc;
|
||||
/* temporarily used for thread list support */
|
||||
char *thread_list;
|
||||
};
|
||||
|
||||
#if 0
|
||||
@@ -695,7 +697,8 @@ static int gdb_output_con(struct connection *connection, const char *line)
|
||||
return ERROR_GDB_BUFFER_TOO_SMALL;
|
||||
|
||||
hex_buffer[0] = 'O';
|
||||
int pkt_len = hexify(hex_buffer + 1, line, bin_size, bin_size * 2 + 1);
|
||||
size_t pkt_len = hexify(hex_buffer + 1, (const uint8_t *)line, bin_size,
|
||||
bin_size * 2 + 1);
|
||||
int retval = gdb_put_packet(connection, hex_buffer, pkt_len + 1);
|
||||
|
||||
free(hex_buffer);
|
||||
@@ -732,22 +735,22 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
|
||||
stop_reason[0] = '\0';
|
||||
if (target->debug_reason == DBG_REASON_WATCHPOINT) {
|
||||
enum watchpoint_rw hit_wp_type;
|
||||
uint32_t hit_wp_address;
|
||||
target_addr_t hit_wp_address;
|
||||
|
||||
if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
|
||||
|
||||
switch (hit_wp_type) {
|
||||
case WPT_WRITE:
|
||||
snprintf(stop_reason, sizeof(stop_reason),
|
||||
"watch:%08" PRIx32 ";", hit_wp_address);
|
||||
"watch:%08" TARGET_PRIxADDR ";", hit_wp_address);
|
||||
break;
|
||||
case WPT_READ:
|
||||
snprintf(stop_reason, sizeof(stop_reason),
|
||||
"rwatch:%08" PRIx32 ";", hit_wp_address);
|
||||
"rwatch:%08" TARGET_PRIxADDR ";", hit_wp_address);
|
||||
break;
|
||||
case WPT_ACCESS:
|
||||
snprintf(stop_reason, sizeof(stop_reason),
|
||||
"awatch:%08" PRIx32 ";", hit_wp_address);
|
||||
"awatch:%08" TARGET_PRIxADDR ";", hit_wp_address);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -934,6 +937,7 @@ static int gdb_new_connection(struct connection *connection)
|
||||
gdb_connection->attached = true;
|
||||
gdb_connection->target_desc.tdesc = NULL;
|
||||
gdb_connection->target_desc.tdesc_length = 0;
|
||||
gdb_connection->thread_list = NULL;
|
||||
|
||||
/* send ACK to GDB for debug request */
|
||||
gdb_write(connection, "+", 1);
|
||||
@@ -1376,7 +1380,7 @@ static int gdb_read_memory_packet(struct connection *connection,
|
||||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
char *separator;
|
||||
uint32_t addr = 0;
|
||||
uint64_t addr = 0;
|
||||
uint32_t len = 0;
|
||||
|
||||
uint8_t *buffer;
|
||||
@@ -1387,7 +1391,7 @@ static int gdb_read_memory_packet(struct connection *connection,
|
||||
/* skip command character */
|
||||
packet++;
|
||||
|
||||
addr = strtoul(packet, &separator, 16);
|
||||
addr = strtoull(packet, &separator, 16);
|
||||
|
||||
if (*separator != ',') {
|
||||
LOG_ERROR("incomplete read memory packet received, dropping connection");
|
||||
@@ -1404,7 +1408,7 @@ static int gdb_read_memory_packet(struct connection *connection,
|
||||
|
||||
buffer = malloc(len);
|
||||
|
||||
LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||
LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||
|
||||
retval = target_read_buffer(target, addr, len, buffer);
|
||||
|
||||
@@ -1429,7 +1433,7 @@ static int gdb_read_memory_packet(struct connection *connection,
|
||||
if (retval == ERROR_OK) {
|
||||
hex_buffer = malloc(len * 2 + 1);
|
||||
|
||||
int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1);
|
||||
size_t pkt_len = hexify(hex_buffer, buffer, len, len * 2 + 1);
|
||||
|
||||
gdb_put_packet(connection, hex_buffer, pkt_len);
|
||||
|
||||
@@ -1447,7 +1451,7 @@ static int gdb_write_memory_packet(struct connection *connection,
|
||||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
char *separator;
|
||||
uint32_t addr = 0;
|
||||
uint64_t addr = 0;
|
||||
uint32_t len = 0;
|
||||
|
||||
uint8_t *buffer;
|
||||
@@ -1456,7 +1460,7 @@ static int gdb_write_memory_packet(struct connection *connection,
|
||||
/* skip command character */
|
||||
packet++;
|
||||
|
||||
addr = strtoul(packet, &separator, 16);
|
||||
addr = strtoull(packet, &separator, 16);
|
||||
|
||||
if (*separator != ',') {
|
||||
LOG_ERROR("incomplete write memory packet received, dropping connection");
|
||||
@@ -1472,9 +1476,9 @@ static int gdb_write_memory_packet(struct connection *connection,
|
||||
|
||||
buffer = malloc(len);
|
||||
|
||||
LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||
LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||
|
||||
if (unhexify((char *)buffer, separator, len) != (int)len)
|
||||
if (unhexify(buffer, separator, len) != len)
|
||||
LOG_ERROR("unable to decode memory packet");
|
||||
|
||||
retval = target_write_buffer(target, addr, len, buffer);
|
||||
@@ -1494,15 +1498,19 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
|
||||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
char *separator;
|
||||
uint32_t addr = 0;
|
||||
uint64_t addr = 0;
|
||||
uint32_t len = 0;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
/* Packets larger than fast_limit bytes will be acknowledged instantly on
|
||||
* the assumption that we're in a download and it's important to go as fast
|
||||
* as possible. */
|
||||
uint32_t fast_limit = 8;
|
||||
|
||||
/* skip command character */
|
||||
packet++;
|
||||
|
||||
addr = strtoul(packet, &separator, 16);
|
||||
addr = strtoull(packet, &separator, 16);
|
||||
|
||||
if (*separator != ',') {
|
||||
LOG_ERROR("incomplete write memory binary packet received, dropping connection");
|
||||
@@ -1518,31 +1526,44 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
|
||||
|
||||
struct gdb_connection *gdb_connection = connection->priv;
|
||||
|
||||
if (gdb_connection->mem_write_error) {
|
||||
if (gdb_connection->mem_write_error)
|
||||
retval = ERROR_FAIL;
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
if (len >= fast_limit) {
|
||||
/* By replying the packet *immediately* GDB will send us a new packet
|
||||
* while we write the last one to the target.
|
||||
* We only do this for larger writes, so that users who do something like:
|
||||
* p *((int*)0xdeadbeef)=8675309
|
||||
* will get immediate feedback that that write failed.
|
||||
*/
|
||||
gdb_put_packet(connection, "OK", 2);
|
||||
}
|
||||
} else {
|
||||
retval = gdb_error(connection, retval);
|
||||
/* now that we have reported the memory write error, we can clear the condition */
|
||||
gdb_connection->mem_write_error = false;
|
||||
}
|
||||
|
||||
/* By replying the packet *immediately* GDB will send us a new packet
|
||||
* while we write the last one to the target.
|
||||
*/
|
||||
if (retval == ERROR_OK)
|
||||
gdb_put_packet(connection, "OK", 2);
|
||||
else {
|
||||
retval = gdb_error(connection, retval);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||
LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||
|
||||
retval = target_write_buffer(target, addr, len, (uint8_t *)separator);
|
||||
if (retval != ERROR_OK)
|
||||
gdb_connection->mem_write_error = true;
|
||||
}
|
||||
|
||||
if (len < fast_limit) {
|
||||
if (retval != ERROR_OK) {
|
||||
gdb_error(connection, retval);
|
||||
gdb_connection->mem_write_error = false;
|
||||
} else {
|
||||
gdb_put_packet(connection, "OK", 2);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1551,13 +1572,13 @@ static int gdb_step_continue_packet(struct connection *connection,
|
||||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
int current = 0;
|
||||
uint32_t address = 0x0;
|
||||
uint64_t address = 0x0;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
LOG_DEBUG("-");
|
||||
|
||||
if (packet_size > 1)
|
||||
address = strtoul(packet + 1, NULL, 16);
|
||||
address = strtoull(packet + 1, NULL, 16);
|
||||
else
|
||||
current = 1;
|
||||
|
||||
@@ -1581,7 +1602,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
|
||||
int type;
|
||||
enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;
|
||||
enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */;
|
||||
uint32_t address;
|
||||
uint64_t address;
|
||||
uint32_t size;
|
||||
char *separator;
|
||||
int retval;
|
||||
@@ -1613,7 +1634,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
|
||||
return ERROR_SERVER_REMOTE_CLOSED;
|
||||
}
|
||||
|
||||
address = strtoul(separator + 1, &separator, 16);
|
||||
address = strtoull(separator + 1, &separator, 16);
|
||||
|
||||
if (*separator != ',') {
|
||||
LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
|
||||
@@ -2291,6 +2312,95 @@ error:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int gdb_generate_thread_list(struct target *target, char **thread_list_out)
|
||||
{
|
||||
struct rtos *rtos = target->rtos;
|
||||
int retval = ERROR_OK;
|
||||
char *thread_list = NULL;
|
||||
int pos = 0;
|
||||
int size = 0;
|
||||
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"<?xml version=\"1.0\"?>\n"
|
||||
"<threads>\n");
|
||||
|
||||
if (rtos != NULL) {
|
||||
for (int i = 0; i < rtos->thread_count; i++) {
|
||||
struct thread_detail *thread_detail = &rtos->thread_details[i];
|
||||
|
||||
if (!thread_detail->exists)
|
||||
continue;
|
||||
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
|
||||
|
||||
if (thread_detail->thread_name_str != NULL)
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"Name: %s", thread_detail->thread_name_str);
|
||||
|
||||
if (thread_detail->extra_info_str != NULL) {
|
||||
if (thread_detail->thread_name_str != NULL)
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
", ");
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
thread_detail->extra_info_str);
|
||||
}
|
||||
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"</thread>\n");
|
||||
}
|
||||
}
|
||||
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"</threads>\n");
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*thread_list_out = thread_list;
|
||||
else
|
||||
free(thread_list);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
|
||||
char **chunk, int32_t offset, uint32_t length)
|
||||
{
|
||||
if (*thread_list == NULL) {
|
||||
int retval = gdb_generate_thread_list(target, thread_list);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Unable to Generate Thread List");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t thread_list_length = strlen(*thread_list);
|
||||
char transfer_type;
|
||||
|
||||
length = MIN(length, thread_list_length - offset);
|
||||
if (length < (thread_list_length - offset))
|
||||
transfer_type = 'm';
|
||||
else
|
||||
transfer_type = 'l';
|
||||
|
||||
*chunk = malloc(length + 2);
|
||||
if (*chunk == NULL) {
|
||||
LOG_ERROR("Unable to allocate memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
(*chunk)[0] = transfer_type;
|
||||
strncpy((*chunk) + 1, (*thread_list) + offset, length);
|
||||
(*chunk)[1 + length] = '\0';
|
||||
|
||||
/* After gdb-server sends out last chunk, invalidate thread list. */
|
||||
if (transfer_type == 'l') {
|
||||
free(*thread_list);
|
||||
*thread_list = NULL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int gdb_query_packet(struct connection *connection,
|
||||
char const *packet, int packet_size)
|
||||
{
|
||||
@@ -2302,7 +2412,7 @@ static int gdb_query_packet(struct connection *connection,
|
||||
if (packet_size > 6) {
|
||||
char *cmd;
|
||||
cmd = malloc((packet_size - 6) / 2 + 1);
|
||||
int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2);
|
||||
size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2);
|
||||
cmd[len] = 0;
|
||||
|
||||
/* We want to print all debug output to GDB connection */
|
||||
@@ -2380,7 +2490,7 @@ static int gdb_query_packet(struct connection *connection,
|
||||
&buffer,
|
||||
&pos,
|
||||
&size,
|
||||
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;QStartNoAckMode+",
|
||||
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+",
|
||||
(GDB_BUFFER_SIZE - 1),
|
||||
((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
|
||||
(gdb_target_desc_supported == 1) ? '+' : '-');
|
||||
@@ -2426,6 +2536,37 @@ static int gdb_query_packet(struct connection *connection,
|
||||
|
||||
gdb_put_packet(connection, xml, strlen(xml));
|
||||
|
||||
free(xml);
|
||||
return ERROR_OK;
|
||||
} else if (strncmp(packet, "qXfer:threads:read:", 19) == 0) {
|
||||
char *xml = NULL;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
int offset;
|
||||
unsigned int length;
|
||||
|
||||
/* skip command character */
|
||||
packet += 19;
|
||||
|
||||
if (decode_xfer_read(packet, NULL, &offset, &length) < 0) {
|
||||
gdb_send_error(connection, 01);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* Target should prepare correct thread list for annex.
|
||||
* The first character of returned xml is 'm' or 'l'. 'm' for
|
||||
* there are *more* chunks to transfer. 'l' for it is the *last*
|
||||
* chunk of target description.
|
||||
*/
|
||||
retval = gdb_get_thread_list_chunk(target, &gdb_connection->thread_list,
|
||||
&xml, offset, length);
|
||||
if (retval != ERROR_OK) {
|
||||
gdb_error(connection, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
gdb_put_packet(connection, xml, strlen(xml));
|
||||
|
||||
free(xml);
|
||||
return ERROR_OK;
|
||||
} else if (strncmp(packet, "QStartNoAckMode", 15) == 0) {
|
||||
@@ -2953,6 +3094,11 @@ static int gdb_target_start(struct target *target, const char *port)
|
||||
|
||||
static int gdb_target_add_one(struct target *target)
|
||||
{
|
||||
if (strcmp(gdb_port, "disabled") == 0) {
|
||||
LOG_INFO("gdb port disabled");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* one gdb instance per smp list */
|
||||
if ((target->smp) && (target->gdb_service))
|
||||
return ERROR_OK;
|
||||
@@ -3146,7 +3292,7 @@ static const struct command_registration gdb_command_handlers[] = {
|
||||
"server listens for the next port number after the "
|
||||
"base port number specified. "
|
||||
"No arguments reports GDB port. \"pipe\" means listen to stdin "
|
||||
"output to stdout, an integer is base port number, \"disable\" disables "
|
||||
"output to stdout, an integer is base port number, \"disabled\" disables "
|
||||
"port. Any other string is are interpreted as named pipe to listen to. "
|
||||
"Output pipe is the same name as input pipe, but with 'o' appended.",
|
||||
.usage = "[port_num]",
|
||||
|
||||
+38
-13
@@ -132,7 +132,9 @@ static int add_connection(struct service *service, struct command_context *cmd_c
|
||||
free(out_file);
|
||||
if (c->fd_out == -1) {
|
||||
LOG_ERROR("could not open %s", service->port);
|
||||
exit(1);
|
||||
command_done(c->cmd_ctx);
|
||||
free(c);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port);
|
||||
@@ -191,7 +193,13 @@ static int remove_connection(struct service *service, struct connection *connect
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* FIX! make service return error instead of invoking exit() */
|
||||
static void free_service(struct service *c)
|
||||
{
|
||||
free(c->name);
|
||||
free(c->port);
|
||||
free(c);
|
||||
}
|
||||
|
||||
int add_service(char *name,
|
||||
const char *port,
|
||||
int max_connections,
|
||||
@@ -235,7 +243,8 @@ int add_service(char *name,
|
||||
c->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (c->fd == -1) {
|
||||
LOG_ERROR("error creating socket: %s", strerror(errno));
|
||||
exit(-1);
|
||||
free_service(c);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
setsockopt(c->fd,
|
||||
@@ -255,7 +264,9 @@ int add_service(char *name,
|
||||
hp = gethostbyname(bindto_name);
|
||||
if (hp == NULL) {
|
||||
LOG_ERROR("couldn't resolve bindto address: %s", bindto_name);
|
||||
exit(-1);
|
||||
close_socket(c->fd);
|
||||
free_service(c);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length);
|
||||
}
|
||||
@@ -263,7 +274,9 @@ int add_service(char *name,
|
||||
|
||||
if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) {
|
||||
LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno));
|
||||
exit(-1);
|
||||
close_socket(c->fd);
|
||||
free_service(c);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -281,7 +294,9 @@ int add_service(char *name,
|
||||
|
||||
if (listen(c->fd, 1) == -1) {
|
||||
LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
|
||||
exit(-1);
|
||||
close_socket(c->fd);
|
||||
free_service(c);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else if (c->type == CONNECTION_STDINOUT) {
|
||||
c->fd = fileno(stdin);
|
||||
@@ -302,13 +317,15 @@ int add_service(char *name,
|
||||
/* we currenty do not support named pipes under win32
|
||||
* so exit openocd for now */
|
||||
LOG_ERROR("Named pipes currently not supported under this os");
|
||||
exit(1);
|
||||
free_service(c);
|
||||
return ERROR_FAIL;
|
||||
#else
|
||||
/* Pipe we're reading from */
|
||||
c->fd = open(c->port, O_RDONLY | O_NONBLOCK);
|
||||
if (c->fd == -1) {
|
||||
LOG_ERROR("could not open %s", c->port);
|
||||
exit(1);
|
||||
free_service(c);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -425,7 +442,7 @@ int server_loop(struct command_context *command_context)
|
||||
FD_ZERO(&read_fds);
|
||||
else {
|
||||
LOG_ERROR("error during select: %s", strerror(errno));
|
||||
exit(-1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -433,7 +450,7 @@ int server_loop(struct command_context *command_context)
|
||||
FD_ZERO(&read_fds);
|
||||
else {
|
||||
LOG_ERROR("error during select: %s", strerror(errno));
|
||||
exit(-1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -552,7 +569,7 @@ int server_preinit(void)
|
||||
|
||||
if (WSAStartup(wVersionRequested, &wsaData) != 0) {
|
||||
LOG_ERROR("Failed to Open Winsock");
|
||||
exit(-1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* register ctrl-c handler */
|
||||
@@ -570,10 +587,18 @@ int server_preinit(void)
|
||||
int server_init(struct command_context *cmd_ctx)
|
||||
{
|
||||
int ret = tcl_init();
|
||||
if (ERROR_OK != ret)
|
||||
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
return telnet_init("Open On-Chip Debugger");
|
||||
ret = telnet_init("Open On-Chip Debugger");
|
||||
|
||||
if (ret != ERROR_OK) {
|
||||
remove_services();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int server_quit(void)
|
||||
|
||||
@@ -105,7 +105,7 @@ static int tcl_target_callback_trace_handler(struct target *target,
|
||||
if (tclc->tc_trace) {
|
||||
hex = malloc(hex_len);
|
||||
buf = malloc(max_len);
|
||||
hexify(hex, (const char *)data, len, hex_len);
|
||||
hexify(hex, data, len, hex_len);
|
||||
snprintf(buf, max_len, "%s%s%s", header, hex, trailer);
|
||||
tcl_output(connection, buf, strlen(buf));
|
||||
free(hex);
|
||||
|
||||
+12
-10
@@ -573,7 +573,7 @@ static int telnet_input(struct connection *connection)
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("unknown telnet state");
|
||||
exit(-1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
bytes_read--;
|
||||
@@ -624,9 +624,8 @@ int telnet_init(char *banner)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct telnet_service *telnet_service;
|
||||
|
||||
telnet_service = malloc(sizeof(struct telnet_service));
|
||||
struct telnet_service *telnet_service =
|
||||
malloc(sizeof(struct telnet_service));
|
||||
|
||||
if (!telnet_service) {
|
||||
LOG_ERROR("Failed to allocate telnet service.");
|
||||
@@ -635,13 +634,16 @@ int telnet_init(char *banner)
|
||||
|
||||
telnet_service->banner = banner;
|
||||
|
||||
return add_service("telnet",
|
||||
telnet_port,
|
||||
CONNECTION_LIMIT_UNLIMITED,
|
||||
telnet_new_connection,
|
||||
telnet_input,
|
||||
telnet_connection_closed,
|
||||
int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED,
|
||||
telnet_new_connection, telnet_input, telnet_connection_closed,
|
||||
telnet_service);
|
||||
|
||||
if (ret != ERROR_OK) {
|
||||
free(telnet_service);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* daemon configuration command telnet_port */
|
||||
|
||||
+2
-8
@@ -1,8 +1,2 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libsvf.la
|
||||
noinst_HEADERS = svf.h
|
||||
libsvf_la_SOURCES = svf.c
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
noinst_LTLIBRARIES += %D%/libsvf.la
|
||||
%C%_libsvf_la_SOURCES = %D%/svf.c %D%/svf.h
|
||||
|
||||
+174
-175
@@ -1,31 +1,15 @@
|
||||
include $(top_srcdir)/common.mk
|
||||
|
||||
if OOCD_TRACE
|
||||
OOCD_TRACE_FILES = oocd_trace.c
|
||||
OOCD_TRACE_FILES = %D%/oocd_trace.c
|
||||
else
|
||||
OOCD_TRACE_FILES =
|
||||
endif
|
||||
|
||||
SUBDIRS = openrisc
|
||||
libtarget_la_LIBADD = $(top_builddir)/src/target/openrisc/libopenrisc.la
|
||||
%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la
|
||||
|
||||
BIN2C = $(top_srcdir)/src/helper/bin2char.sh
|
||||
STARTUP_TCL_SRCS += %D%/startup.tcl
|
||||
|
||||
DEBUG_HANDLER = $(srcdir)/xscale/debug_handler.bin
|
||||
EXTRA_DIST = \
|
||||
startup.tcl \
|
||||
$(wildcard $(srcdir)/xscale/*)
|
||||
|
||||
DEBUG_HEADER = xscale_debug.inc
|
||||
BUILT_SOURCES = $(DEBUG_HEADER)
|
||||
CLEANFILES = $(DEBUG_HEADER)
|
||||
|
||||
$(DEBUG_HEADER): $(DEBUG_HANDLER) $(BIN2C)
|
||||
$(BIN2C) < $< > $@ || { rm -f $@; false; }
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libtarget.la
|
||||
libtarget_la_SOURCES = \
|
||||
noinst_LTLIBRARIES += %D%/libtarget.la
|
||||
%C%_libtarget_la_SOURCES = \
|
||||
$(TARGET_CORE_SRC) \
|
||||
$(ARM_DEBUG_SRC) \
|
||||
$(ARMV4_5_SRC) \
|
||||
@@ -37,185 +21,200 @@ libtarget_la_SOURCES = \
|
||||
$(NDS32_SRC) \
|
||||
$(INTEL_IA32_SRC) \
|
||||
$(RISCV_SRC) \
|
||||
avrt.c \
|
||||
dsp563xx.c \
|
||||
dsp563xx_once.c \
|
||||
dsp5680xx.c \
|
||||
hla_target.c
|
||||
%D%/avrt.c \
|
||||
%D%/dsp563xx.c \
|
||||
%D%/dsp563xx_once.c \
|
||||
%D%/dsp5680xx.c \
|
||||
%D%/hla_target.c
|
||||
|
||||
if TARGET64
|
||||
%C%_libtarget_la_SOURCES +=$(ARMV8_SRC)
|
||||
endif
|
||||
|
||||
TARGET_CORE_SRC = \
|
||||
algorithm.c \
|
||||
register.c \
|
||||
image.c \
|
||||
breakpoints.c \
|
||||
target.c \
|
||||
target_request.c \
|
||||
testee.c \
|
||||
smp.c
|
||||
%D%/algorithm.c \
|
||||
%D%/register.c \
|
||||
%D%/image.c \
|
||||
%D%/breakpoints.c \
|
||||
%D%/target.c \
|
||||
%D%/target_request.c \
|
||||
%D%/testee.c \
|
||||
%D%/smp.c
|
||||
|
||||
ARMV4_5_SRC = \
|
||||
armv4_5.c \
|
||||
armv4_5_mmu.c \
|
||||
armv4_5_cache.c \
|
||||
%D%/armv4_5.c \
|
||||
%D%/armv4_5_mmu.c \
|
||||
%D%/armv4_5_cache.c \
|
||||
$(ARM7_9_SRC)
|
||||
|
||||
ARM7_9_SRC = \
|
||||
arm7_9_common.c \
|
||||
arm7tdmi.c \
|
||||
arm720t.c \
|
||||
arm9tdmi.c \
|
||||
arm920t.c \
|
||||
arm966e.c \
|
||||
arm946e.c \
|
||||
arm926ejs.c \
|
||||
feroceon.c
|
||||
%D%/arm7_9_common.c \
|
||||
%D%/arm7tdmi.c \
|
||||
%D%/arm720t.c \
|
||||
%D%/arm9tdmi.c \
|
||||
%D%/arm920t.c \
|
||||
%D%/arm966e.c \
|
||||
%D%/arm946e.c \
|
||||
%D%/arm926ejs.c \
|
||||
%D%/feroceon.c
|
||||
|
||||
ARM_MISC_SRC = \
|
||||
fa526.c \
|
||||
xscale.c
|
||||
%D%/fa526.c \
|
||||
%D%/xscale.c
|
||||
|
||||
ARMV6_SRC = \
|
||||
arm11.c \
|
||||
arm11_dbgtap.c
|
||||
%D%/arm11.c \
|
||||
%D%/arm11_dbgtap.c
|
||||
|
||||
ARMV7_SRC = \
|
||||
armv7m.c \
|
||||
armv7m_trace.c \
|
||||
cortex_m.c \
|
||||
armv7a.c \
|
||||
cortex_a.c \
|
||||
ls1_sap.c
|
||||
%D%/armv7m.c \
|
||||
%D%/armv7m_trace.c \
|
||||
%D%/cortex_m.c \
|
||||
%D%/armv7a.c \
|
||||
%D%/cortex_a.c \
|
||||
%D%/ls1_sap.c
|
||||
|
||||
ARMV8_SRC = \
|
||||
%D%/armv8_dpm.c \
|
||||
%D%/armv8_opcodes.c \
|
||||
%D%/aarch64.c \
|
||||
%D%/armv8.c \
|
||||
%D%/armv8_cache.c
|
||||
|
||||
ARM_DEBUG_SRC = \
|
||||
arm_dpm.c \
|
||||
arm_jtag.c \
|
||||
arm_disassembler.c \
|
||||
arm_simulator.c \
|
||||
arm_semihosting.c \
|
||||
arm_adi_v5.c \
|
||||
armv7a_cache.c \
|
||||
armv7a_cache_l2x.c \
|
||||
adi_v5_jtag.c \
|
||||
adi_v5_swd.c \
|
||||
embeddedice.c \
|
||||
trace.c \
|
||||
etb.c \
|
||||
etm.c \
|
||||
%D%/arm_dpm.c \
|
||||
%D%/arm_jtag.c \
|
||||
%D%/arm_disassembler.c \
|
||||
%D%/arm_simulator.c \
|
||||
%D%/arm_semihosting.c \
|
||||
%D%/arm_adi_v5.c \
|
||||
%D%/armv7a_cache.c \
|
||||
%D%/armv7a_cache_l2x.c \
|
||||
%D%/adi_v5_jtag.c \
|
||||
%D%/adi_v5_swd.c \
|
||||
%D%/embeddedice.c \
|
||||
%D%/trace.c \
|
||||
%D%/etb.c \
|
||||
%D%/etm.c \
|
||||
$(OOCD_TRACE_FILES) \
|
||||
etm_dummy.c
|
||||
%D%/etm_dummy.c \
|
||||
%D%/arm_cti.c
|
||||
|
||||
AVR32_SRC = \
|
||||
avr32_ap7k.c \
|
||||
avr32_jtag.c \
|
||||
avr32_mem.c \
|
||||
avr32_regs.c
|
||||
%D%/avr32_ap7k.c \
|
||||
%D%/avr32_jtag.c \
|
||||
%D%/avr32_mem.c \
|
||||
%D%/avr32_regs.c
|
||||
|
||||
MIPS32_SRC = \
|
||||
mips32.c \
|
||||
mips_m4k.c \
|
||||
mips32_pracc.c \
|
||||
mips32_dmaacc.c \
|
||||
mips_ejtag.c
|
||||
%D%/mips32.c \
|
||||
%D%/mips_m4k.c \
|
||||
%D%/mips32_pracc.c \
|
||||
%D%/mips32_dmaacc.c \
|
||||
%D%/mips_ejtag.c
|
||||
|
||||
NDS32_SRC = \
|
||||
nds32.c \
|
||||
nds32_reg.c \
|
||||
nds32_cmd.c \
|
||||
nds32_disassembler.c \
|
||||
nds32_tlb.c \
|
||||
nds32_v2.c \
|
||||
nds32_v3_common.c \
|
||||
nds32_v3.c \
|
||||
nds32_v3m.c \
|
||||
nds32_aice.c
|
||||
%D%/nds32.c \
|
||||
%D%/nds32_reg.c \
|
||||
%D%/nds32_cmd.c \
|
||||
%D%/nds32_disassembler.c \
|
||||
%D%/nds32_tlb.c \
|
||||
%D%/nds32_v2.c \
|
||||
%D%/nds32_v3_common.c \
|
||||
%D%/nds32_v3.c \
|
||||
%D%/nds32_v3m.c \
|
||||
%D%/nds32_aice.c
|
||||
|
||||
INTEL_IA32_SRC = \
|
||||
quark_x10xx.c \
|
||||
quark_d20xx.c \
|
||||
lakemont.c \
|
||||
x86_32_common.c
|
||||
%D%/quark_x10xx.c \
|
||||
%D%/quark_d20xx.c \
|
||||
%D%/lakemont.c \
|
||||
%D%/x86_32_common.c
|
||||
|
||||
RISCV_SRC = \
|
||||
riscv/riscv-011.c \
|
||||
riscv/riscv-013.c \
|
||||
riscv/riscv.c \
|
||||
riscv/program.c \
|
||||
riscv/batch.c
|
||||
%D%/riscv/riscv-011.c \
|
||||
%D%/riscv/riscv-013.c \
|
||||
%D%/riscv/riscv.c \
|
||||
%D%/riscv/program.c \
|
||||
%D%/riscv/batch.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
algorithm.h \
|
||||
arm.h \
|
||||
arm_dpm.h \
|
||||
arm_jtag.h \
|
||||
arm_adi_v5.h \
|
||||
armv7a_cache.h \
|
||||
armv7a_cache_l2x.h \
|
||||
arm_disassembler.h \
|
||||
arm_opcodes.h \
|
||||
arm_simulator.h \
|
||||
arm_semihosting.h \
|
||||
arm7_9_common.h \
|
||||
arm7tdmi.h \
|
||||
arm720t.h \
|
||||
arm9tdmi.h \
|
||||
arm920t.h \
|
||||
arm926ejs.h \
|
||||
arm966e.h \
|
||||
arm946e.h \
|
||||
arm11.h \
|
||||
arm11_dbgtap.h \
|
||||
armv4_5.h \
|
||||
armv4_5_mmu.h \
|
||||
armv4_5_cache.h \
|
||||
armv7a.h \
|
||||
armv7m.h \
|
||||
armv7m_trace.h \
|
||||
avrt.h \
|
||||
dsp563xx.h \
|
||||
dsp563xx_once.h \
|
||||
dsp5680xx.h \
|
||||
breakpoints.h \
|
||||
cortex_m.h \
|
||||
cortex_a.h \
|
||||
embeddedice.h \
|
||||
etb.h \
|
||||
etm.h \
|
||||
etm_dummy.h \
|
||||
image.h \
|
||||
mips32.h \
|
||||
mips_m4k.h \
|
||||
mips_ejtag.h \
|
||||
mips32_pracc.h \
|
||||
mips32_dmaacc.h \
|
||||
oocd_trace.h \
|
||||
register.h \
|
||||
target.h \
|
||||
target_type.h \
|
||||
trace.h \
|
||||
target_request.h \
|
||||
trace.h \
|
||||
xscale.h \
|
||||
smp.h \
|
||||
avr32_ap7k.h \
|
||||
avr32_jtag.h \
|
||||
avr32_mem.h \
|
||||
avr32_regs.h \
|
||||
nds32.h \
|
||||
nds32_cmd.h \
|
||||
nds32_disassembler.h \
|
||||
nds32_edm.h \
|
||||
nds32_insn.h \
|
||||
nds32_reg.h \
|
||||
nds32_tlb.h \
|
||||
nds32_v2.h \
|
||||
nds32_v3_common.h \
|
||||
nds32_v3.h \
|
||||
nds32_v3m.h \
|
||||
nds32_aice.h \
|
||||
lakemont.h \
|
||||
x86_32_common.h
|
||||
%C%_libtarget_la_SOURCES += \
|
||||
%D%/algorithm.h \
|
||||
%D%/arm.h \
|
||||
%D%/arm_dpm.h \
|
||||
%D%/arm_jtag.h \
|
||||
%D%/arm_adi_v5.h \
|
||||
%D%/armv7a_cache.h \
|
||||
%D%/armv7a_cache_l2x.h \
|
||||
%D%/arm_disassembler.h \
|
||||
%D%/arm_opcodes.h \
|
||||
%D%/arm_simulator.h \
|
||||
%D%/arm_semihosting.h \
|
||||
%D%/arm7_9_common.h \
|
||||
%D%/arm7tdmi.h \
|
||||
%D%/arm720t.h \
|
||||
%D%/arm9tdmi.h \
|
||||
%D%/arm920t.h \
|
||||
%D%/arm926ejs.h \
|
||||
%D%/arm966e.h \
|
||||
%D%/arm946e.h \
|
||||
%D%/arm11.h \
|
||||
%D%/arm11_dbgtap.h \
|
||||
%D%/armv4_5.h \
|
||||
%D%/armv4_5_mmu.h \
|
||||
%D%/armv4_5_cache.h \
|
||||
%D%/armv7a.h \
|
||||
%D%/armv7m.h \
|
||||
%D%/armv7m_trace.h \
|
||||
%D%/armv8.h \
|
||||
%D%/armv8_dpm.h \
|
||||
%D%/armv8_opcodes.h \
|
||||
%D%/armv8_cache.h \
|
||||
%D%/avrt.h \
|
||||
%D%/dsp563xx.h \
|
||||
%D%/dsp563xx_once.h \
|
||||
%D%/dsp5680xx.h \
|
||||
%D%/breakpoints.h \
|
||||
%D%/cortex_m.h \
|
||||
%D%/cortex_a.h \
|
||||
%D%/aarch64.h \
|
||||
%D%/embeddedice.h \
|
||||
%D%/etb.h \
|
||||
%D%/etm.h \
|
||||
%D%/etm_dummy.h \
|
||||
%D%/image.h \
|
||||
%D%/mips32.h \
|
||||
%D%/mips_m4k.h \
|
||||
%D%/mips_ejtag.h \
|
||||
%D%/mips32_pracc.h \
|
||||
%D%/mips32_dmaacc.h \
|
||||
%D%/oocd_trace.h \
|
||||
%D%/register.h \
|
||||
%D%/target.h \
|
||||
%D%/target_type.h \
|
||||
%D%/trace.h \
|
||||
%D%/target_request.h \
|
||||
%D%/trace.h \
|
||||
%D%/xscale.h \
|
||||
%D%/smp.h \
|
||||
%D%/avr32_ap7k.h \
|
||||
%D%/avr32_jtag.h \
|
||||
%D%/avr32_mem.h \
|
||||
%D%/avr32_regs.h \
|
||||
%D%/nds32.h \
|
||||
%D%/nds32_cmd.h \
|
||||
%D%/nds32_disassembler.h \
|
||||
%D%/nds32_edm.h \
|
||||
%D%/nds32_insn.h \
|
||||
%D%/nds32_reg.h \
|
||||
%D%/nds32_tlb.h \
|
||||
%D%/nds32_v2.h \
|
||||
%D%/nds32_v3_common.h \
|
||||
%D%/nds32_v3.h \
|
||||
%D%/nds32_v3m.h \
|
||||
%D%/nds32_aice.h \
|
||||
%D%/lakemont.h \
|
||||
%D%/x86_32_common.h \
|
||||
%D%/arm_cti.h
|
||||
|
||||
ocddatadir = $(pkglibdir)
|
||||
nobase_dist_ocddata_DATA =
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
include %D%/openrisc/Makefile.am
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2015 by David Ung *
|
||||
* *
|
||||
* 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., *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_AARCH64_H
|
||||
#define OPENOCD_TARGET_AARCH64_H
|
||||
|
||||
#include "armv8.h"
|
||||
|
||||
#define AARCH64_COMMON_MAGIC 0x411fc082
|
||||
|
||||
#define CPUDBG_CPUID 0xD00
|
||||
#define CPUDBG_CTYPR 0xD04
|
||||
#define CPUDBG_TTYPR 0xD0C
|
||||
#define ID_AA64PFR0_EL1 0xD20
|
||||
#define ID_AA64DFR0_EL1 0xD28
|
||||
#define CPUDBG_LOCKACCESS 0xFB0
|
||||
#define CPUDBG_LOCKSTATUS 0xFB4
|
||||
|
||||
#define BRP_NORMAL 0
|
||||
#define BRP_CONTEXT 1
|
||||
|
||||
#define AARCH64_PADDRDBG_CPU_SHIFT 13
|
||||
|
||||
struct aarch64_brp {
|
||||
int used;
|
||||
int type;
|
||||
target_addr_t value;
|
||||
uint32_t control;
|
||||
uint8_t BRPn;
|
||||
};
|
||||
|
||||
struct aarch64_common {
|
||||
int common_magic;
|
||||
|
||||
/* Context information */
|
||||
uint32_t system_control_reg;
|
||||
uint32_t system_control_reg_curr;
|
||||
|
||||
/* Breakpoint register pairs */
|
||||
int brp_num_context;
|
||||
int brp_num;
|
||||
int brp_num_available;
|
||||
struct aarch64_brp *brp_list;
|
||||
|
||||
struct armv8_common armv8_common;
|
||||
};
|
||||
|
||||
static inline struct aarch64_common *
|
||||
target_to_aarch64(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info, struct aarch64_common, armv8_common.arm);
|
||||
}
|
||||
|
||||
#endif /* OPENOCD_TARGET_AARCH64_H */
|
||||
@@ -574,8 +574,6 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
|
||||
if ((ctrlstat & (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) !=
|
||||
(CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) {
|
||||
LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened");
|
||||
retval = ERROR_JTAG_DEVICE_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ctrlstat & SSTICKYERR)
|
||||
@@ -590,10 +588,7 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
|
||||
if (ctrlstat & SSTICKYERR) {
|
||||
retval = ERROR_JTAG_DEVICE_ERROR;
|
||||
goto done;
|
||||
}
|
||||
retval = ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -26,7 +26,7 @@ enum param_direction {
|
||||
};
|
||||
|
||||
struct mem_param {
|
||||
uint32_t address;
|
||||
target_addr_t address;
|
||||
uint32_t size;
|
||||
uint8_t *value;
|
||||
enum param_direction direction;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user