aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac86
-rw-r--r--doc/openocd.texi83
-rw-r--r--src/Makefile.am5
-rw-r--r--src/flash/nor/Makefile.am1
-rw-r--r--src/flash/nor/driver.h1
-rw-r--r--src/flash/nor/drivers.c1
-rw-r--r--src/flash/nor/mspm0.c1131
-rw-r--r--src/flash/nor/stm32l4x.c23
-rw-r--r--src/flash/nor/stm32l4x.h1
-rw-r--r--src/helper/command.c80
-rw-r--r--src/helper/log.h3
-rw-r--r--src/jtag/adapter.c41
-rw-r--r--src/jtag/drivers/bcm2835gpio.c20
-rw-r--r--src/rtos/linux.c28
-rw-r--r--src/rtos/rtos.c4
-rw-r--r--src/rtt/rtt.c4
-rw-r--r--src/target/aarch64.c8
-rw-r--r--src/target/arm_adi_v5.c4
-rw-r--r--src/target/armv7a.c16
-rw-r--r--src/target/armv8.c3
-rw-r--r--src/target/armv8.h1
-rw-r--r--src/target/armv8_cache.c63
-rw-r--r--src/target/armv8_opcodes.c2
-rw-r--r--src/target/armv8_opcodes.h3
-rw-r--r--src/target/cortex_a.c11
-rw-r--r--src/target/espressif/esp32_apptrace.c2
-rw-r--r--src/target/espressif/esp_xtensa_apptrace.c2
-rw-r--r--src/target/target.c274
-rw-r--r--src/target/target.h9
-rw-r--r--src/transport/transport.c48
-rw-r--r--src/transport/transport.h2
-rw-r--r--tcl/board/ti_am261_launchpad.cfg25
-rw-r--r--tcl/board/ti_am263p_launchpad.cfg25
-rw-r--r--tcl/board/ti_am62levm.cfg25
-rw-r--r--tcl/board/ti_mspm0_launchpad.cfg14
-rw-r--r--tcl/target/ngultra.cfg5
-rw-r--r--tcl/target/nordic/nrf54l.cfg23
-rw-r--r--tcl/target/renesas_rcar_gen3.cfg29
-rw-r--r--tcl/target/ti_k3.cfg43
-rw-r--r--tcl/target/ti_mspm0.cfg199
-rw-r--r--tools/scripts/camelcase.txt1
41 files changed, 1949 insertions, 400 deletions
diff --git a/configure.ac b/configure.ac
index 83eb676..ba073f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,9 @@ m4_define([LIBFTDI_USB1_ADAPTERS],
m4_define([LIBGPIOD_ADAPTERS],
[[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]])
+m4_define([REMOTE_BITBANG_ADAPTER],
+ [[[remote_bitbang], [Remote Bitbang driver], [REMOTE_BITBANG]]])
+
m4_define([LIBJAYLINK_ADAPTERS],
[[[jlink], [SEGGER J-Link Programmer], [JLINK]]])
@@ -179,6 +182,15 @@ m4_define([LINUXSPIDEV_ADAPTER],
m4_define([VDEBUG_ADAPTER],
[[[vdebug], [Cadence Virtual Debug Interface], [VDEBUG]]])
+m4_define([JTAG_DPI_ADAPTER],
+ [[[jtag_dpi], [JTAG DPI Adapter], [JTAG_DPI]]])
+
+m4_define([JTAG_VPI_ADAPTER],
+ [[[jtag_vpi], [JTAG VPI Adapter], [JTAG_VPI]]])
+
+m4_define([RSHIM_ADAPTER],
+ [[[rshim], [BlueField SoC via rshim], [RSHIM]]])
+
# The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter
# because there is an M4 macro called 'adapter'.
m4_define([DUMMY_ADAPTER],
@@ -277,10 +289,6 @@ AS_IF([test "x$debug_malloc" = "xyes" -a "x$have_glibc" = "xyes"], [
AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging])
])
-AC_ARG_ENABLE([rshim],
- AS_HELP_STRING([--enable-rshim], [Enable building the rshim driver]),
- [build_rshim=$enableval], [build_rshim=no])
-
AC_ARG_ENABLE([dmem],
AS_HELP_STRING([--enable-dmem], [Enable building the dmem driver]),
[build_dmem=$enableval], [build_dmem=no])
@@ -305,10 +313,14 @@ AC_ARG_ADAPTERS([
LIBFTDI_ADAPTERS,
LIBFTDI_USB1_ADAPTERS,
LIBGPIOD_ADAPTERS,
+ REMOTE_BITBANG_ADAPTER,
LINUXSPIDEV_ADAPTER,
SERIAL_PORT_ADAPTERS,
DUMMY_ADAPTER,
VDEBUG_ADAPTER,
+ JTAG_DPI_ADAPTER,
+ JTAG_VPI_ADAPTER,
+ RSHIM_ADAPTER,
PCIE_ADAPTERS,
LIBJAYLINK_ADAPTERS
],[auto])
@@ -327,14 +339,6 @@ AC_ARG_ENABLE([parport_giveio],
[Enable use of giveio for parport (for CygWin only)]),
[parport_use_giveio=$enableval], [parport_use_giveio=])
-AC_ARG_ENABLE([jtag_vpi],
- AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]),
- [build_jtag_vpi=$enableval], [build_jtag_vpi=no])
-
-AC_ARG_ENABLE([jtag_dpi],
- AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]),
- [build_jtag_dpi=$enableval], [build_jtag_dpi=no])
-
AC_ARG_ENABLE([amtjtagaccel],
AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]),
[build_amtjtagaccel=$enableval], [build_amtjtagaccel=no])
@@ -380,19 +384,24 @@ AC_ARG_ENABLE([sysfsgpio],
AS_HELP_STRING([--enable-sysfsgpio], [Enable building support for programming driven via sysfs gpios.]),
[build_sysfsgpio=$enableval], [build_sysfsgpio=no])
+can_build_rshim=no
+
AS_CASE([$host_os],
[linux*], [
is_linux=yes
+ can_build_rshim=yes
],
[
AS_IF([test "x$build_sysfsgpio" = "xyes"], [
AC_MSG_ERROR([sysfsgpio is only available on linux])
])
- AS_CASE([$host_os], [freebsd*], [],
+ AS_CASE([$host_os], [freebsd*], [
+ can_build_rshim=yes
+ ],
[
- AS_IF([test "x$build_rshim" = "xyes"], [
- AC_MSG_ERROR([build_rshim is only available on linux or freebsd])
+ AS_IF([test "x$enable_rshim" = "xyes"], [
+ AC_MSG_ERROR([rshim is only available on linux or freebsd])
])
])
@@ -414,10 +423,6 @@ AC_ARG_ENABLE([internal-libjaylink],
[Enable building internal libjaylink]),
[use_internal_libjaylink=$enableval], [use_internal_libjaylink=no])
-AC_ARG_ENABLE([remote-bitbang],
- AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang driver]),
- [build_remote_bitbang=$enableval], [build_remote_bitbang=yes])
-
AS_CASE(["${host_cpu}"],
[i?86|x86*], [],
[
@@ -515,12 +520,6 @@ AS_IF([test "x$build_parport" = "xyes"], [
AC_DEFINE([BUILD_PARPORT], [0], [0 if you don't want parport.])
])
-AS_IF([test "x$build_rshim" = "xyes"], [
- AC_DEFINE([BUILD_RSHIM], [1], [1 if you want to debug BlueField SoC via rshim.])
-], [
- AC_DEFINE([BUILD_RSHIM], [0], [0 if you don't want to debug BlueField SoC via rshim.])
-])
-
AS_IF([test "x$build_dmem" = "xyes"], [
AC_DEFINE([BUILD_DMEM], [1], [1 if you want to debug via Direct Mem.])
], [
@@ -578,19 +577,6 @@ AS_IF([test "x$parport_use_giveio" = "xyes"], [
AC_DEFINE([PARPORT_USE_GIVEIO], [0], [0 if you don't want parport to use giveio.])
])
-AS_IF([test "x$build_jtag_vpi" = "xyes"], [
- AC_DEFINE([BUILD_JTAG_VPI], [1], [1 if you want JTAG VPI.])
-], [
- AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.])
-])
-
-AS_IF([test "x$build_jtag_dpi" = "xyes"], [
- AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.])
-], [
- AC_DEFINE([BUILD_JTAG_DPI], [0], [0 if you don't want JTAG DPI.])
-])
-
-
AS_IF([test "x$build_amtjtagaccel" = "xyes"], [
AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec JTAG-Accelerator driver.])
], [
@@ -625,13 +611,6 @@ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [
])
])
-AS_IF([test "x$build_remote_bitbang" = "xyes"], [
- build_bitbang=yes
- AC_DEFINE([BUILD_REMOTE_BITBANG], [1], [1 if you want the Remote Bitbang driver.])
-], [
- AC_DEFINE([BUILD_REMOTE_BITBANG], [0], [0 if you don't want the Remote Bitbang driver.])
-])
-
AS_IF([test "x$build_sysfsgpio" = "xyes"], [
build_bitbang=yes
AC_DEFINE([BUILD_SYSFSGPIO], [1], [1 if you want the SysfsGPIO driver.])
@@ -730,18 +709,27 @@ PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libu
PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi])
PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_libusb1" = "xyes"], [libftdi and libusb-1.x])
PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [Linux libgpiod])
+PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused])
PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2])
PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build])
PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"],
[internal error: validation should happen beforehand])
PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes"], [Linux spidev])
PROCESS_ADAPTERS([VDEBUG_ADAPTER], [true], [unused])
+PROCESS_ADAPTERS([JTAG_DPI_ADAPTER], [true], [unused])
+PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused])
+PROCESS_ADAPTERS([RSHIM_ADAPTER], ["x$can_build_rshim" = "xyes"],
+ [internal error: validation should happen beforehand])
PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused])
AS_IF([test "x$enable_linuxgpiod" != "xno"], [
build_bitbang=yes
])
+AS_IF([test "x$enable_remote_bitbang" != "xno"], [
+ build_bitbang=yes
+])
+
AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno" -o "x$enable_nulink" != "xno"], [
AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.])
AM_CONDITIONAL([HLADAPTER], [true])
@@ -783,12 +771,9 @@ AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"])
AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"])
AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"])
AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"])
-AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"])
-AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"])
AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"])
AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"])
AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"])
-AM_CONDITIONAL([REMOTE_BITBANG], [test "x$build_remote_bitbang" = "xyes"])
AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"])
AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"])
AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"])
@@ -800,7 +785,6 @@ AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"])
AM_CONDITIONAL([USE_LIBGPIOD], [test "x$use_libgpiod" = "xyes"])
AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"])
AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"])
-AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"])
AM_CONDITIONAL([DMEM], [test "x$build_dmem" = "xyes"])
AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"])
@@ -887,9 +871,13 @@ m4_foreach([adapter], [USB1_ADAPTERS,
HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS,
LIBFTDI_USB1_ADAPTERS,
LIBGPIOD_ADAPTERS,
+ REMOTE_BITBANG_ADAPTER,
LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS,
LINUXSPIDEV_ADAPTER,
VDEBUG_ADAPTER,
+ JTAG_DPI_ADAPTER,
+ JTAG_VPI_ADAPTER,
+ RSHIM_ADAPTER,
DUMMY_ADAPTER,
OPTIONAL_LIBRARIES,
COVERAGE],
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 94a8fc7..1dcb7f3 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -2415,12 +2415,6 @@ target.
List the debug adapter drivers that have been built into
the running copy of OpenOCD.
@end deffn
-@deffn {Config Command} {adapter transports} transport_name+
-Specifies the transports supported by this debug adapter.
-The adapter driver builds-in similar knowledge; use this only
-when external configuration (such as jumpering) changes what
-the hardware can support.
-@end deffn
@anchor{adapter gpio}
@deffn {Config Command} {adapter gpio [ @
@@ -3845,13 +3839,6 @@ Not all adapters and adapter drivers support SWD multi-drop. Only the following
adapter drivers are SWD multi-drop capable:
cmsis_dap (use an adapter with CMSIS-DAP version 2.0), ftdi, all bitbang based.
-@subsection SPI Transport
-@cindex SPI
-@cindex Serial Peripheral Interface
-The Serial Peripheral Interface (SPI) is a general purpose transport
-which uses four wire signaling. Some processors use it as part of a
-solution for flash programming.
-
@anchor{swimtransport}
@subsection SWIM Transport
@cindex SWIM
@@ -7430,6 +7417,76 @@ msp432 bsl lock
@end deffn
@end deffn
+@deffn {Flash Driver} {mspm0}
+
+All Arm Cortex-M0+ MSPM0 microcontroller versions from Texas Instruments
+include internal flash. The mspm0 flash driver automatically recognizes the
+specific version's flash parameters and autoconfigures itself. The main
+program flash starts at address 0x0. Non-main flash starts at 0x41c00000.
+If present on the device, the optional region called "Data" starts at
+0x41d00000.
+
+@b{Warning}:
+
+@itemize @bullet
+@item @b{Reset while MCU operation:} When erasing all of MAIN memory, if the
+MCU is still executing from MAIN memory do not reset the device as it could
+cause a double hard-fault due to the missing interrupt vector table at the
+start of memory. To recover from such scenario reset or power-cycle the MCU.
+
+@item @b{No explicit protection support:} MSPM0 flash controller auto-protect
+themselves after every flash operation. As a result of this, OpenOCD does not
+explicitly provide any protection function and automatically un-protects
+required sections as flash operations are requested.
+@end itemize
+
+@b{Examples}:
+
+@itemize @bullet
+
+@item @b{Flash bank description:}
+@example
+flash bank $_FLASHNAME mspm0 0 0 0 0 $_TARGETNAME
+@end example
+
+@item @b{To erase and program the MAIN region:}
+@example
+halt
+flash erase_sector 0 0 last
+flash write_image MAIN.bin 0x0
+mspm0_board_reset
+@end example
+
+@item @b{To erase and program the NONMAIN region:}
+@example
+halt
+flash erase_sector 1 0 last
+flash write_image NONMAIN.bin 0x41C00000
+mspm0_board_reset
+@end example
+
+@end itemize
+
+@deffn {TCL proc} {mspm0_board_reset}
+Performs an nRST toggle on the device.
+@end deffn
+
+@deffn {TCL proc} {mspm0_mass_erase}
+Sends the mass erase command to the SEC-AP mailbox and then performs
+an nRST toggle. Once the command has been fully processed by the ROM,
+all MAIN memory will be erased. NOTE: This command is not supported
+on MSPM0C* family of devices.
+@end deffn
+
+@deffn {TCL proc} {mspm0_factory_reset}
+Sends the factory reset command to the SEC-AP mailbox and then performs
+an nRST toggle. Once the command has been fully processed by the ROM,
+all MAIN memory will be erased and NONMAIN will be reset to its default
+values.
+@end deffn
+
+@end deffn
+
@deffn {Flash Driver} {niietcm4}
This drivers handles the integrated NOR flash on NIIET Cortex-M4
based controllers. Flash size and sector layout are auto-configured by the driver.
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d1c1a2..4dbe93f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,7 +34,10 @@ if RELEASE
else
%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`\"
+%C%_libopenocd_la_CPPFLAGS += -DPKGBLDDATE=\"`DATE_FMT=+%F-%R; \
+ SOURCE_DATE_EPOCH="$${SOURCE_DATE_EPOCH:-$$(date +%s)}"; \
+ date -u -d "@$$SOURCE_DATE_EPOCH" "$$DATE_FMT" 2>/dev/null || \
+ date -u -r "$$SOURCE_DATE_EPOCH" "$$DATE_FMT" 2>/dev/null || date -u "$$DATE_FMT"`\"
endif
# add default CPPFLAGS
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 8296877..147807f 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -45,6 +45,7 @@ NOR_DRIVERS = \
%D%/max32xxx.c \
%D%/mdr.c \
%D%/msp432.c \
+ %D%/mspm0.c \
%D%/mrvlqspi.c \
%D%/niietcm4.c \
%D%/non_cfi.c \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 852a55a..794566f 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -274,6 +274,7 @@ extern const struct flash_driver max32xxx_flash;
extern const struct flash_driver mdr_flash;
extern const struct flash_driver mrvlqspi_flash;
extern const struct flash_driver msp432_flash;
+extern const struct flash_driver mspm0_flash;
extern const struct flash_driver niietcm4_flash;
extern const struct flash_driver npcx_flash;
extern const struct flash_driver nrf51_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index ce97b81..67d8624 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -51,6 +51,7 @@ static const struct flash_driver * const flash_drivers[] = {
&mdr_flash,
&mrvlqspi_flash,
&msp432_flash,
+ &mspm0_flash,
&niietcm4_flash,
&npcx_flash,
&nrf5_flash,
diff --git a/src/flash/nor/mspm0.c b/src/flash/nor/mspm0.c
new file mode 100644
index 0000000..4731c89
--- /dev/null
+++ b/src/flash/nor/mspm0.c
@@ -0,0 +1,1131 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2023-2025 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * NOR flash driver for MSPM0L and MSPM0G class of uC from Texas Instruments.
+ *
+ * See:
+ * https://www.ti.com/microcontrollers-mcus-processors/arm-based-microcontrollers/arm-cortex-m0-mcus/overview.html
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/bits.h>
+#include <helper/time_support.h>
+
+/* MSPM0 Region memory map */
+#define MSPM0_FLASH_BASE_NONMAIN 0x41C00000
+#define MSPM0_FLASH_END_NONMAIN 0x41C00400
+#define MSPM0_FLASH_BASE_MAIN 0x0
+#define MSPM0_FLASH_BASE_DATA 0x41D00000
+
+/* MSPM0 FACTORYREGION registers */
+#define MSPM0_FACTORYREGION 0x41C40000
+#define MSPM0_TRACEID (MSPM0_FACTORYREGION + 0x000)
+#define MSPM0_DID (MSPM0_FACTORYREGION + 0x004)
+#define MSPM0_USERID (MSPM0_FACTORYREGION + 0x008)
+#define MSPM0_SRAMFLASH (MSPM0_FACTORYREGION + 0x018)
+
+/* MSPM0 FCTL registers */
+#define FLASH_CONTROL_BASE 0x400CD000
+#define FCTL_REG_DESC (FLASH_CONTROL_BASE + 0x10FC)
+#define FCTL_REG_CMDEXEC (FLASH_CONTROL_BASE + 0x1100)
+#define FCTL_REG_CMDTYPE (FLASH_CONTROL_BASE + 0x1104)
+#define FCTL_REG_CMDADDR (FLASH_CONTROL_BASE + 0x1120)
+#define FCTL_REG_CMDBYTEN (FLASH_CONTROL_BASE + 0x1124)
+#define FCTL_REG_CMDDATA0 (FLASH_CONTROL_BASE + 0x1130)
+#define FCTL_REG_CMDWEPROTA (FLASH_CONTROL_BASE + 0x11D0)
+#define FCTL_REG_CMDWEPROTB (FLASH_CONTROL_BASE + 0x11D4)
+#define FCTL_REG_CMDWEPROTNM (FLASH_CONTROL_BASE + 0x1210)
+#define FCTL_REG_STATCMD (FLASH_CONTROL_BASE + 0x13D0)
+
+/* FCTL_STATCMD[CMDDONE] Bits */
+#define FCTL_STATCMD_CMDDONE_MASK 0x00000001
+#define FCTL_STATCMD_CMDDONE_STATDONE 0x00000001
+
+/* FCTL_STATCMD[CMDPASS] Bits */
+#define FCTL_STATCMD_CMDPASS_MASK 0x00000002
+#define FCTL_STATCMD_CMDPASS_STATPASS 0x00000002
+
+/*
+ * FCTL_CMDEXEC Bits
+ * FCTL_CMDEXEC[VAL] Bits
+ */
+#define FCTL_CMDEXEC_VAL_EXECUTE 0x00000001
+
+/* FCTL_CMDTYPE[COMMAND] Bits */
+#define FCTL_CMDTYPE_COMMAND_PROGRAM 0x00000001
+#define FCTL_CMDTYPE_COMMAND_ERASE 0x00000002
+
+/* FCTL_CMDTYPE[SIZE] Bits */
+#define FCTL_CMDTYPE_SIZE_ONEWORD 0x00000000
+#define FCTL_CMDTYPE_SIZE_SECTOR 0x00000040
+
+/* FCTL_FEATURE_VER_B minimum */
+#define FCTL_FEATURE_VER_B 0xA
+
+#define MSPM0_MAX_PROTREGS 3
+
+#define MSPM0_FLASH_TIMEOUT_MS 8000
+#define ERR_STRING_MAX 255
+
+/* SYSCTL BASE */
+#define SYSCTL_BASE 0x400AF000
+#define SYSCTL_SECCFG_SECSTATUS (SYSCTL_BASE + 0x00003048)
+
+/* TI manufacturer ID */
+#define TI_MANUFACTURER_ID 0x17
+
+/* Defines for probe status */
+#define MSPM0_NO_ID_FOUND 0
+#define MSPM0_DEV_ID_FOUND 1
+#define MSPM0_DEV_PART_ID_FOUND 2
+
+struct mspm0_flash_bank {
+ /* chip id register */
+ uint32_t did;
+ /* Device Unique ID register */
+ uint32_t traceid;
+ unsigned char version;
+
+ const char *name;
+
+ /* Decoded flash information */
+ unsigned int data_flash_size_kb;
+ unsigned int main_flash_size_kb;
+ unsigned int main_flash_num_banks;
+ unsigned int sector_size;
+ /* Decoded SRAM information */
+ unsigned int sram_size_kb;
+
+ /* Flash word size: 64 bit = 8, 128bit = 16 bytes */
+ unsigned char flash_word_size_bytes;
+
+ /* Protection register stuff */
+ unsigned int protect_reg_base;
+ unsigned int protect_reg_count;
+
+ /* Flashctl version: A - CMDWEPROTA/B, B- CMDWEPROTB */
+ unsigned char flash_version;
+};
+
+struct mspm0_part_info {
+ const char *part_name;
+ unsigned short part;
+ unsigned char variant;
+};
+
+struct mspm0_family_info {
+ const char *family_name;
+ unsigned short part_num;
+ unsigned char part_count;
+ const struct mspm0_part_info *part_info;
+};
+
+/* https://www.ti.com/lit/ds/symlink/mspm0l1346.pdf Table 8-13 and so on */
+static const struct mspm0_part_info mspm0l_parts[] = {
+ { "MSPM0L1105TDGS20R", 0x51DB, 0x16 },
+ { "MSPM0L1105TDGS28R", 0x51DB, 0x83 },
+ { "MSPM0L1105TDYYR", 0x51DB, 0x54 },
+ { "MSPM0L1105TRGER", 0x51DB, 0x86 },
+ { "MSPM0L1105TRHBR", 0x51DB, 0x68 },
+ { "MSPM0L1106TDGS20R", 0x5552, 0x4B },
+ { "MSPM0L1106TDGS28R", 0x5552, 0x98 },
+ { "MSPM0L1106TDYYR", 0x5552, 0x9D },
+ { "MSPM0L1106TRGER", 0x5552, 0x90 },
+ { "MSPM0L1106TRHBR", 0x5552, 0x53 },
+ { "MSPM0L1303SRGER", 0xef0, 0x17 },
+ { "MSPM0L1303TRGER", 0xef0, 0xe2 },
+ { "MSPM0L1304QDGS20R", 0xd717, 0x91 },
+ { "MSPM0L1304QDGS28R", 0xd717, 0xb6 },
+ { "MSPM0L1304QDYYR", 0xd717, 0xa0 },
+ { "MSPM0L1304QRHBR", 0xd717, 0xa9 },
+ { "MSPM0L1304SDGS20R", 0xd717, 0xfa },
+ { "MSPM0L1304SDGS28R", 0xd717, 0x73 },
+ { "MSPM0L1304SDYYR", 0xd717, 0xb7 },
+ { "MSPM0L1304SRGER", 0xd717, 0x26 },
+ { "MSPM0L1304SRHBR", 0xd717, 0xe4 },
+ { "MSPM0L1304TDGS20R", 0xd717, 0x33 },
+ { "MSPM0L1304TDGS28R", 0xd717, 0xa8 },
+ { "MSPM0L1304TDYYR", 0xd717, 0xf9 },
+ { "MSPM0L1304TRGER", 0xd717, 0xb7 },
+ { "MSPM0L1304TRHBR", 0xd717, 0x5a },
+ { "MSPM0L1305QDGS20R", 0x4d03, 0xb7 },
+ { "MSPM0L1305QDGS28R", 0x4d03, 0x74 },
+ { "MSPM0L1305QDYYR", 0x4d03, 0xec },
+ { "MSPM0L1305QRHBR", 0x4d03, 0x78 },
+ { "MSPM0L1305SDGS20R", 0x4d03, 0xc7 },
+ { "MSPM0L1305SDGS28R", 0x4d03, 0x64 },
+ { "MSPM0L1305SDYYR", 0x4d03, 0x91 },
+ { "MSPM0L1305SRGER", 0x4d03, 0x73 },
+ { "MSPM0L1305SRHBR", 0x4d03, 0x2d },
+ { "MSPM0L1305TDGS20R", 0x4d03, 0xa0 },
+ { "MSPM0L1305TDGS28R", 0x4d03, 0xfb },
+ { "MSPM0L1305TDYYR", 0x4d03, 0xde },
+ { "MSPM0L1305TRGER", 0x4d03, 0xea },
+ { "MSPM0L1305TRHBR", 0x4d03, 0x85 },
+ { "MSPM0L1306QDGS20R", 0xbb70, 0x59 },
+ { "MSPM0L1306QDGS28R", 0xbb70, 0xf7 },
+ { "MSPM0L1306QDYYR", 0xbb70, 0x9f },
+ { "MSPM0L1306QRHBR", 0xbb70, 0xc2 },
+ { "MSPM0L1306SDGS20R", 0xbb70, 0xf4 },
+ { "MSPM0L1306SDGS28R", 0xbb70, 0x5 },
+ { "MSPM0L1306SDYYR", 0xbb70, 0xe },
+ { "MSPM0L1306SRGER", 0xbb70, 0x7f },
+ { "MSPM0L1306SRHBR", 0xbb70, 0x3c },
+ { "MSPM0L1306TDGS20R", 0xbb70, 0xa },
+ { "MSPM0L1306TDGS28R", 0xbb70, 0x63 },
+ { "MSPM0L1306TDYYR", 0xbb70, 0x35 },
+ { "MSPM0L1306TRGER", 0xbb70, 0xaa },
+ { "MSPM0L1306TRHBR", 0xbb70, 0x52 },
+ { "MSPM0L1343TDGS20R", 0xb231, 0x2e },
+ { "MSPM0L1344TDGS20R", 0x40b0, 0xd0 },
+ { "MSPM0L1345TDGS28R", 0x98b4, 0x74 },
+ { "MSPM0L1346TDGS28R", 0xf2b5, 0xef },
+};
+
+/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-20 */
+static const struct mspm0_part_info mspm0g_parts[] = {
+ { "MSPM0G1105TPTR", 0x8934, 0xD },
+ { "MSPM0G1105TRGZR", 0x8934, 0xFE },
+ { "MSPM0G1106TPMR", 0x477B, 0xD4 },
+ { "MSPM0G1106TPTR", 0x477B, 0x71 },
+ { "MSPM0G1106TRGZR", 0x477B, 0xBB },
+ { "MSPM0G1106TRHBR", 0x477B, 0x0 },
+ { "MSPM0G1107TDGS28R", 0x807B, 0x82 },
+ { "MSPM0G1107TPMR", 0x807B, 0xB3 },
+ { "MSPM0G1107TPTR", 0x807B, 0x32 },
+ { "MSPM0G1107TRGER", 0x807B, 0x79 },
+ { "MSPM0G1107TRGZR", 0x807B, 0x20 },
+ { "MSPM0G1107TRHBR", 0x807B, 0xBC },
+ { "MSPM0G1505SDGS28R", 0x13C4, 0x73 },
+ { "MSPM0G1505SPMR", 0x13C4, 0x53 },
+ { "MSPM0G1505SPTR", 0x13C4, 0x3E },
+ { "MSPM0G1505SRGER", 0x13C4, 0x47 },
+ { "MSPM0G1505SRGZR", 0x13C4, 0x34 },
+ { "MSPM0G1505SRHBR", 0x13C4, 0x30 },
+ { "MSPM0G1506SDGS28R", 0x5AE0, 0x3A },
+ { "MSPM0G1506SPMR", 0x5AE0, 0xF6 },
+ { "MSPM0G1506SRGER", 0x5AE0, 0x67 },
+ { "MSPM0G1506SRGZR", 0x5AE0, 0x75 },
+ { "MSPM0G1506SRHBR", 0x5AE0, 0x57 },
+ { "MSPM0G1507SDGS28R", 0x2655, 0x6D },
+ { "MSPM0G1507SPMR", 0x2655, 0x97 },
+ { "MSPM0G1507SRGER", 0x2655, 0x83 },
+ { "MSPM0G1507SRGZR", 0x2655, 0xD3 },
+ { "MSPM0G1507SRHBR", 0x2655, 0x4D },
+ { "MSPM0G3105SDGS20R", 0x4749, 0x21 },
+ { "MSPM0G3105SDGS28R", 0x4749, 0xDD },
+ { "MSPM0G3105SRHBR", 0x4749, 0xBE },
+ { "MSPM0G3106SDGS20R", 0x54C7, 0xD2 },
+ { "MSPM0G3106SDGS28R", 0x54C7, 0xB9 },
+ { "MSPM0G3106SRHBR", 0x54C7, 0x67 },
+ { "MSPM0G3107SDGS20R", 0xAB39, 0x5C },
+ { "MSPM0G3107SDGS28R", 0xAB39, 0xCC },
+ { "MSPM0G3107SRHBR", 0xAB39, 0xB7 },
+ { "MSPM0G3505SDGS28R", 0xc504, 0x8e },
+ { "MSPM0G3505SPMR", 0xc504, 0x1d },
+ { "MSPM0G3505SPTR", 0xc504, 0x93 },
+ { "MSPM0G3505SRGZR", 0xc504, 0xc7 },
+ { "MSPM0G3505SRHBR", 0xc504, 0xe7 },
+ { "MSPM0G3505TDGS28R", 0xc504, 0xdf },
+ { "MSPM0G3506SDGS28R", 0x151f, 0x8 },
+ { "MSPM0G3506SPMR", 0x151f, 0xd4 },
+ { "MSPM0G3506SPTR", 0x151f, 0x39 },
+ { "MSPM0G3506SRGZR", 0x151f, 0xfe },
+ { "MSPM0G3506SRHBR", 0x151f, 0xb5 },
+ { "MSPM0G3507SDGS28R", 0xae2d, 0xca },
+ { "MSPM0G3507SPMR", 0xae2d, 0xc7 },
+ { "MSPM0G3507SPTR", 0xae2d, 0x3f },
+ { "MSPM0G3507SRGZR", 0xae2d, 0xf7 },
+ { "MSPM0G3507SRHBR", 0xae2d, 0x4c },
+ { "M0G3107QPMRQ1", 0x4e2f, 0x51 },
+ { "M0G3107QPTRQ1", 0x4e2f, 0xc7},
+ { "M0G3107QRGZRQ1", 0x4e2f, 0x8a },
+ { "M0G3107QRHBRQ1", 0x4e2f, 0x9a},
+ { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5},
+ { "M0G3107QDGS28RQ1", 0x4e2f, 0x67},
+ { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd},
+ { "M0G3106QPMRQ1", 0x54C7, 0x08},
+ { "M0G3105QDGS32RQ1", 0x1349, 0x08},
+ { "M0G3106QPTRQ1", 0x54C7, 0x3F},
+ { "M0G3105QDGS28RQ1", 0x1349, 0x1B},
+ { "M0G3106QRGZRQ1", 0x94AD, 0xE6},
+ { "M0G3105QDGS20RQ1", 0x1349, 0xFB},
+ { "M0G3106QRHBRQ1", 0x94AD, 0x20},
+ { "M0G3106QDGS32RQ1", 0x94AD, 0x8D},
+ { "M0G3106QDGS28RQ1", 0x94AD, 0x03},
+ { "M0G3106QDGS20RQ1", 0x94AD, 0x6F},
+ { "M0G3105QPMRQ1", 0x1349, 0xD0},
+ { "M0G3105QPTRQ1", 0x1349, 0xEF},
+ { "M0G3105QRGZRQ1", 0x1349, 0x70},
+ { "M0G3105QRHBRQ1", 0x1349, 0x01},
+};
+
+/* https://www.ti.com/lit/gpn/mspm0c1104 Table 8-12 and so on */
+static const struct mspm0_part_info mspm0c_parts[] = {
+ { "MSPS003F4SPW20R", 0x57b3, 0x70},
+ { "MSPM0C1104SDGS20R", 0x57b3, 0x71},
+ { "MSPM0C1104SRUKR", 0x57b3, 0x73},
+ { "MSPM0C1104SDYYR", 0x57b3, 0x75},
+ { "MSPM0C1104SDDFR", 0x57b3, 0x77},
+ { "MSPM0C1104SDSGR", 0x57b3, 0x79},
+};
+
+/* https://www.ti.com/lit/gpn/MSPM0L2228 Table 8-16 and so on */
+static const struct mspm0_part_info mspm0lx22x_parts[] = {
+ { "MSPM0L1227SRGER", 0x7C32, 0xF1},
+ { "MSPM0L1227SPTR", 0x7C32, 0xC9},
+ { "MSPM0L1227SPMR", 0x7C32, 0x1C},
+ { "MSPM0L1227SPNAR", 0x7C32, 0x91},
+ { "MSPM0L1227SPNR", 0x7C32, 0x39},
+ { "MSPM0L1228SRGER", 0x33F7, 0x13},
+ { "MSPM0L1228SRHBR", 0x33F7, 0x3A},
+ { "MSPM0L1228SRGZR", 0x33F7, 0xBC},
+ { "MSPM0L1228SPTR", 0x33F7, 0xF8},
+ { "MSPM0L1228SPMR", 0x33F7, 0xCE},
+ { "MSPM0L1228SPNAR", 0x33F7, 0x59},
+ { "MSPM0L1228SPNR", 0x33F7, 0x7},
+ { "MSPM0L2227SRGZR", 0x5E8F, 0x90},
+ { "MSPM0L2227SPTR", 0x5E8F, 0xA},
+ { "MSPM0L2227SPMR", 0x5E8F, 0x6D},
+ { "MSPM0L2227SPNAR", 0x5E8F, 0x24},
+ { "MSPM0L2227SPNR", 0x5E8F, 0x68},
+ { "MSPM0L2228SRGZR", 0x2C38, 0xB8},
+ { "MSPM0L2228SPTR", 0x2C38, 0x25},
+ { "MSPM0L2228SPMR", 0x2C38, 0x6E},
+ { "MSPM0L2228SPNAR", 0x2C38, 0x63},
+ { "MSPM0L2228SPNR", 0x2C38, 0x3C},
+};
+
+static const struct mspm0_family_info mspm0_finf[] = {
+ { "MSPM0L", 0xbb82, ARRAY_SIZE(mspm0l_parts), mspm0l_parts },
+ { "MSPM0Lx22x", 0xbb9f, ARRAY_SIZE(mspm0lx22x_parts), mspm0lx22x_parts },
+ { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts), mspm0g_parts },
+ { "MSPM0C", 0xbba1, ARRAY_SIZE(mspm0c_parts), mspm0c_parts },
+};
+
+/*
+ * OpenOCD command interface
+ */
+
+/*
+ * flash_bank mspm0 <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(mspm0_flash_bank_command)
+{
+ struct mspm0_flash_bank *mspm0_info;
+
+ switch (bank->base) {
+ case MSPM0_FLASH_BASE_NONMAIN:
+ case MSPM0_FLASH_BASE_MAIN:
+ case MSPM0_FLASH_BASE_DATA:
+ break;
+ default:
+ LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
+ return ERROR_FAIL;
+ }
+
+ mspm0_info = calloc(1, sizeof(struct mspm0_flash_bank));
+ if (!mspm0_info) {
+ LOG_ERROR("%s: Out of memory for mspm0_info!", __func__);
+ return ERROR_FAIL;
+ }
+
+ bank->driver_priv = mspm0_info;
+
+ mspm0_info->sector_size = 0x400;
+
+ return ERROR_OK;
+}
+
+/*
+ * Chip identification and status
+ */
+static int get_mspm0_info(struct flash_bank *bank, struct command_invocation *cmd)
+{
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+
+ if (mspm0_info->did == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ command_print_sameline(cmd,
+ "\nTI MSPM0 information: Chip is "
+ "%s rev %d Device Unique ID: 0x%" PRIu32 "\n",
+ mspm0_info->name, mspm0_info->version,
+ mspm0_info->traceid);
+ command_print_sameline(cmd,
+ "main flash: %uKiB in %u bank(s), sram: %uKiB, data flash: %uKiB",
+ mspm0_info->main_flash_size_kb,
+ mspm0_info->main_flash_num_banks, mspm0_info->sram_size_kb,
+ mspm0_info->data_flash_size_kb);
+
+ return ERROR_OK;
+}
+
+/* Extract a bitfield helper */
+static unsigned int mspm0_extract_val(unsigned int var, unsigned char hi, unsigned char lo)
+{
+ return (var & GENMASK(hi, lo)) >> lo;
+}
+
+static int mspm0_read_part_info(struct flash_bank *bank)
+{
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+ struct target *target = bank->target;
+ const struct mspm0_family_info *minfo = NULL;
+
+ /* Read and parse chip identification and flash version register */
+ uint32_t did;
+ int retval = target_read_u32(target, MSPM0_DID, &did);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read device ID");
+ return retval;
+ }
+ retval = target_read_u32(target, MSPM0_TRACEID, &mspm0_info->traceid);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read trace ID");
+ return retval;
+ }
+ uint32_t userid;
+ retval = target_read_u32(target, MSPM0_USERID, &userid);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read user ID");
+ return retval;
+ }
+ uint32_t flashram;
+ retval = target_read_u32(target, MSPM0_SRAMFLASH, &flashram);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read sramflash register");
+ return retval;
+ }
+ uint32_t flashdesc;
+ retval = target_read_u32(target, FCTL_REG_DESC, &flashdesc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read flashctl description register");
+ return retval;
+ }
+
+ unsigned char version = mspm0_extract_val(did, 31, 28);
+ unsigned short pnum = mspm0_extract_val(did, 27, 12);
+ unsigned char variant = mspm0_extract_val(userid, 23, 16);
+ unsigned short part = mspm0_extract_val(userid, 15, 0);
+ unsigned short manufacturer = mspm0_extract_val(did, 11, 1);
+
+ /*
+ * Valid DIE and manufacturer ID?
+ * Check the ALWAYS_1 bit to be 1 and manufacturer to be 0x17. All MSPM0
+ * devices within the Device ID field of the factory constants will
+ * always read 0x17 as it is TI's JEDEC bank and company code. If 1
+ * and 0x17 is not read from their respective registers then it truly
+ * is not a MSPM0 device so we will return an error instead of
+ * going any further.
+ */
+ if (!(did & BIT(0)) || !(manufacturer & TI_MANUFACTURER_ID)) {
+ LOG_WARNING("Unknown Device ID[0x%" PRIx32 "], cannot identify target",
+ did);
+ LOG_DEBUG("did 0x%" PRIx32 ", traceid 0x%" PRIx32 ", userid 0x%" PRIx32
+ ", flashram 0x%" PRIx32 "", did, mspm0_info->traceid, userid,
+ flashram);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Initialize master index selector and probe status*/
+ unsigned char minfo_idx = 0xff;
+ unsigned char probe_status = MSPM0_NO_ID_FOUND;
+
+ /* Check if we at least know the family of devices */
+ for (unsigned int i = 0; i < ARRAY_SIZE(mspm0_finf); i++) {
+ if (mspm0_finf[i].part_num == pnum) {
+ minfo_idx = i;
+ minfo = &mspm0_finf[i];
+ probe_status = MSPM0_DEV_ID_FOUND;
+ break;
+ }
+ }
+
+ /* Initialize part index selector*/
+ unsigned char pinfo_idx = 0xff;
+
+ /*
+ * If we can identify the part number then we will attempt to identify
+ * the specific chip. Otherwise, if we do not know the part number then
+ * it would be useless to identify the specific chip.
+ */
+ if (probe_status == MSPM0_DEV_ID_FOUND) {
+ /* Can we specifically identify the chip */
+ for (unsigned int i = 0; i < minfo->part_count; i++) {
+ if (minfo->part_info[i].part == part
+ && minfo->part_info[i].variant == variant) {
+ pinfo_idx = i;
+ probe_status = MSPM0_DEV_PART_ID_FOUND;
+ break;
+ }
+ }
+ }
+
+ /*
+ * We will check the status of our probe within this switch-case statement
+ * using these three scenarios.
+ *
+ * 1) Device, part, and variant ID is unknown.
+ * 2) Device ID is known but the part/variant ID is unknown.
+ * 3) Device ID and part/variant ID is known
+ *
+ * For scenario 1, we allow the user to continue because if the
+ * manufacturer matches TI's JEDEC value and ALWAYS_1 from the device ID
+ * field is correct then the assumption the user is using an MSPM0 device
+ * can be made.
+ */
+ switch (probe_status) {
+ case MSPM0_NO_ID_FOUND:
+ mspm0_info->name = "mspm0x";
+ LOG_INFO("Unidentified PART[0x%x]/variant[0x%x"
+ "], unknown DeviceID[0x%x"
+ "]. Attempting to proceed as %s.", part, variant, pnum,
+ mspm0_info->name);
+ break;
+ case MSPM0_DEV_ID_FOUND:
+ mspm0_info->name = mspm0_finf[minfo_idx].family_name;
+ LOG_INFO("Unidentified PART[0x%x]/variant[0x%x"
+ "], known DeviceID[0x%x"
+ "]. Attempting to proceed as %s.", part, variant, pnum,
+ mspm0_info->name);
+ break;
+ case MSPM0_DEV_PART_ID_FOUND:
+ default:
+ mspm0_info->name = mspm0_finf[minfo_idx].part_info[pinfo_idx].part_name;
+ LOG_DEBUG("Part: %s detected", mspm0_info->name);
+ break;
+ }
+
+ mspm0_info->did = did;
+ mspm0_info->version = version;
+ mspm0_info->data_flash_size_kb = mspm0_extract_val(flashram, 31, 26);
+ mspm0_info->main_flash_size_kb = mspm0_extract_val(flashram, 11, 0);
+ mspm0_info->main_flash_num_banks = mspm0_extract_val(flashram, 13, 12) + 1;
+ mspm0_info->sram_size_kb = mspm0_extract_val(flashram, 25, 16);
+ mspm0_info->flash_version = mspm0_extract_val(flashdesc, 15, 12);
+
+ /*
+ * Hardcode flash_word_size unless we find some other pattern
+ * See section 7.7 (Foot note mentions the flash word size).
+ * almost all values seem to be 8 bytes, but if there are variance,
+ * then we should update mspm0_part_info structure with this info.
+ */
+ mspm0_info->flash_word_size_bytes = 8;
+
+ LOG_DEBUG("Detected: main flash: %uKb in %u banks, sram: %uKb, data flash: %uKb",
+ mspm0_info->main_flash_size_kb, mspm0_info->main_flash_num_banks,
+ mspm0_info->sram_size_kb, mspm0_info->data_flash_size_kb);
+
+ return ERROR_OK;
+}
+
+/*
+ * Decode error values
+ */
+static const struct {
+ const unsigned char bit_offset;
+ const char *fail_string;
+} mspm0_fctl_fail_decode_strings[] = {
+ { 2, "CMDINPROGRESS" },
+ { 4, "FAILWEPROT" },
+ { 5, "FAILVERIFY" },
+ { 6, "FAILILLADDR" },
+ { 7, "FAILMODE" },
+ { 12, "FAILMISC" },
+};
+
+static const char *mspm0_fctl_translate_ret_err(unsigned int return_code)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(mspm0_fctl_fail_decode_strings); i++) {
+ if (return_code & BIT(mspm0_fctl_fail_decode_strings[i].bit_offset))
+ return mspm0_fctl_fail_decode_strings[i].fail_string;
+ }
+
+ /* If unknown error notify the user*/
+ return "FAILUNKNOWN";
+}
+
+static int mspm0_fctl_get_sector_reg(struct flash_bank *bank, unsigned int addr,
+ unsigned int *reg, unsigned int *sector_mask)
+{
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+ struct target *target = bank->target;
+ int ret = ERROR_OK;
+ unsigned int sector_num = (addr >> 10);
+ unsigned int sector_in_bank = sector_num;
+ unsigned int phys_sector_num = sector_num;
+ uint32_t sysctl_sec_status;
+ unsigned int exec_upper_bank;
+
+ /*
+ * If the device has dual banks we will need to check if it is configured
+ * to execute from the upper bank. In the scenario that we are executing
+ * from upper bank then we will need to protect it using CMDWEPROTA rather
+ * than CMDWEPROTB. We also need to take into account what sector
+ * we're using when going between banks.
+ */
+ if (mspm0_info->main_flash_num_banks > 1 &&
+ bank->base == MSPM0_FLASH_BASE_MAIN) {
+ ret = target_read_u32(target, SYSCTL_SECCFG_SECSTATUS, &sysctl_sec_status);
+ if (ret != ERROR_OK)
+ return ret;
+ exec_upper_bank = mspm0_extract_val(sysctl_sec_status, 12, 12);
+ if (exec_upper_bank) {
+ if (sector_num > (mspm0_info->main_flash_size_kb / 2)) {
+ phys_sector_num =
+ sector_num - (mspm0_info->main_flash_size_kb / 2);
+ } else {
+ phys_sector_num =
+ sector_num + (mspm0_info->main_flash_size_kb / 2);
+ }
+ }
+ sector_in_bank =
+ sector_num % (mspm0_info->main_flash_size_kb /
+ mspm0_info->main_flash_num_banks);
+ }
+
+ /*
+ * NOTE: MSPM0 devices of version A will use CMDWEPROTA and CMDWEPROTB
+ * for MAIN flash. CMDWEPROTC is included in the TRM/DATASHEET but for
+ * all practical purposes, it is considered reserved. If the flash
+ * version on the device is version B, then we will only use
+ * CMDWEPROTB for MAIN and DATA flash if the device has it.
+ */
+ switch (bank->base) {
+ case MSPM0_FLASH_BASE_MAIN:
+ case MSPM0_FLASH_BASE_DATA:
+ if (mspm0_info->flash_version < FCTL_FEATURE_VER_B) {
+ /* Use CMDWEPROTA */
+ if (phys_sector_num < 32) {
+ *sector_mask = BIT(phys_sector_num);
+ *reg = FCTL_REG_CMDWEPROTA;
+ }
+
+ /* Use CMDWEPROTB */
+ if (phys_sector_num >= 32 && sector_in_bank < 256) {
+ /* Dual bank system */
+ if (mspm0_info->main_flash_num_banks > 1)
+ *sector_mask = BIT(sector_in_bank / 8);
+ else /* Single bank system */
+ *sector_mask = BIT((sector_in_bank - 32) / 8);
+ *reg = FCTL_REG_CMDWEPROTB;
+ }
+ } else {
+ *sector_mask = BIT((sector_in_bank / 8) % 32);
+ *reg = FCTL_REG_CMDWEPROTB;
+ }
+ break;
+ case MSPM0_FLASH_BASE_NONMAIN:
+ *sector_mask = BIT(sector_num % 32);
+ *reg = FCTL_REG_CMDWEPROTNM;
+ break;
+ default:
+ /*
+ * Not expected to reach here due to check in mspm0_address_check()
+ * but adding it as another layer of safety.
+ */
+ ret = ERROR_FLASH_DST_OUT_OF_BANK;
+ break;
+ }
+
+ if (ret != ERROR_OK)
+ LOG_ERROR("Unable to map sector protect reg for address 0x%08x", addr);
+
+ return ret;
+}
+
+static int mspm0_address_check(struct flash_bank *bank, unsigned int addr)
+{
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+ unsigned int flash_main_size = mspm0_info->main_flash_size_kb * 1024;
+ unsigned int flash_data_size = mspm0_info->data_flash_size_kb * 1024;
+ int ret = ERROR_FLASH_SECTOR_INVALID;
+
+ /*
+ * Before unprotecting any memory lets make sure that the address and
+ * bank given is a known bank and whether or not the address falls under
+ * the proper bank.
+ */
+ switch (bank->base) {
+ case MSPM0_FLASH_BASE_MAIN:
+ if (addr <= (MSPM0_FLASH_BASE_MAIN + flash_main_size))
+ ret = ERROR_OK;
+ break;
+ case MSPM0_FLASH_BASE_NONMAIN:
+ if (addr >= MSPM0_FLASH_BASE_NONMAIN && addr <= MSPM0_FLASH_END_NONMAIN)
+ ret = ERROR_OK;
+ break;
+ case MSPM0_FLASH_BASE_DATA:
+ if (addr >= MSPM0_FLASH_BASE_DATA &&
+ addr <= (MSPM0_FLASH_BASE_DATA + flash_data_size))
+ ret = ERROR_OK;
+ break;
+ default:
+ ret = ERROR_FLASH_DST_OUT_OF_BANK;
+ break;
+ }
+
+ return ret;
+}
+
+static int mspm0_fctl_unprotect_sector(struct flash_bank *bank, unsigned int addr)
+{
+ struct target *target = bank->target;
+ unsigned int reg = 0x0;
+ uint32_t sector_mask = 0x0;
+ int ret;
+
+ ret = mspm0_address_check(bank, addr);
+ switch (ret) {
+ case ERROR_FLASH_SECTOR_INVALID:
+ LOG_ERROR("Unable to map sector protect reg for address 0x%08x", addr);
+ break;
+ case ERROR_FLASH_DST_OUT_OF_BANK:
+ LOG_ERROR("Unable to determine which bank to use 0x%08x", addr);
+ break;
+ default:
+ mspm0_fctl_get_sector_reg(bank, addr, &reg, &sector_mask);
+ ret = target_write_u32(target, reg, ~sector_mask);
+ break;
+ }
+
+ return ret;
+}
+
+static int mspm0_fctl_cfg_command(struct flash_bank *bank,
+ uint32_t addr,
+ uint32_t cmd,
+ uint32_t byte_en)
+{
+ struct target *target = bank->target;
+
+ /*
+ * Configure the flash operation within the CMDTYPE register, byte_en
+ * bits if needed, and then set the address where the flash operation
+ * will execute.
+ */
+ int retval = target_write_u32(target, FCTL_REG_CMDTYPE, cmd);
+ if (retval != ERROR_OK)
+ return retval;
+ if (byte_en != 0) {
+ retval = target_write_u32(target, FCTL_REG_CMDBYTEN, byte_en);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ return target_write_u32(target, FCTL_REG_CMDADDR, addr);
+}
+
+static int mspm0_fctl_wait_cmd_ok(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ uint32_t return_code = 0;
+ int64_t start_ms;
+ int64_t elapsed_ms;
+
+ start_ms = timeval_ms();
+ while ((return_code & FCTL_STATCMD_CMDDONE_MASK) != FCTL_STATCMD_CMDDONE_STATDONE) {
+ int retval = target_read_u32(target, FCTL_REG_STATCMD, &return_code);
+ if (retval != ERROR_OK)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > MSPM0_FLASH_TIMEOUT_MS)
+ break;
+ }
+
+ if ((return_code & FCTL_STATCMD_CMDPASS_MASK) != FCTL_STATCMD_CMDPASS_STATPASS) {
+ LOG_ERROR("Flash command failed: %s", mspm0_fctl_translate_ret_err(return_code));
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int mspm0_fctl_sector_erase(struct flash_bank *bank, uint32_t addr)
+{
+ struct target *target = bank->target;
+
+ /*
+ * TRM Says:
+ * Note that the CMDWEPROTx registers are reset to a protected state
+ * at the end of all program and erase operations. These registers
+ * must be re-configured by software before a new operation is
+ * initiated.
+ *
+ * This means that as we start erasing sector by sector, the protection
+ * registers are reset and need to be unprotected *again* for the next
+ * erase operation. Unfortunately, this means that we cannot do a unitary
+ * unprotect operation independent of flash erase operation
+ */
+ int retval = mspm0_fctl_unprotect_sector(bank, addr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Unprotecting sector of memory at address 0x%08" PRIx32
+ " failed", addr);
+ return retval;
+ }
+
+ /* Actual erase operation */
+ retval = mspm0_fctl_cfg_command(bank, addr,
+ (FCTL_CMDTYPE_COMMAND_ERASE | FCTL_CMDTYPE_SIZE_SECTOR), 0);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_write_u32(target, FCTL_REG_CMDEXEC, FCTL_CMDEXEC_VAL_EXECUTE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return mspm0_fctl_wait_cmd_ok(bank);
+}
+
+static int mspm0_protect_check(struct flash_bank *bank)
+{
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+
+ if (mspm0_info->did == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /*
+ * TRM Says:
+ * Note that the CMDWEPROTx registers are reset to a protected state
+ * at the end of all program and erase operations. These registers
+ * must be re-configured by software before a new operation is
+ * initiated.
+ *
+ * This means that when any flash operation is performed at a block level,
+ * the block is locked back again. This prevents usage where we can set a
+ * protection level once at the flash level and then do erase / write
+ * operation without touching the protection register (since it is
+ * reset by hardware automatically). In effect, we cannot use the hardware
+ * defined protection scheme in openOCD.
+ *
+ * To deal with this protection scheme, the CMDWEPROTx register that
+ * correlates to the sector is modified at the time of operation and as far
+ * openOCD is concerned, the flash operates as completely un-protected
+ * flash.
+ */
+ for (unsigned int i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_protected = 0;
+
+ return ERROR_OK;
+}
+
+static int mspm0_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
+{
+ struct target *target = bank->target;
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+ int retval = ERROR_OK;
+ uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS];
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Please halt target for erasing flash");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (mspm0_info->did == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* Pick a copy of the current protection config for later restoration */
+ for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) {
+ retval = target_read_u32(target,
+ mspm0_info->protect_reg_base + (i * 4),
+ &protect_reg_cache[i]);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed saving flashctl protection status");
+ return retval;
+ }
+ }
+
+ switch (bank->base) {
+ case MSPM0_FLASH_BASE_MAIN:
+ for (unsigned int csa = first; csa <= last; csa++) {
+ unsigned int addr = csa * mspm0_info->sector_size;
+ retval = mspm0_fctl_sector_erase(bank, addr);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Sector erase on MAIN failed at address 0x%08x "
+ "(sector: %u)", addr, csa);
+ }
+ break;
+ case MSPM0_FLASH_BASE_NONMAIN:
+ retval = mspm0_fctl_sector_erase(bank, MSPM0_FLASH_BASE_NONMAIN);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Sector erase on NONMAIN failed");
+ break;
+ case MSPM0_FLASH_BASE_DATA:
+ for (unsigned int csa = first; csa <= last; csa++) {
+ unsigned int addr = (MSPM0_FLASH_BASE_DATA +
+ (csa * mspm0_info->sector_size));
+ retval = mspm0_fctl_sector_erase(bank, addr);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Sector erase on DATA bank failed at address 0x%08x "
+ "(sector: %u)", addr, csa);
+ }
+ break;
+ default:
+ LOG_ERROR("Invalid memory region access");
+ retval = ERROR_FLASH_BANK_INVALID;
+ break;
+ }
+
+ /* If there were any issues in our checks, return the error */
+ if (retval != ERROR_OK)
+ return retval;
+
+ /*
+ * TRM Says:
+ * Note that the CMDWEPROTx registers are reset to a protected state
+ * at the end of all program and erase operations. These registers
+ * must be re-configured by software before a new operation is
+ * initiated
+ * Let us just Dump the protection registers back to the system.
+ * That way we retain the protection status as requested by the user
+ */
+ for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) {
+ retval = target_write_u32(target, mspm0_info->protect_reg_base + (i * 4),
+ protect_reg_cache[i]);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed re-applying protection status of flashctl");
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static int mspm0_write(struct flash_bank *bank, const unsigned char *buffer,
+ unsigned int offset, unsigned int count)
+{
+ struct target *target = bank->target;
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+ uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS];
+ int retval;
+
+ /*
+ * XXX: TRM Says:
+ * The number of program operations applied to a given word line must be
+ * monitored to ensure that the maximum word line program limit before
+ * erase is not violated.
+ *
+ * There is no reasonable way we can maintain that state in OpenOCD. So,
+ * Let the manufacturing path figure this out.
+ */
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Please halt target for programming flash");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (mspm0_info->did == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /*
+ * Pick a copy of the current protection config for later restoration
+ * We need to restore these regs after every write, so instead of trying
+ * to figure things out on the fly, we just context save and restore
+ */
+ for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) {
+ retval = target_read_u32(target,
+ mspm0_info->protect_reg_base + (i * 4),
+ &protect_reg_cache[i]);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed saving flashctl protection status");
+ return retval;
+ }
+ }
+
+ /* Add proper memory offset for bank being written to */
+ unsigned int addr = bank->base + offset;
+
+ while (count) {
+ unsigned int num_bytes_to_write;
+ uint32_t bytes_en;
+
+ /*
+ * If count is not 64 bit aligned, we will do byte wise op to keep things simple
+ * Usually this might mean we need to additional write ops towards
+ * trailing edge, but that is a tiny penalty for image downloads.
+ * NOTE: we are going to assume the device does not support multi-word
+ * programming - there does not seem to be discoverability!
+ */
+ if (count < mspm0_info->flash_word_size_bytes)
+ num_bytes_to_write = count;
+ else
+ num_bytes_to_write = mspm0_info->flash_word_size_bytes;
+
+ /* Data bytes to write */
+ bytes_en = (1 << num_bytes_to_write) - 1;
+ /* ECC chunks to write */
+ switch (mspm0_info->flash_word_size_bytes) {
+ case 8:
+ bytes_en |= BIT(8);
+ break;
+ case 16:
+ bytes_en |= BIT(16);
+ bytes_en |= (num_bytes_to_write > 8) ? BIT(17) : 0;
+ break;
+ default:
+ LOG_ERROR("Invalid flash_word_size_bytes %d",
+ mspm0_info->flash_word_size_bytes);
+ return ERROR_FAIL;
+ }
+
+ retval = mspm0_fctl_cfg_command(bank, addr,
+ (FCTL_CMDTYPE_COMMAND_PROGRAM | FCTL_CMDTYPE_SIZE_ONEWORD),
+ bytes_en);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = mspm0_fctl_unprotect_sector(bank, addr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = target_write_buffer(target, FCTL_REG_CMDDATA0, num_bytes_to_write, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ addr += num_bytes_to_write;
+ buffer += num_bytes_to_write;
+ count -= num_bytes_to_write;
+
+ retval = target_write_u32(target, FCTL_REG_CMDEXEC, FCTL_CMDEXEC_VAL_EXECUTE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = mspm0_fctl_wait_cmd_ok(bank);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /*
+ * TRM Says:
+ * Note that the CMDWEPROTx registers are reset to a protected state
+ * at the end of all program and erase operations. These registers
+ * must be re-configured by software before a new operation is
+ * initiated
+ * Let us just Dump the protection registers back to the system.
+ * That way we retain the protection status as requested by the user
+ */
+ for (unsigned int i = 0; i < mspm0_info->protect_reg_count; i++) {
+ retval = target_write_u32(target,
+ mspm0_info->protect_reg_base + (i * 4),
+ protect_reg_cache[i]);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed re-applying protection status of flashctl");
+ return retval;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int mspm0_probe(struct flash_bank *bank)
+{
+ struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+
+ /*
+ * If this is a mspm0 chip, it has flash; probe() is just
+ * to figure out how much is present. Only do it once.
+ */
+ if (mspm0_info->did != 0)
+ return ERROR_OK;
+
+ /*
+ * mspm0_read_part_info() already handled error checking and
+ * reporting. Note that it doesn't write, so we don't care about
+ * whether the target is halted or not.
+ */
+ int retval = mspm0_read_part_info(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (bank->sectors) {
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
+ bank->write_start_alignment = 4;
+ bank->write_end_alignment = 4;
+
+ switch (bank->base) {
+ case MSPM0_FLASH_BASE_NONMAIN:
+ bank->size = 1024;
+ bank->num_sectors = 0x1;
+ mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTNM;
+ mspm0_info->protect_reg_count = 1;
+ break;
+ case MSPM0_FLASH_BASE_MAIN:
+ bank->size = (mspm0_info->main_flash_size_kb * 1024);
+ bank->num_sectors = bank->size / mspm0_info->sector_size;
+ /*
+ * If the feature version bit read from the FCTL_REG_DESC is
+ * greater than or equal to 0xA then it means that the device
+ * will exclusively use CMDWEPROTB ONLY for MAIN memory protection
+ */
+ if (mspm0_info->flash_version >= FCTL_FEATURE_VER_B) {
+ mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTB;
+ mspm0_info->protect_reg_count = 1;
+ } else {
+ mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTA;
+ mspm0_info->protect_reg_count = 3;
+ }
+ break;
+ case MSPM0_FLASH_BASE_DATA:
+ if (!mspm0_info->data_flash_size_kb) {
+ LOG_INFO("Data region NOT available!");
+ bank->size = 0x0;
+ bank->num_sectors = 0x0;
+ return ERROR_OK;
+ }
+ /*
+ * Any MSPM0 device containing data bank will have a flashctl
+ * feature version of 0xA or higher. Since data bank is treated
+ * like MAIN memory, it will also exclusively use CMDWEPROTB for
+ * protection.
+ */
+ bank->size = (mspm0_info->data_flash_size_kb * 1024);
+ bank->num_sectors = bank->size / mspm0_info->sector_size;
+ mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTB;
+ mspm0_info->protect_reg_count = 1;
+ break;
+ default:
+ LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT,
+ bank->base);
+ return ERROR_FAIL;
+ }
+
+ bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
+ if (!bank->sectors) {
+ LOG_ERROR("Out of memory for sectors!");
+ return ERROR_FAIL;
+ }
+ for (unsigned int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * mspm0_info->sector_size;
+ bank->sectors[i].size = mspm0_info->sector_size;
+ bank->sectors[i].is_erased = -1;
+ }
+
+ return ERROR_OK;
+}
+
+const struct flash_driver mspm0_flash = {
+ .name = "mspm0",
+ .flash_bank_command = mspm0_flash_bank_command,
+ .erase = mspm0_erase,
+ .protect = NULL,
+ .write = mspm0_write,
+ .read = default_flash_read,
+ .probe = mspm0_probe,
+ .auto_probe = mspm0_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = mspm0_protect_check,
+ .info = get_mspm0_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index 3062fca..fa57db8 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -370,11 +370,15 @@ static const struct stm32l4_rev stm32u53_u54xx_revs[] = {
static const struct stm32l4_rev stm32u57_u58xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
- { 0x2001, "X" }, { 0x3000, "C" }, { 0x3001, "W" },
+ { 0x2001, "X" }, { 0x3000, "C" }, { 0x3001, "W" }, { 0x3007, "U" },
};
static const struct stm32l4_rev stm32u59_u5axx_revs[] = {
- { 0x3001, "X" },
+ { 0x3001, "X" }, { 0x3002, "W" },
+};
+
+static const struct stm32l4_rev stm32u5f_u5gxx_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" },
};
static const struct stm32l4_rev stm32wba5x_revs[] = {
@@ -675,6 +679,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.otp_size = 512,
},
{
+ .id = DEVID_STM32U5F_U5GXX,
+ .revs = stm32u5f_u5gxx_revs,
+ .num_revs = ARRAY_SIZE(stm32u5f_u5gxx_revs),
+ .device_str = "STM32U5F/U5Gxx",
+ .max_flash_size_kb = 4096,
+ .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x0BFA07A0,
+ .otp_base = 0x0BFA0000,
+ .otp_size = 512,
+ },
+ {
.id = DEVID_STM32WBA5X,
.revs = stm32wba5x_revs,
.num_revs = ARRAY_SIZE(stm32wba5x_revs),
@@ -2095,6 +2111,7 @@ static int stm32l4_probe(struct flash_bank *bank)
case DEVID_STM32U53_U54XX:
case DEVID_STM32U57_U58XX:
case DEVID_STM32U59_U5AXX:
+ case DEVID_STM32U5F_U5GXX:
/* according to RM0456 Rev 4, Chapter 7.3.1 and 7.9.13
* U53x/U54x have 512K max flash size:
* 512K variants are always in DUAL BANK mode
@@ -2102,7 +2119,7 @@ static int stm32l4_probe(struct flash_bank *bank)
* U57x/U58x have 2M max flash size:
* 2M variants are always in DUAL BANK mode
* 1M variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set
- * U59x/U5Ax have 4M max flash size:
+ * U59x/U5Ax/U5Fx/U5Gx have 4M max flash size:
* 4M variants are always in DUAL BANK mode
* 2M variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set
* Note: flash banks are always contiguous
diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h
index f152c9f..3199d4f 100644
--- a/src/flash/nor/stm32l4x.h
+++ b/src/flash/nor/stm32l4x.h
@@ -103,6 +103,7 @@
#define DEVID_STM32L4R_L4SXX 0x470
#define DEVID_STM32L4P_L4QXX 0x471
#define DEVID_STM32L55_L56XX 0x472
+#define DEVID_STM32U5F_U5GXX 0x476
#define DEVID_STM32G49_G4AXX 0x479
#define DEVID_STM32U59_U5AXX 0x481
#define DEVID_STM32U57_U58XX 0x482
diff --git a/src/helper/command.c b/src/helper/command.c
index d90d341..3d4379d 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -41,6 +41,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a
static int help_add_command(struct command_context *cmd_ctx,
const char *cmd_name, const char *help_text, const char *usage_text);
static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name);
+static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_name);
/* set of functions to wrap jimtcl internal data */
static inline bool jimcmd_is_proc(Jim_Cmd *cmd)
@@ -673,7 +674,7 @@ COMMAND_HANDLER(handle_echo)
}
if (CMD_ARGC != 1)
- return ERROR_FAIL;
+ return ERROR_COMMAND_SYNTAX_ERROR;
LOG_USER("%s", CMD_ARGV[0]);
return ERROR_OK;
@@ -779,24 +780,7 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
if (is_match && show_help) {
char *msg;
- /* TODO: factorize jim_command_mode() to avoid running jim command here */
- char *request = alloc_printf("command mode %s", c->cmd_name);
- if (!request) {
- LOG_ERROR("Out of memory");
- return ERROR_FAIL;
- }
- int retval = Jim_Eval(CMD_CTX->interp, request);
- free(request);
- enum command_mode mode = COMMAND_UNKNOWN;
- if (retval != JIM_ERR) {
- const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL);
- if (!strcmp(result, "any"))
- mode = COMMAND_ANY;
- else if (!strcmp(result, "config"))
- mode = COMMAND_CONFIG;
- else if (!strcmp(result, "exec"))
- mode = COMMAND_EXEC;
- }
+ enum command_mode mode = get_command_mode(CMD_CTX->interp, c->cmd_name);
/* Normal commands are runtime-only; highlight exceptions */
if (mode != COMMAND_EXEC) {
@@ -809,6 +793,7 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
case COMMAND_ANY:
stage_msg = " (command valid any time)";
break;
+ case COMMAND_UNKNOWN:
default:
stage_msg = " (?mode error?)";
break;
@@ -817,11 +802,13 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
} else
msg = alloc_printf("%s", c->help ? c->help : "");
- if (msg) {
- command_help_show_wrap(msg, n + 3, n + 3);
- free(msg);
- } else
- return -ENOMEM;
+ if (!msg) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ command_help_show_wrap(msg, n + 3, n + 3);
+ free(msg);
}
return ERROR_OK;
@@ -936,35 +923,41 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a
return retval;
}
+static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_name)
+{
+ if (!cmd_name)
+ return COMMAND_UNKNOWN;
+
+ Jim_Obj *s = Jim_NewStringObj(interp, cmd_name, -1);
+ Jim_IncrRefCount(s);
+ Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
+ Jim_DecrRefCount(interp, s);
+
+ if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd)))
+ return COMMAND_UNKNOWN;
+
+ /* tcl proc */
+ if (jimcmd_is_proc(cmd))
+ return COMMAND_ANY;
+
+ struct command *c = jimcmd_privdata(cmd);
+ return c->mode;
+}
+
static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
struct command_context *cmd_ctx = current_command_context(interp);
- enum command_mode mode;
+ enum command_mode mode = cmd_ctx->mode;
if (argc > 1) {
char *full_name = alloc_concatenate_strings(argc - 1, argv + 1);
if (!full_name)
return JIM_ERR;
- Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1);
- Jim_IncrRefCount(s);
- Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
- Jim_DecrRefCount(interp, s);
- free(full_name);
- if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd))) {
- Jim_SetResultString(interp, "unknown", -1);
- return JIM_OK;
- }
- if (jimcmd_is_proc(cmd)) {
- /* tcl proc */
- mode = COMMAND_ANY;
- } else {
- struct command *c = jimcmd_privdata(cmd);
+ mode = get_command_mode(interp, full_name);
- mode = c->mode;
- }
- } else
- mode = cmd_ctx->mode;
+ free(full_name);
+ }
const char *mode_str;
switch (mode) {
@@ -977,6 +970,7 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
case COMMAND_EXEC:
mode_str = "exec";
break;
+ case COMMAND_UNKNOWN:
default:
mode_str = "unknown";
break;
diff --git a/src/helper/log.h b/src/helper/log.h
index e2bb131..ac24f8e 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -85,7 +85,8 @@ struct log_callback {
int log_add_callback(log_callback_fn fn, void *priv);
int log_remove_callback(log_callback_fn fn, void *priv);
-char *alloc_vprintf(const char *fmt, va_list ap);
+char *alloc_vprintf(const char *fmt, va_list ap)
+ __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 0)));
char *alloc_printf(const char *fmt, ...)
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2)));
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 04942f7..2fcbd60 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -392,37 +392,22 @@ COMMAND_HANDLER(handle_adapter_name)
return ERROR_OK;
}
-COMMAND_HANDLER(adapter_transports_command)
+COMMAND_HANDLER(dump_adapter_driver_list)
{
- char **transports;
- int retval;
-
- retval = CALL_COMMAND_HANDLER(transport_list_parse, &transports);
- if (retval != ERROR_OK)
- return retval;
-
- retval = allow_transports(CMD_CTX, (const char **)transports);
-
- if (retval != ERROR_OK) {
- for (unsigned int i = 0; transports[i]; i++)
- free(transports[i]);
- free(transports);
+ for (unsigned int i = 0; adapter_drivers[i]; i++) {
+ const char *name = adapter_drivers[i]->name;
+ command_print(CMD, "%u: %s", i + 1, name);
}
- return retval;
+
+ return ERROR_OK;
}
COMMAND_HANDLER(handle_adapter_list_command)
{
- if (strcmp(CMD_NAME, "list") == 0 && CMD_ARGC > 0)
+ if (CMD_ARGC)
return ERROR_COMMAND_SYNTAX_ERROR;
- command_print(CMD, "The following debug adapters are available:");
- for (unsigned int i = 0; adapter_drivers[i]; i++) {
- const char *name = adapter_drivers[i]->name;
- command_print(CMD, "%u: %s", i + 1, name);
- }
-
- return ERROR_OK;
+ return CALL_COMMAND_HANDLER(dump_adapter_driver_list);
}
COMMAND_HANDLER(handle_adapter_driver_command)
@@ -459,7 +444,8 @@ COMMAND_HANDLER(handle_adapter_driver_command)
*/
LOG_ERROR("The specified debug interface was not found (%s)",
CMD_ARGV[0]);
- CALL_COMMAND_HANDLER(handle_adapter_list_command);
+ command_print(CMD, "The following adapter drivers are available:");
+ CALL_COMMAND_HANDLER(dump_adapter_driver_list);
return ERROR_JTAG_INVALID_INTERFACE;
}
@@ -1138,13 +1124,6 @@ static const struct command_registration adapter_command_handlers[] = {
.chain = adapter_srst_command_handlers,
},
{
- .name = "transports",
- .handler = adapter_transports_command,
- .mode = COMMAND_CONFIG,
- .help = "Declare transports the adapter supports.",
- .usage = "transport ...",
- },
- {
.name = "usb",
.mode = COMMAND_ANY,
.help = "usb adapter command group",
diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c
index 095601f..e8689aa 100644
--- a/src/jtag/drivers/bcm2835gpio.c
+++ b/src/jtag/drivers/bcm2835gpio.c
@@ -427,7 +427,7 @@ static int bcm2835gpio_blink(bool on)
return ERROR_OK;
}
-static struct bitbang_interface bcm2835gpio_bitbang = {
+static const struct bitbang_interface bcm2835gpio_bitbang_swd_write_generic = {
.read = bcm2835gpio_read,
.write = bcm2835gpio_write,
.swdio_read = bcm2835_swdio_read,
@@ -436,11 +436,19 @@ static struct bitbang_interface bcm2835gpio_bitbang = {
.blink = bcm2835gpio_blink,
};
+static const struct bitbang_interface bcm2835gpio_bitbang_swd_write_fast = {
+ .read = bcm2835gpio_read,
+ .write = bcm2835gpio_write,
+ .swdio_read = bcm2835_swdio_read,
+ .swdio_drive = bcm2835_swdio_drive,
+ .swd_write = bcm2835gpio_swd_write_fast,
+ .blink = bcm2835gpio_blink,
+};
+
static int bcm2835gpio_init(void)
{
LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver");
- bitbang_interface = &bcm2835gpio_bitbang;
adapter_gpio_config = adapter_gpio_get_config();
if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) {
@@ -509,6 +517,8 @@ LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
initialize_gpio(ADAPTER_GPIO_IDX_TRST);
}
+ const struct bitbang_interface *bcm2835gpio_bitbang = &bcm2835gpio_bitbang_swd_write_generic;
+
if (transport_is_swd()) {
/* swdio and its buffer should be initialized in the order that prevents
* two outputs from being connected together. This will occur if the
@@ -529,16 +539,18 @@ LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL &&
adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) {
LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write");
- bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_fast;
+ bcm2835gpio_bitbang = &bcm2835gpio_bitbang_swd_write_fast;
} else {
LOG_DEBUG("BCM2835 GPIO using generic mode for SWD write");
- bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_generic;
+ assert(bcm2835gpio_bitbang == &bcm2835gpio_bitbang_swd_write_generic);
}
}
initialize_gpio(ADAPTER_GPIO_IDX_SRST);
initialize_gpio(ADAPTER_GPIO_IDX_LED);
+ bitbang_interface = bcm2835gpio_bitbang;
+
return ERROR_OK;
}
diff --git a/src/rtos/linux.c b/src/rtos/linux.c
index 5467988..5efdc9f 100644
--- a/src/rtos/linux.c
+++ b/src/rtos/linux.c
@@ -1040,6 +1040,10 @@ static int linux_gdb_thread_packet(struct target *target,
return ERROR_TARGET_FAILURE;
char *out_str = calloc(MAX_THREADS * 17 + 10, 1);
+ if (!out_str) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
char *tmp_str = out_str;
tmp_str += sprintf(tmp_str, "m");
struct threads *temp = linux_os->thread_list;
@@ -1116,23 +1120,13 @@ static int linux_thread_extra_info(struct target *target,
while (temp) {
if (temp->threadid == threadid) {
- char *pid = " PID: ";
- char *pid_current = "*PID: ";
- char *name = "Name: ";
- int str_size = strlen(pid) + strlen(name);
- char *tmp_str = calloc(1, str_size + 50);
- char *tmp_str_ptr = tmp_str;
-
- /* discriminate current task */
- if (temp->status == 3)
- tmp_str_ptr += sprintf(tmp_str_ptr, "%s",
- pid_current);
- else
- tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid);
-
- 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 *tmp_str = alloc_printf("%cPID: %" PRIu32 ", Name: %s",
+ temp->status == 3 ? '*' : ' ',
+ temp->pid, temp->name);
+ if (!tmp_str) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
char *hex_str = calloc(1, 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);
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 2bd7d3b..e87e51c 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -370,6 +370,10 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
str_size += strlen(detail->extra_info_str);
char *tmp_str = calloc(str_size + 9, sizeof(char));
+ if (!tmp_str) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
char *tmp_str_ptr = tmp_str;
if (detail->thread_name_str)
diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c
index 42c3ee3..15b9a37 100644
--- a/src/rtt/rtt.c
+++ b/src/rtt/rtt.c
@@ -140,8 +140,8 @@ int rtt_start(void)
addr);
rtt.ctrl.address = addr;
} else {
- LOG_INFO("rtt: No control block found");
- return ERROR_OK;
+ LOG_ERROR("rtt: No control block found");
+ return ERROR_FAIL;
}
}
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index 609965b..ce7808e 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -2857,6 +2857,14 @@ static void aarch64_deinit_target(struct target *target)
struct aarch64_common *aarch64 = target_to_aarch64(target);
struct armv8_common *armv8 = &aarch64->armv8_common;
struct arm_dpm *dpm = &armv8->dpm;
+ uint64_t address;
+
+ if (target->state == TARGET_HALTED) {
+ // Restore the previous state of the target (gp registers, MMU, caches, etc)
+ int retval = aarch64_restore_one(target, true, &address, false, false);
+ if (retval != ERROR_OK)
+ LOG_TARGET_ERROR(target, "Failed to restore target state");
+ }
if (armv8->debug_ap)
dap_put_ap(armv8->debug_ap);
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index 0c7633b..df897b8 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -2367,7 +2367,9 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
return e;
dap = dap_instance_by_jim_obj(goi->interp, o_t);
if (!dap) {
- Jim_SetResultString(goi->interp, "DAP name invalid!", -1);
+ const char *dap_name = Jim_GetString(o_t, NULL);
+ Jim_SetResultFormatted(goi->interp, "DAP '%s' not found",
+ dap_name);
return JIM_ERR;
}
if (*dap_p && *dap_p != dap) {
diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index e22d309..c14155e 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -101,14 +101,14 @@ static int armv7a_read_midr(struct target *target)
armv7a->arch = (midr >> 16) & 0xf;
armv7a->variant = (midr >> 20) & 0xf;
armv7a->implementor = (midr >> 24) & 0xff;
- LOG_DEBUG("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
- ", variant %" PRIx32 ", implementor %" PRIx32,
- target->cmd_name,
- armv7a->rev,
- armv7a->partnum,
- armv7a->arch,
- armv7a->variant,
- armv7a->implementor);
+ LOG_TARGET_DEBUG(target,
+ "rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
+ ", variant %" PRIx32 ", implementor %" PRIx32,
+ armv7a->rev,
+ armv7a->partnum,
+ armv7a->arch,
+ armv7a->variant,
+ armv7a->implementor);
done:
dpm->finish(dpm);
diff --git a/src/target/armv8.c b/src/target/armv8.c
index 50a9f46..4039073 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -1686,12 +1686,12 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
struct arm_reg *armv8_reg = reg->arch_info;
struct target *target = armv8_reg->target;
struct arm *arm = target_to_arm(target);
- uint64_t value = buf_get_u64(buf, 0, reg->size);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
if (reg->size <= 64) {
+ uint64_t value = buf_get_u64(buf, 0, reg->size);
if (reg == arm->cpsr)
armv8_set_cpsr(arm, (uint32_t)value);
else {
@@ -1699,6 +1699,7 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
reg->valid = true;
}
} else if (reg->size <= 128) {
+ uint64_t value = buf_get_u64(buf, 0, 64);
uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64);
buf_set_u64(reg->value, 0, 64, value);
diff --git a/src/target/armv8.h b/src/target/armv8.h
index 49ab3e5..dba12f9 100644
--- a/src/target/armv8.h
+++ b/src/target/armv8.h
@@ -162,6 +162,7 @@ struct armv8_cache_common {
/* l2 external unified cache if some */
void *l2_cache;
int (*flush_all_data_cache)(struct target *target);
+ int (*invalidate_all_instruction_cache)(struct target *target);
int (*display_cache_info)(struct command_invocation *cmd,
struct armv8_cache_common *armv8_cache);
};
diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c
index 66d4e00..1c251be 100644
--- a/src/target/armv8_cache.c
+++ b/src/target/armv8_cache.c
@@ -61,6 +61,7 @@ static int armv8_cache_d_inner_flush_level(struct armv8_common *armv8, struct ar
goto done;
c_way -= 1;
} while (c_way >= 0);
+ keep_alive();
c_index -= 1;
} while (c_index >= 0);
@@ -140,6 +141,36 @@ done:
return retval;
}
+static int armv8_cache_i_inner_clean_inval_all(struct armv8_common *armv8)
+{
+ struct arm_dpm *dpm = armv8->arm.dpm;
+ int retval;
+
+ retval = armv8_i_cache_sanity_check(armv8);
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_DEBUG("flushing cache");
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+
+ retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_ICIALLU));
+ if (retval != ERROR_OK)
+ goto done;
+
+ dpm->finish(dpm);
+ LOG_DEBUG("flushing cache done");
+ return retval;
+
+done:
+ LOG_ERROR("i-cache invalidate failed");
+ dpm->finish(dpm);
+
+ return retval;
+}
+
int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size)
{
struct arm_dpm *dpm = armv8->arm.dpm;
@@ -252,6 +283,32 @@ static int armv8_flush_all_data(struct target *target)
return retval;
}
+static int armv8_flush_all_instruction(struct target *target)
+{
+ int retval = ERROR_FAIL;
+ /* check that armv8_cache is correctly identify */
+ struct armv8_common *armv8 = target_to_armv8(target);
+ if (armv8->armv8_mmu.armv8_cache.info == -1) {
+ LOG_ERROR("trying to flush un-identified cache");
+ return retval;
+ }
+
+ if (target->smp) {
+ /* look if all the other target have been flushed in order to flush icache */
+ struct target_list *head;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
+ if (curr->state == TARGET_HALTED) {
+ LOG_TARGET_INFO(curr, "Wait flushing instruction l1.");
+ retval = armv8_cache_i_inner_clean_inval_all(target_to_armv8(curr));
+ }
+ }
+ } else {
+ retval = armv8_cache_i_inner_clean_inval_all(armv8);
+ }
+ return retval;
+}
+
static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg)
{
struct armv8_common *armv8 = dpm->arm->arch_info;
@@ -411,6 +468,12 @@ int armv8_identify_cache(struct armv8_common *armv8)
armv8->armv8_mmu.armv8_cache.flush_all_data_cache =
armv8_flush_all_data;
}
+ if (!armv8->armv8_mmu.armv8_cache.invalidate_all_instruction_cache) {
+ armv8->armv8_mmu.armv8_cache.display_cache_info =
+ armv8_handle_inner_cache_info_command;
+ armv8->armv8_mmu.armv8_cache.invalidate_all_instruction_cache =
+ armv8_flush_all_instruction;
+ }
done:
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
diff --git a/src/target/armv8_opcodes.c b/src/target/armv8_opcodes.c
index 2635b3e..0f6c810 100644
--- a/src/target/armv8_opcodes.c
+++ b/src/target/armv8_opcodes.c
@@ -41,6 +41,7 @@ static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = {
[ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP(1, 0),
[ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP(1, 0),
[ARMV8_OPC_STRD_IP] = ARMV8_STRD_IP(1, 0),
+ [ARMV8_OPC_ICIALLU] = ARMV8_SYS(SYSTEM_ICIALLU, 0x1F),
};
static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = {
@@ -68,6 +69,7 @@ static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = {
[ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP_T3(1, 0),
[ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP_T3(1, 0),
[ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP_T3(1, 0),
+ [ARMV8_OPC_ICIALLU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 0),
};
void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64)
diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h
index 9200dac..9f18e94 100644
--- a/src/target/armv8_opcodes.h
+++ b/src/target/armv8_opcodes.h
@@ -72,6 +72,8 @@
#define SYSTEM_DCCISW 0x43F2
#define SYSTEM_DCCSW 0x43D2
#define SYSTEM_ICIVAU 0x5BA9
+/* Attention, SYSTEM_ICIALLU requires rt=0x1f */
+#define SYSTEM_ICIALLU 0x03A8
#define SYSTEM_DCCVAU 0x5BD9
#define SYSTEM_DCCIVAC 0x5BF1
@@ -207,6 +209,7 @@ enum armv8_opcode {
ARMV8_OPC_LDRH_IP,
ARMV8_OPC_LDRW_IP,
ARMV8_OPC_LDRD_IP,
+ ARMV8_OPC_ICIALLU,
ARMV8_OPC_NUM,
};
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index b32fec2..9c60645 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -2923,14 +2923,12 @@ static int cortex_a_examine_first(struct target *target)
armv7a->debug_ap->memaccess_tck = 80;
if (!target->dbgbase_set) {
- LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table",
- target->cmd_name);
+ LOG_TARGET_DEBUG(target, "dbgbase is not set, trying to detect using the ROM table");
/* Lookup Processor DAP */
retval = dap_lookup_cs_component(armv7a->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG,
&armv7a->debug_base, target->coreid);
if (retval != ERROR_OK) {
- LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.",
- target->cmd_name);
+ LOG_TARGET_ERROR(target, "Can't detect dbgbase from the ROM table; you need to specify it explicitly");
return retval;
}
LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT,
@@ -2939,8 +2937,9 @@ static int cortex_a_examine_first(struct target *target)
armv7a->debug_base = target->dbgbase;
if ((armv7a->debug_base & (1UL<<31)) == 0)
- LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n"
- "Please fix the target configuration.", target_name(target));
+ LOG_TARGET_WARNING(target,
+ "Debug base address has bit 31 set to 0. Access to debug registers will likely fail!\n"
+ "Please fix the target configuration");
retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DIDR, &didr);
diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c
index 3202fd3..3070960 100644
--- a/src/target/espressif/esp32_apptrace.c
+++ b/src/target/espressif/esp32_apptrace.c
@@ -649,7 +649,7 @@ static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct t
if (res != ERROR_OK)
return res;
if (target->state == TARGET_HALTED) {
- LOG_USER("%s: HALTED", target->cmd_name);
+ LOG_TARGET_USER(target, "HALTED");
break;
}
alive_sleep(500);
diff --git a/src/target/espressif/esp_xtensa_apptrace.c b/src/target/espressif/esp_xtensa_apptrace.c
index 5741ab0..313f6ce 100644
--- a/src/target/espressif/esp_xtensa_apptrace.c
+++ b/src/target/espressif/esp_xtensa_apptrace.c
@@ -277,7 +277,7 @@ static int esp_xtensa_swdbg_activate(struct target *target, int enab)
xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
if (res != ERROR_OK) {
- LOG_ERROR("%s: writing DCR failed!", target->cmd_name);
+ LOG_TARGET_ERROR(target, "writing DCR failed");
return res;
}
diff --git a/src/target/target.c b/src/target/target.c
index b1ec5c2..442e8be 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -31,6 +31,7 @@
#endif
#include <helper/align.h>
+#include <helper/list.h>
#include <helper/nvp.h>
#include <helper/time_support.h>
#include <jtag/jtag.h>
@@ -52,6 +53,13 @@
/* default halt wait timeout (ms) */
#define DEFAULT_HALT_TIMEOUT 5000
+struct target_event_action {
+ enum target_event event;
+ Jim_Interp *interp;
+ Jim_Obj *body;
+ struct list_head list;
+};
+
static int target_read_buffer_default(struct target *target, target_addr_t address,
uint32_t count, uint8_t *buffer);
static int target_write_buffer_default(struct target *target, target_addr_t address,
@@ -2200,12 +2208,11 @@ static void target_destroy(struct target *target)
jtag_unregister_event_callback(jtag_enable_callback, target);
- struct target_event_action *teap = target->event_action;
- while (teap) {
- struct target_event_action *next = teap->next;
+ struct target_event_action *teap, *temp;
+ list_for_each_entry_safe(teap, temp, &target->events_action, list) {
+ list_del(&teap->list);
Jim_DecrRefCount(teap->interp, teap->body);
free(teap);
- teap = next;
}
target_free_all_working_areas(target);
@@ -4431,15 +4438,17 @@ COMMAND_HANDLER(handle_target_read_memory)
return ERROR_COMMAND_ARGUMENT_INVALID;
}
- const unsigned int width = width_bits / 8;
-
- if ((addr + (count * width)) < addr) {
- command_print(CMD, "read_memory: addr + count wraps to zero");
+ if (count > 65536) {
+ command_print(CMD, "too large read request, exceeds 64K elements");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
- if (count > 65536) {
- command_print(CMD, "read_memory: too large read request, exceeds 64K elements");
+ const unsigned int width = width_bits / 8;
+ /* -1 is needed to handle cases when (addr + count * width) results in zero
+ * due to overflow.
+ */
+ if ((addr + count * width - 1) < addr) {
+ command_print(CMD, "memory region wraps over address zero");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
@@ -4466,13 +4475,13 @@ COMMAND_HANDLER(handle_target_read_memory)
retval = target_read_memory(target, addr, width, chunk_len, buffer);
if (retval != ERROR_OK) {
- LOG_DEBUG("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
+ LOG_DEBUG("read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
addr, width_bits, chunk_len);
/*
* FIXME: we append the errmsg to the list of value already read.
* Add a way to flush and replace old output, but LOG_DEBUG() it
*/
- command_print(CMD, "read_memory: failed to read memory");
+ command_print(CMD, "failed to read memory");
free(buffer);
return retval;
}
@@ -4508,50 +4517,36 @@ COMMAND_HANDLER(handle_target_read_memory)
return ERROR_OK;
}
-static int target_jim_write_memory(Jim_Interp *interp, int argc,
- Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_target_write_memory)
{
/*
- * argv[1] = memory address
- * argv[2] = desired element width in bits
- * argv[3] = list of data to write
- * argv[4] = optional "phys"
+ * CMD_ARGV[0] = memory address
+ * CMD_ARGV[1] = desired element width in bits
+ * CMD_ARGV[2] = list of data to write
+ * CMD_ARGV[3] = optional "phys"
*/
- if (argc < 4 || argc > 5) {
- Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']");
- return JIM_ERR;
- }
+ if (CMD_ARGC < 3 || CMD_ARGC > 4)
+ return ERROR_COMMAND_SYNTAX_ERROR;
/* Arg 1: Memory address. */
- int e;
- jim_wide wide_addr;
- e = Jim_GetWide(interp, argv[1], &wide_addr);
-
- if (e != JIM_OK)
- return e;
-
- target_addr_t addr = (target_addr_t)wide_addr;
+ target_addr_t addr;
+ COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr);
/* Arg 2: Bit width of one element. */
- long l;
- e = Jim_GetLong(interp, argv[2], &l);
-
- if (e != JIM_OK)
- return e;
+ unsigned int width_bits;
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits);
- const unsigned int width_bits = l;
- size_t count = Jim_ListLength(interp, argv[3]);
+ /* Arg 3: Elements to write. */
+ size_t count = Jim_ListLength(CMD_CTX->interp, CMD_JIMTCL_ARGV[2]);
/* Arg 4: Optional 'phys'. */
bool is_phys = false;
- if (argc > 4) {
- const char *phys = Jim_GetString(argv[4], NULL);
-
- if (strcmp(phys, "phys")) {
- Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys);
- return JIM_ERR;
+ if (CMD_ARGC == 4) {
+ if (strcmp(CMD_ARGV[3], "phys")) {
+ command_print(CMD, "invalid argument '%s', must be 'phys'", CMD_ARGV[3]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
is_phys = true;
@@ -4564,32 +4559,32 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc,
case 64:
break;
default:
- Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1);
- return JIM_ERR;
+ command_print(CMD, "invalid width, must be 8, 16, 32 or 64");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
- const unsigned int width = width_bits / 8;
-
- if ((addr + (count * width)) < addr) {
- Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1);
- return JIM_ERR;
+ if (count > 65536) {
+ command_print(CMD, "too large memory write request, exceeds 64K elements");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
- if (count > 65536) {
- Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1);
- return JIM_ERR;
+ const unsigned int width = width_bits / 8;
+ /* -1 is needed to handle cases when (addr + count * width) results in zero
+ * due to overflow.
+ */
+ if ((addr + count * width - 1) < addr) {
+ command_print(CMD, "memory region wraps over address zero");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
- struct command_context *cmd_ctx = current_command_context(interp);
- assert(cmd_ctx);
- struct target *target = get_current_target(cmd_ctx);
+ struct target *target = get_current_target(CMD_CTX);
const size_t buffersize = 4096;
uint8_t *buffer = malloc(buffersize);
if (!buffer) {
LOG_ERROR("Failed to allocate memory");
- return JIM_ERR;
+ return ERROR_FAIL;
}
size_t j = 0;
@@ -4599,9 +4594,14 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc,
const size_t chunk_len = MIN(count, max_chunk_len);
for (size_t i = 0; i < chunk_len; i++, j++) {
- Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j);
+ Jim_Obj *tmp = Jim_ListGetIndex(CMD_CTX->interp, CMD_JIMTCL_ARGV[2], j);
jim_wide element_wide;
- Jim_GetWide(interp, tmp, &element_wide);
+ int jimretval = Jim_GetWide(CMD_CTX->interp, tmp, &element_wide);
+ if (jimretval != JIM_OK) {
+ command_print(CMD, "invalid value \"%s\"", Jim_GetString(tmp, NULL));
+ free(buffer);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
const uint64_t v = element_wide;
@@ -4631,11 +4631,11 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc,
retval = target_write_memory(target, addr, width, chunk_len, buffer);
if (retval != ERROR_OK) {
- LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
+ LOG_DEBUG("write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
addr, width_bits, chunk_len);
- Jim_SetResultString(interp, "write_memory: failed to write memory", -1);
- e = JIM_ERR;
- break;
+ command_print(CMD, "failed to write memory");
+ free(buffer);
+ return retval;
}
addr += chunk_len * width;
@@ -4643,7 +4643,7 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc,
free(buffer);
- return e;
+ return ERROR_OK;
}
/* FIX? should we propagate errors here rather than printing them
@@ -4654,7 +4654,7 @@ void target_handle_event(struct target *target, enum target_event e)
struct target_event_action *teap;
int retval;
- for (teap = target->event_action; teap; teap = teap->next) {
+ list_for_each_entry(teap, &target->events_action, list) {
if (teap->event == e) {
LOG_DEBUG("target: %s (%s) event: %d (%s) action: %s",
target_name(target),
@@ -4693,63 +4693,46 @@ void target_handle_event(struct target *target, enum target_event e)
}
}
-static int target_jim_get_reg(Jim_Interp *interp, int argc,
- Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_target_get_reg)
{
- bool force = false;
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
- if (argc == 3) {
- const char *option = Jim_GetString(argv[1], NULL);
+ bool force = false;
+ Jim_Obj *next_argv = CMD_JIMTCL_ARGV[0];
- if (!strcmp(option, "-force")) {
- argc--;
- argv++;
- force = true;
- } else {
- Jim_SetResultFormatted(interp, "invalid option '%s'", option);
- return JIM_ERR;
+ if (CMD_ARGC == 2) {
+ if (strcmp(CMD_ARGV[0], "-force")) {
+ command_print(CMD, "invalid argument '%s', must be '-force'", CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
- }
- if (argc != 2) {
- Jim_WrongNumArgs(interp, 1, argv, "[-force] list");
- return JIM_ERR;
+ force = true;
+ next_argv = CMD_JIMTCL_ARGV[1];
}
- const int length = Jim_ListLength(interp, argv[1]);
-
- Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0);
+ const int length = Jim_ListLength(CMD_CTX->interp, next_argv);
- if (!result_dict)
- return JIM_ERR;
-
- struct command_context *cmd_ctx = current_command_context(interp);
- assert(cmd_ctx);
- const struct target *target = get_current_target(cmd_ctx);
+ const struct target *target = get_current_target(CMD_CTX);
for (int i = 0; i < length; i++) {
- Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i);
-
- if (!elem)
- return JIM_ERR;
+ Jim_Obj *elem = Jim_ListGetIndex(CMD_CTX->interp, next_argv, i);
const char *reg_name = Jim_String(elem);
- struct reg *reg = register_get_by_name(target->reg_cache, reg_name,
- false);
+ struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false);
if (!reg || !reg->exist) {
- Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name);
- return JIM_ERR;
+ command_print(CMD, "unknown register '%s'", reg_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (force || !reg->valid) {
int retval = reg->type->get(reg);
if (retval != ERROR_OK) {
- Jim_SetResultFormatted(interp, "failed to read register '%s'",
- reg_name);
- return JIM_ERR;
+ command_print(CMD, "failed to read register '%s'", reg_name);
+ return retval;
}
}
@@ -4757,27 +4740,15 @@ static int target_jim_get_reg(Jim_Interp *interp, int argc,
if (!reg_value) {
LOG_ERROR("Failed to allocate memory");
- return JIM_ERR;
+ return ERROR_FAIL;
}
- char *tmp = alloc_printf("0x%s", reg_value);
+ command_print(CMD, "%s 0x%s", reg_name, reg_value);
free(reg_value);
-
- if (!tmp) {
- LOG_ERROR("Failed to allocate memory");
- return JIM_ERR;
- }
-
- Jim_DictAddElement(interp, result_dict, elem,
- Jim_NewStringObj(interp, tmp, -1));
-
- free(tmp);
}
- Jim_SetResult(interp, result_dict);
-
- return JIM_OK;
+ return ERROR_OK;
}
COMMAND_HANDLER(handle_set_reg_command)
@@ -4846,7 +4817,7 @@ bool target_has_event_action(const struct target *target, enum target_event even
{
struct target_event_action *teap;
- for (teap = target->event_action; teap; teap = teap->next) {
+ list_for_each_entry(teap, &target->events_action, list) {
if (teap->event == event)
return true;
}
@@ -4966,13 +4937,14 @@ no_params:
{
struct target_event_action *teap;
- teap = target->event_action;
/* replace existing? */
- while (teap) {
+ list_for_each_entry(teap, &target->events_action, list)
if (teap->event == (enum target_event)n->value)
break;
- teap = teap->next;
- }
+
+ /* not found! */
+ if (&teap->list == &target->events_action)
+ teap = NULL;
if (goi->is_configure) {
/* START_DEPRECATED_TPIU */
@@ -4980,6 +4952,17 @@ no_params:
LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name);
/* END_DEPRECATED_TPIU */
+ jim_getopt_obj(goi, &o);
+ if (Jim_Length(o) == 0) {
+ /* empty action, drop existing one */
+ if (teap) {
+ list_del(&teap->list);
+ Jim_DecrRefCount(teap->interp, teap->body);
+ free(teap);
+ }
+ break;
+ }
+
bool replace = true;
if (!teap) {
/* create new */
@@ -4988,7 +4971,6 @@ no_params:
}
teap->event = n->value;
teap->interp = goi->interp;
- jim_getopt_obj(goi, &o);
if (teap->body)
Jim_DecrRefCount(teap->interp, teap->body);
teap->body = Jim_DuplicateObj(goi->interp, o);
@@ -5006,8 +4988,7 @@ no_params:
if (!replace) {
/* add to head of event list */
- teap->next = target->event_action;
- target->event_action = teap;
+ list_add(&teap->list, &target->events_action);
}
Jim_SetEmptyResult(goi->interp);
} else {
@@ -5422,19 +5403,19 @@ COMMAND_HANDLER(handle_target_wait_state)
COMMAND_HANDLER(handle_target_event_list)
{
struct target *target = get_current_target(CMD_CTX);
- struct target_event_action *teap = target->event_action;
+ struct target_event_action *teap;
command_print(CMD, "Event actions for target %s\n",
target_name(target));
command_print(CMD, "%-25s | Body", "Event");
command_print(CMD, "------------------------- | "
"----------------------------------------");
- while (teap) {
+
+ list_for_each_entry(teap, &target->events_action, list)
command_print(CMD, "%-25s | %s",
target_event_name(teap->event),
Jim_GetString(teap->body, NULL));
- teap = teap->next;
- }
+
command_print(CMD, "***END***");
return ERROR_OK;
}
@@ -5569,9 +5550,9 @@ static const struct command_registration target_instance_command_handlers[] = {
{
.name = "get_reg",
.mode = COMMAND_EXEC,
- .jim_handler = target_jim_get_reg,
+ .handler = handle_target_get_reg,
.help = "Get register values from the target",
- .usage = "list",
+ .usage = "[-force] list",
},
{
.name = "set_reg",
@@ -5590,7 +5571,7 @@ static const struct command_registration target_instance_command_handlers[] = {
{
.name = "write_memory",
.mode = COMMAND_EXEC,
- .jim_handler = target_jim_write_memory,
+ .handler = handle_target_write_memory,
.help = "Write Tcl list of 8/16/32/64 bit numbers to target memory",
.usage = "address width data ['phys']",
},
@@ -5787,6 +5768,8 @@ static int target_create(struct jim_getopt_info *goi)
target->halt_issued = false;
+ INIT_LIST_HEAD(&target->events_action);
+
/* initialize trace information */
target->trace_info = calloc(1, sizeof(struct trace));
if (!target->trace_info) {
@@ -5807,6 +5790,16 @@ static int target_create(struct jim_getopt_info *goi)
target->gdb_port_override = NULL;
target->gdb_max_connections = 1;
+ cp = Jim_GetString(new_cmd, NULL);
+ target->cmd_name = strdup(cp);
+ if (!target->cmd_name) {
+ LOG_ERROR("Out of memory");
+ free(target->trace_info);
+ free(target->type);
+ free(target);
+ return JIM_ERR;
+ }
+
/* Do the rest as "configure" options */
goi->is_configure = true;
e = target_configure(goi, target);
@@ -5843,19 +5836,6 @@ static int target_create(struct jim_getopt_info *goi)
target->endianness = TARGET_LITTLE_ENDIAN;
}
- cp = Jim_GetString(new_cmd, NULL);
- target->cmd_name = strdup(cp);
- if (!target->cmd_name) {
- LOG_ERROR("Out of memory");
- rtos_destroy(target);
- free(target->gdb_port_override);
- free(target->trace_info);
- free(target->type);
- free(target->private_config);
- free(target);
- return JIM_ERR;
- }
-
if (target->type->target_create) {
e = (*(target->type->target_create))(target, goi->interp);
if (e != ERROR_OK) {
@@ -6707,9 +6687,9 @@ static const struct command_registration target_exec_command_handlers[] = {
{
.name = "get_reg",
.mode = COMMAND_EXEC,
- .jim_handler = target_jim_get_reg,
+ .handler = handle_target_get_reg,
.help = "Get register values from the target",
- .usage = "list",
+ .usage = "[-force] list",
},
{
.name = "set_reg",
@@ -6728,7 +6708,7 @@ static const struct command_registration target_exec_command_handlers[] = {
{
.name = "write_memory",
.mode = COMMAND_EXEC,
- .jim_handler = target_jim_write_memory,
+ .handler = handle_target_write_memory,
.help = "Write Tcl list of 8/16/32/64 bit numbers to target memory",
.usage = "address width data ['phys']",
},
diff --git a/src/target/target.h b/src/target/target.h
index 33aba09..d16c3a0 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -142,7 +142,7 @@ struct target {
*/
bool running_alg;
- struct target_event_action *event_action;
+ struct list_head events_action;
bool reset_halt; /* attempt resetting the CPU into the halted mode? */
target_addr_t working_area; /* working area (initialised RAM). Evaluated
@@ -301,13 +301,6 @@ enum target_event {
TARGET_EVENT_SEMIHOSTING_USER_CMD_0X107 = 0x107,
};
-struct target_event_action {
- enum target_event event;
- Jim_Interp *interp;
- Jim_Obj *body;
- struct target_event_action *next;
-};
-
bool target_has_event_action(const struct target *target, enum target_event event);
struct target_event_callback {
diff --git a/src/transport/transport.c b/src/transport/transport.c
index c7293e7..0af1360 100644
--- a/src/transport/transport.c
+++ b/src/transport/transport.c
@@ -166,54 +166,6 @@ struct transport *get_current_transport(void)
* Infrastructure for Tcl interface to transports.
*/
-/**
- * Makes and stores a copy of a set of transports passed as
- * parameters to a command.
- *
- * @param vector where the resulting copy is stored, as an argv-style
- * NULL-terminated vector.
- */
-COMMAND_HELPER(transport_list_parse, char ***vector)
-{
- char **argv;
- unsigned int n = CMD_ARGC;
- unsigned int j = 0;
-
- *vector = NULL;
-
- if (n < 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- /* our return vector must be NULL terminated */
- argv = calloc(n + 1, sizeof(char *));
- if (!argv)
- return ERROR_FAIL;
-
- for (unsigned int i = 0; i < n; i++) {
- struct transport *t;
-
- for (t = transport_list; t; t = t->next) {
- if (strcmp(t->name, CMD_ARGV[i]) != 0)
- continue;
- argv[j++] = strdup(CMD_ARGV[i]);
- break;
- }
- if (!t) {
- LOG_ERROR("no such transport '%s'", CMD_ARGV[i]);
- goto fail;
- }
- }
-
- *vector = argv;
- return ERROR_OK;
-
-fail:
- for (unsigned int i = 0; i < n; i++)
- free(argv[i]);
- free(argv);
- return ERROR_FAIL;
-}
-
COMMAND_HANDLER(handle_transport_init)
{
LOG_DEBUG("%s", __func__);
diff --git a/src/transport/transport.h b/src/transport/transport.h
index 00d8b07..2e3dcc6 100644
--- a/src/transport/transport.h
+++ b/src/transport/transport.h
@@ -77,8 +77,6 @@ struct transport *get_current_transport(void);
int transport_register_commands(struct command_context *ctx);
-COMMAND_HELPER(transport_list_parse, char ***vector);
-
int allow_transports(struct command_context *ctx, const char * const *vector);
bool transport_is_jtag(void);
diff --git a/tcl/board/ti_am261_launchpad.cfg b/tcl/board/ti_am261_launchpad.cfg
new file mode 100644
index 0000000..c6c4609
--- /dev/null
+++ b/tcl/board/ti_am261_launchpad.cfg
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2025 Texas Instruments Incorporated - https://www.ti.com/
+#
+# Texas Instruments AM261 Launchpad
+# https://www.ti.com/tool/LP-AM261
+#
+
+# AM263 Launchpad has an xds110 onboard.
+source [find interface/xds110.cfg]
+
+transport select jtag
+
+# default JTAG configuration has only SRST and no TRST
+reset_config srst_only srst_push_pull
+
+# delay after SRST goes inactive
+adapter srst delay 20
+
+if { ![info exists SOC] } {
+ set SOC am261
+}
+
+source [find target/ti_k3.cfg]
+
+adapter speed 250
diff --git a/tcl/board/ti_am263p_launchpad.cfg b/tcl/board/ti_am263p_launchpad.cfg
new file mode 100644
index 0000000..96e06fa
--- /dev/null
+++ b/tcl/board/ti_am263p_launchpad.cfg
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2025 Texas Instruments Incorporated - https://www.ti.com/
+#
+# Texas Instruments AM263P Launchpad
+# https://www.ti.com/tool/LP-AM263P
+#
+
+# AM263P Launchpad has an xds110 onboard.
+source [find interface/xds110.cfg]
+
+transport select jtag
+
+# default JTAG configuration has only SRST and no TRST
+reset_config srst_only srst_push_pull
+
+# delay after SRST goes inactive
+adapter srst delay 20
+
+if { ![info exists SOC] } {
+ set SOC am263p
+}
+
+source [find target/ti_k3.cfg]
+
+adapter speed 250
diff --git a/tcl/board/ti_am62levm.cfg b/tcl/board/ti_am62levm.cfg
new file mode 100644
index 0000000..6debdd4
--- /dev/null
+++ b/tcl/board/ti_am62levm.cfg
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2025 Texas Instruments Incorporated - https://www.ti.com/
+#
+# Texas Instruments AM62L EVM:
+# Links: https://www.ti.com/tool/TMDS62LEVM
+#
+
+# the AM62L3 EVM/SK has an xds110 onboard.
+source [find interface/xds110.cfg]
+
+transport select jtag
+
+# default JTAG configuration has only SRST and no TRST
+reset_config srst_only srst_push_pull
+
+# delay after SRST goes inactive
+adapter srst delay 20
+
+if { ![info exists SOC] } {
+ set SOC am62l
+}
+
+source [find target/ti_k3.cfg]
+
+adapter speed 2500
diff --git a/tcl/board/ti_mspm0_launchpad.cfg b/tcl/board/ti_mspm0_launchpad.cfg
new file mode 100644
index 0000000..132fdc2
--- /dev/null
+++ b/tcl/board/ti_mspm0_launchpad.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2023-2025 Texas Instruments Incorporated - https://www.ti.com/
+#
+# TI MSPM0L1306 LaunchPad Evaluation Kit
+# https://www.ti.com/tool/LP-MSPM0L1306
+# TI MSPM0C1104 LaunchPad Evaluation Kit
+# https://www.ti.com/tool/LP-MSPM0C1104
+# TI MSPM0G3507 LaunchPad Evaluation Kit
+# https://www.ti.com/tool/LP-MSPM0G3507
+#
+
+source [find interface/xds110.cfg]
+adapter speed 10000
+source [find target/ti_mspm0.cfg]
diff --git a/tcl/target/ngultra.cfg b/tcl/target/ngultra.cfg
index 956fdbb..9f9814f 100644
--- a/tcl/target/ngultra.cfg
+++ b/tcl/target/ngultra.cfg
@@ -36,12 +36,11 @@ dap create $_CHIPNAME.coresight.dap -chain-position $_CHIPNAME.coresight.cpu
for { set _core 0 } { $_core < $_cores } { incr _core } {
cti create cti.$_core -dap $_CHIPNAME.coresight.dap -ap-num 0 \
-baseaddr [lindex $CTIBASE $_core]
-# Cores are armv8-r but works with aarch64 (since armv8-r not directly supported by openocd yet).
if { $_core == 0} {
- target create core.$_core aarch64 -dap $_CHIPNAME.coresight.dap \
+ target create core.$_core armv8r -dap $_CHIPNAME.coresight.dap \
-ap-num 0 -dbgbase [lindex $DBGBASE $_core] -cti cti.$_core
} else {
- target create core.$_core aarch64 -dap $_CHIPNAME.coresight.dap \
+ target create core.$_core armv8r -dap $_CHIPNAME.coresight.dap \
-ap-num 0 -dbgbase [lindex $DBGBASE $_core] -cti cti.$_core -defer-examine
}
}
diff --git a/tcl/target/nordic/nrf54l.cfg b/tcl/target/nordic/nrf54l.cfg
index 70ead13..3e14055 100644
--- a/tcl/target/nordic/nrf54l.cfg
+++ b/tcl/target/nordic/nrf54l.cfg
@@ -27,18 +27,35 @@ if { [info exists CPUTAPID] } {
set _CPUTAPID 0x6ba02477
}
+# Multidrop instance ID should be configurable by FW in TAD TINSTANCE register.
+# Writes to the register are ignored due to a silicon erratum.
+if { [info exists SWD_INSTANCE_ID] } {
+ set _SWD_INSTANCE_ID $SWD_INSTANCE_ID
+} else {
+ set _SWD_INSTANCE_ID 0
+}
+
transport select swd
swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
-dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+if { [info exists SWD_MULTIDROP] } {
+ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -dp-id 0x001c0289 -instance-id $_SWD_INSTANCE_ID
+} else {
+ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+}
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap -ap-num 0
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
-# Create target for the control access port (CTRL-AP).
-target create $_CHIPNAME.ctrl mem_ap -dap $_CHIPNAME.dap -ap-num 1
+# Create target for the AUX access port (AUX-AP).
+target create $_CHIPNAME.aux mem_ap -dap $_CHIPNAME.dap -ap-num 1
+
+# AUX-AP is accessible only if CSW Prot[0] bit (Data Access) is set
+$_CHIPNAME.dap apsel 1
+$_CHIPNAME.dap apcsw 0x01000000 0x01000000
adapter speed 1000
diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg
index 73b3003..f6bc5e4 100644
--- a/tcl/target/renesas_rcar_gen3.cfg
+++ b/tcl/target/renesas_rcar_gen3.cfg
@@ -90,6 +90,18 @@ switch $_soc {
set _num_cr52 1
set _boot_core CA76
}
+ V4H {
+ set _CHIPNAME r8a779g0
+ set _num_ca76 4
+ set _num_cr52 3
+ set _boot_core CR52
+ }
+ V4M {
+ set _CHIPNAME r8a779h0
+ set _num_ca76 4
+ set _num_cr52 3
+ set _boot_core CR52
+ }
default {
error "'$_soc' is invalid!"
}
@@ -126,8 +138,8 @@ set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000}
set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000}
set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000}
set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000}
-set CR52_DBGBASE 0x80c10000
-set CR52_CTIBASE 0x80c20000
+set CR52_DBGBASE {0x80C10000 0x80D10000 0x80E10000}
+set CR52_CTIBASE {0x80C20000 0x80D20000 0x80E20000}
set CR7_DBGBASE 0x80910000
set CR7_CTIBASE 0x80918000
@@ -159,24 +171,27 @@ proc setup_a5x {core_name dbgbase ctibase num boot} {
proc setup_crx {core_name dbgbase ctibase num boot} {
global _CHIPNAME
global _DAPNAME
+ global smp_targets
global _targets
for { set _core 0 } { $_core < $num } { incr _core } {
- set _TARGETNAME $_CHIPNAME.$core_name
+ set _TARGETNAME $_CHIPNAME.$core_name.$_core
set _CTINAME $_TARGETNAME.cti
- cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase
+ cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr [lindex $ctibase $_core]
if { $core_name == "r52" } {
set _command "target create $_TARGETNAME armv8r -dap $_DAPNAME \
- -ap-num 1 -dbgbase $dbgbase -cti $_CTINAME"
+ -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME"
} else {
set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \
- -ap-num 1 -dbgbase $dbgbase"
+ -ap-num 1 -dbgbase [lindex $dbgbase $_core]"
}
- if { $boot == 1 } {
+ if { $_core == 0 && $boot == 1 } {
set _targets "$_TARGETNAME"
} else {
set _command "$_command -defer-examine"
}
+ set smp_targets "$smp_targets $_TARGETNAME"
eval $_command
+ $_TARGETNAME configure -event examine-end { halt }
}
}
diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg
index 2ae0f75..0dee74e 100644
--- a/tcl/target/ti_k3.cfg
+++ b/tcl/target/ti_k3.cfg
@@ -4,8 +4,12 @@
# Texas Instruments K3 devices:
# * AM243: https://www.ti.com/lit/pdf/spruim2
# Has 4 R5 Cores, M4F and an M3
+# * AM261: https://www.ti.com/lit/pdf/sprujb6
+# Has 2 R5 Cores and an M4F
# * AM263: https://www.ti.com/lit/pdf/spruj17
# Has 4 R5 Cores and an M3
+# * AM263P: https://www.ti.com/lit/pdf/spruj55
+# Has 4 R5 Cores and an M4F
# * AM273: https://www.ti.com/lit/pdf/spruiu0
# Has 2 R5 Cores and an M3
# * AM625: https://www.ti.com/lit/pdf/spruiv7a
@@ -14,6 +18,8 @@
# Has 4 ARMV8 Cores and 2 R5 Cores
# * AM62P: https://www.ti.com/lit/pdf/spruj83
# Has 4 ARMV8 Cores and 2 R5 Cores
+# * AM62L: https://www.ti.com/lit/pdf/sprujb4
+# Has 2 ARMv8 Cores only
# * AM642: https://www.ti.com/lit/pdf/spruim2
# Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3
# * AM654x: https://www.ti.com/lit/pdf/spruid7
@@ -77,8 +83,16 @@ set _gp_mcu_ap_unlock_offsets {0xf0 0x60}
# Generic mem-ap port number
set _mem_ap_num 2
+# Generic AP_SEL PWR Register number
+set _power_ap_num 3
+
+# Generic SPREC RESET BANK and Field number
+set _powerap_sprec_reset 0xf0
+
# Set configuration overrides for each SOC
switch $_soc {
+ am261 -
+ am263p -
am263 {
set _K3_DAP_TAPID 0x2bb7d02f
@@ -94,6 +108,16 @@ switch $_soc {
set R5_DBGBASE {0x90030000 0x90032000 0x90050000 0x90052000}
set R5_CTIBASE {0x90038000 0x90039000 0x90058000 0x90059000}
set _r5_ap_num 5
+
+ set _power_ap_num 7
+
+ if { "$_soc" == "am263p" } {
+ set _K3_DAP_TAPID 0x1bb9502f
+ }
+ if { "$_soc" == "am261" } {
+ set _K3_DAP_TAPID 0x1bba602f
+ set _r5_cores 2
+ }
}
am273 {
set _K3_DAP_TAPID 0x1bb6a02f
@@ -233,6 +257,18 @@ switch $_soc {
set R5_CTIBASE {0x9d418000 0x9d518000 0x9d818000}
}
}
+ am62l {
+ set _K3_DAP_TAPID 0x0bba702f
+
+ # AM62Lx has 1 cluster of 2 A53 cores.
+ set _armv8_cpu_name a53
+ set _armv8_cores 2
+ set ARMV8_DBGBASE {0x90010000 0x90110000}
+ set ARMV8_CTIBASE {0x90020000 0x90120000}
+
+ # Has no supporting microcontrollers
+ set _r5_cores 0
+ }
j721e {
set _K3_DAP_TAPID 0x0bb6402f
# J721E has 1 cluster of 2 A72 cores.
@@ -499,3 +535,10 @@ if { 0 == [string compare [adapter name] dmem ] } {
# AXI AP access port for SoC address map
target create $_CHIPNAME.axi_ap mem_ap -dap $_CHIPNAME.dap -ap-num $_mem_ap_num
}
+
+# Reset system using (Debug Reset) SPREC Register,SYSTEMRESET bit field via apreg
+proc dbg_sys_reset {} {
+ $::_CHIPNAME.dap apreg $::_power_ap_num $::_powerap_sprec_reset 0x1
+}
+
+add_help_text dbg_sys_reset "Debugger initiated system reset attempt via Power-AP"
diff --git a/tcl/target/ti_mspm0.cfg b/tcl/target/ti_mspm0.cfg
new file mode 100644
index 0000000..4e9b89c
--- /dev/null
+++ b/tcl/target/ti_mspm0.cfg
@@ -0,0 +1,199 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2023-2025 Texas Instruments Incorporated - https://www.ti.com/
+#
+# Texas Instruments MSPM0L/G - ARM Cortex-M0 @ 32MHz
+# https://www.ti.com/microcontrollers-mcus-processors/arm-based-microcontrollers/arm-cortex-m0-mcus/overview.html
+#
+
+source [find bitsbytes.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ # Meant to work with MSPM0L and MSPM0G class of devices.
+ set _CHIPNAME mspm0x
+}
+
+if { [info exists CPUTAPID] } {
+ set _DAP_TAPID $CPUTAPID
+} else {
+ set _DAP_TAPID 0x4ba00477
+}
+
+if { [info exists DAP_SWD_ID] } {
+ set _DAP_SWD_ID $DAP_SWD_ID
+} else {
+ set _DAP_SWD_ID 0x2ba01477
+}
+
+source [find target/swj-dp.tcl]
+
+# MSPM0 only supports swd, so set it here and save a line for custom boards
+transport select swd
+
+set _DAP_ID $_DAP_SWD_ID
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
+
+if { [info exists WORKAREABASE] } {
+ set _WORKAREABASE $WORKAREABASE
+} else {
+ set _WORKAREABASE 0x20000000
+}
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ # Smallest SRAM size is 1K SRAM.
+ set _WORKAREASIZE 0x400
+}
+
+#
+# MSPM0 Debug SubSystem Mailbox (DSSM) Communication helpers
+#
+
+proc _mspm0_wait_for_dssm_response {command} {
+ # Wait for SECAP::RCR rx_valid to be set
+ set timeout 1000
+ while { [expr { [$::_CHIPNAME.dap apreg 2 0xc] & 0x1}] != 0x1 } {
+ sleep 1
+ set timeout [expr {$timeout - 1}]
+ if { $timeout == 0 } {
+ set rcr [$::_CHIPNAME.dap apreg 2 0xc]
+ return -code error [format "MSPM0 SECAP RCR=0x%08x timeout rx_valid" $rcr]
+ }
+ }
+
+ # Read SECAP::RXD to clear the RX_VALID bit
+ set rxd [$::_CHIPNAME.dap apreg 2 0x8]
+ # Read SECAP::RCR
+ set rcr [$::_CHIPNAME.dap apreg 2 0xc]
+
+ # Check if we got successful response. This is denoted as:
+ # 8 LSBits of $command should matchup with SECAP::RCR
+ # and
+ # SECAP::RXD should be 0x10003
+ if { ([expr { $command & 0xff}] == $rcr) && ($rxd == 0x10003) } {
+ return 0
+ }
+
+ # Provide some debug log for users to report back if CMD fails.
+ return -code error [format "MSPM0 SECAP CMD FAIL! RXD: 0x%08X RCR: 0x%08X" $rxd $rcr]
+}
+
+proc _mspm0_dssm_command {command} {
+ # SECAP::TCR = command
+ $::_CHIPNAME.dap apreg 2 0x4 $command
+ # SECAP::TDR = 0x0
+ $::_CHIPNAME.dap apreg 2 0x0 0x0
+ # Read SECAP::RCR and RXD to clear up any prev pending reads
+ set rxd [$::_CHIPNAME.dap apreg 2 0x8]
+ set rcr [$::_CHIPNAME.dap apreg 2 0xc]
+ # Make sure everything is synced
+ sleep 1000
+ # Trigger nRST
+ mspm0_board_reset
+
+ # Wait for ROM to do it's magic and respond back
+ set res [_mspm0_wait_for_dssm_response $command]
+ if { $res } {
+ return $res
+ }
+ # Paranoid.. make sure ROM does what it is meant to do
+ # RX valid should have been cleared after the operation is
+ # complete
+ sleep 1000
+
+ # Trigger nRST to get back to sane system
+ mspm0_board_reset
+ sleep 1000
+
+ return 0
+}
+
+# NOTE: Password authentication scheme is NOT supported atm.
+# mspm0_factory_reset: Factory reset the board
+proc mspm0_factory_reset {} {
+ set res [_mspm0_dssm_command 0x020a]
+ if { $res } {
+ echo "Factory Reset failed!"
+ } else {
+ echo "Factory reset success! Halting processor"
+ # We need to halt the processor else the WDT fires!
+ halt
+ }
+ return $res
+}
+
+add_help_text mspm0_factory_reset "Force Factory reset to recover 'bricked' board"
+
+# NOTE: Password authentication scheme is NOT supported atm.
+# mspm0_mass_erase: Mass erase flash
+proc mspm0_mass_erase {} {
+ set res [_mspm0_dssm_command 0x020c]
+ if { $res } {
+ echo "Mass Erase failed!"
+ } else {
+ echo "Mass Erase success! Halting Processor"
+ # We need to halt the processor else the WDT fires!
+ halt
+ }
+ return $res
+}
+
+add_help_text mspm0_mass_erase "Mass erase flash"
+
+# mspm0_start_bootloader: Ask explicitly for bootloader startup
+proc mspm0_start_bootloader {} {
+ set res [_mspm0_dssm_command 0x0108]
+ if { $res } {
+ echo "Start BL failed!"
+ }
+ return $res
+}
+
+add_help_text mspm0_start_bootloader "Ask explicitly for bootloader startup"
+
+# MSPM0 requires board level NRST reset to be toggled for
+# Factory reset operations to function.
+# However this cannot be the default configuration as this
+# prevents reset init reset halt to function properly
+# since the Debug Subsystem (debugss) logic or coresight
+# seems impacted by nRST.
+# This can be overridden in board file as required.
+#
+# mspm0_board_reset: Board level reset
+proc mspm0_board_reset {} {
+ set user_reset_config [reset_config]
+ reset_config srst_only
+ set errno [catch {reset}]
+ eval reset_config $user_reset_config
+ if {$errno} {error}
+}
+
+add_help_text mspm0_board_reset "Request a board level reset"
+
+# If the flash is empty or the device is already in low-power state, then
+# debug access is not available. to handle this, explicitly control power ap
+# to provide access. Refer to Technical Reference Manual for further info.
+proc _mspm0_enable_low_power_mode { } {
+ # PWR_AP::DPREC <= FRCACT(3)=1, RST_CTL(14:16)=1, IHIB_SLP(20)=1
+ $::_CHIPNAME.dap apreg 4 0x00 0x104008
+ # PWR_AP::SPREC <= SYSRST=1
+ $::_CHIPNAME.dap apreg 4 0xF0 0x01
+ # PWR_AP::DPREC <= FRCACT(3)=1, IHIB_SLP(20)=1
+ $::_CHIPNAME.dap apreg 4 0x00 0x100008
+}
+
+$_TARGETNAME configure -event examine-start { _mspm0_enable_low_power_mode }
+$_TARGETNAME configure -work-area-phys $_WORKAREABASE -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME.main mspm0 0 0 0 0 $_TARGETNAME
+flash bank $_FLASHNAME.nonmain mspm0 0x41c00000 0 0 0 $_TARGETNAME
+flash bank $_FLASHNAME.data mspm0 0x41d00000 0 0 0 $_TARGETNAME
+
+cortex_m reset_config sysresetreq
diff --git a/tools/scripts/camelcase.txt b/tools/scripts/camelcase.txt
index b787902..6c6c28d 100644
--- a/tools/scripts/camelcase.txt
+++ b/tools/scripts/camelcase.txt
@@ -122,6 +122,7 @@ Jim_GetWide
Jim_IncrRefCount
Jim_InitStaticExtensions
Jim_Interp
+Jim_Length
Jim_ListAppendElement
Jim_ListGetIndex
Jim_ListLength