diff --git a/NEWS-0.5.0 b/NEWS-0.5.0
index add6c1e90..90ea35c41 100644
--- a/NEWS-0.5.0
+++ b/NEWS-0.5.0
@@ -71,4 +71,3 @@ For older NEWS, see the NEWS files associated with each release
For more information about contributing test reports, bug fixes, or new
features and device support, please read the new Developer Manual (or
the BUGS and PATCHES.txt files in the source archive).
-
diff --git a/README b/README
index f957bc07d..2d8c50115 100644
--- a/README
+++ b/README
@@ -277,7 +277,7 @@ e.g. for cross-building for Windows 32-bit with MinGW on Debian:
To make pkg-config work nicely for cross-compiling, you might need an
additional wrapper script as described at
- http://www.flameeyes.eu/autotools-mythbuster/pkgconfig/cross-compiling.html
+ https://autotools.io/pkgconfig/cross-compiling.html
This is needed to tell pkg-config where to look for the target
libraries that OpenOCD depends on. Alternatively, you can specify
diff --git a/TODO b/TODO
index 350aaa274..ebb6c9980 100644
--- a/TODO
+++ b/TODO
@@ -37,11 +37,33 @@ This section provides possible things to improve with OpenOCD's TCL support.
- See src/jtag/core.c and src/jtag/tcl.c for an example.
- allow some of these TCL command modules to be dynamically loadable?
-@section thelistjtag JTAG
+@section thelistadapter Adapter
-This section list issues that need to be resolved in the JTAG layer.
+This section list issues that need to be resolved in the Adapter layer.
-@subsection thelistjtagcore JTAG Core
+@subsection thelistadapterrework Code restructuring
+
+This section lists pending reworks to complete the restructure from the
+old JTAG centric implementation to a generic Adapter layer.
+This restructuring is very invasive and will prevent the merge of several
+changes pending in gerrit.
+
+- rename folder src/jtag/ to src/adapter/
+- rename var "jtag" to "adapter" in src/jtag/core.c
+- split content of src/adapter/ in the different protocols jtag.[ch],
+ swd.[ch], ...
+- wrap the calls to adapter->transport_ops->api() with transport_api()
+ and reduce the visibility of global var "adapter"
+- complete the migration of JTAG-only drivers to adapter->reset()
+- try to remove JTAG_SLEEP also from JTAG mode?
+- tap_set_state(TAP_RESET) is already done in src/jtag/core.c. No need
+ to replicate it in the drivers, apart in case the driver sets TRST
+ independently
+- add .hla_ops to "adapter"
+- HLA is a API level (.hla_ops). Transport should simply be {jtag,swd},
+ not {hla_jtag,hla_swd}.
+
+@subsection thelistadapterjtagcore JTAG Core
The following tasks have been suggested for cleaning up the JTAG layer:
@@ -63,9 +85,9 @@ The following tasks have been suggested for adding new core JTAG support:
- (ab)use bit-banging JTAG interfaces to emulate SPI/UART
- allow SPI to program flash, MCUs, etc.
-@subsection thelistjtaginterfaces JTAG Interfaces
+@subsection thelistadapterinterfaces Interface drivers
-There are some known bugs to fix in JTAG adapter drivers:
+There are some known bugs to fix in Interface drivers:
- For JTAG_STATEMOVE to TAP_RESET, all drivers must ignore the current
recorded state. The tap_get_state() call won't necessarily return
@@ -107,10 +129,6 @@ of a minidriver is required to capture all the jtag_add_xxx()
fn's at a high enough level and repackage these cmd's as
TCP/IP packets handled by the server.
-@section thelistswd Serial Wire Debug
-
-- implement Serial Wire Debug interface
-
@section thelistbs Boundary Scan Support
- add STAPL support?
@@ -373,4 +391,3 @@ to complete:
/** @file
This file contains the @ref thelist page.
*/
-
diff --git a/configure.ac b/configure.ac
index c151e1fba..b29ab0771 100644
--- a/configure.ac
+++ b/configure.ac
@@ -117,10 +117,8 @@ m4_define([USB1_ADAPTERS],
[[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]],
[[ft232r], [Bitbang mode of FT232R based devices], [FT232R]],
[[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]],
- [[xds110], [TI XDS110 Debug Probe], [XDS110]]])
-
-m4_define([USB_ADAPTERS],
- [[[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],
+ [[xds110], [TI XDS110 Debug Probe], [XDS110]],
+ [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],
[[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]],
[[aice], [Andes JTAG Programmer], [AICE]]])
@@ -143,6 +141,9 @@ m4_define([LIBFTDI_ADAPTERS],
m4_define([LIBJAYLINK_ADAPTERS],
[[[jlink], [SEGGER J-Link Programmer], [JLINK]]])
+m4_define([PCIE_ADAPTERS],
+ [[[xlnx_pcie_xvc], [Xilinx XVC/PCIe], [XLNX_PCIE_XVC]]])
+
AC_ARG_ENABLE([doxygen-html],
AS_HELP_STRING([--disable-doxygen-html],
@@ -222,6 +223,10 @@ AC_ARG_ENABLE([dummy],
AS_HELP_STRING([--enable-dummy], [Enable building the dummy port driver]),
[build_dummy=$enableval], [build_dummy=no])
+AC_ARG_ENABLE([rshim],
+ AS_HELP_STRING([--enable-rshim], [Enable building the rshim driver]),
+ [build_rshim=$enableval], [build_rshim=no])
+
m4_define([AC_ARG_ADAPTERS], [
m4_foreach([adapter], [$1],
[AC_ARG_ENABLE(ADAPTER_OPT([adapter]),
@@ -233,7 +238,6 @@ m4_define([AC_ARG_ADAPTERS], [
AC_ARG_ADAPTERS([
USB1_ADAPTERS,
- USB_ADAPTERS,
USB0_ADAPTERS,
HIDAPI_ADAPTERS,
HIDAPI_USB1_ADAPTERS,
@@ -276,15 +280,7 @@ AC_ARG_ENABLE([ioutil],
[build_ioutil=$enableval], [build_ioutil=no])
AS_CASE(["${host_cpu}"],
- [arm*], [
- AC_ARG_ENABLE([ep93xx],
- AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]),
- [build_ep93xx=$enableval], [build_ep93xx=no])
-
- AC_ARG_ENABLE([at91rm9200],
- AS_HELP_STRING([--enable-at91rm9200], [Enable building support for AT91RM9200 based SBCs]),
- [build_at91rm9200=$enableval], [build_at91rm9200=no])
-
+ [arm*|aarch64], [
AC_ARG_ENABLE([bcm2835gpio],
AS_HELP_STRING([--enable-bcm2835gpio], [Enable building support for bitbanging on BCM2835 (as found in Raspberry Pi)]),
[build_bcm2835gpio=$enableval], [build_bcm2835gpio=no])
@@ -293,12 +289,25 @@ AS_CASE(["${host_cpu}"],
[build_imx_gpio=$enableval], [build_imx_gpio=no])
],
[
- build_ep93xx=no
- build_at91rm9200=no
build_bcm2835gpio=no
build_imx_gpio=no
])
+AS_CASE(["${host_cpu}"],
+ [arm*], [
+ AC_ARG_ENABLE([ep93xx],
+ AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]),
+ [build_ep93xx=$enableval], [build_ep93xx=no])
+
+ AC_ARG_ENABLE([at91rm9200],
+ AS_HELP_STRING([--enable-at91rm9200], [Enable building support for AT91RM9200 based SBCs]),
+ [build_at91rm9200=$enableval], [build_at91rm9200=no])
+ ],
+ [
+ build_ep93xx=no
+ build_at91rm9200=no
+])
+
AC_ARG_ENABLE([gw16012],
AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]),
[build_gw16012=$enableval], [build_gw16012=no])
@@ -316,12 +325,27 @@ AC_ARG_ENABLE([sysfsgpio],
AS_HELP_STRING([--enable-sysfsgpio], [Enable building support for programming driven via sysfs gpios.]),
[build_sysfsgpio=$enableval], [build_sysfsgpio=no])
+AC_ARG_ENABLE([xlnx_pcie_xvc],
+ AS_HELP_STRING([--enable-xlnx-pcie-xvc], [Enable building support for Xilinx XVC/PCIe.]),
+ [build_xlnx_pcie_xvc=$enableval], [build_xlnx_pcie_xvc=no])
+
AS_CASE([$host_os],
[linux*], [],
[
AS_IF([test "x$build_sysfsgpio" = "xyes"], [
AC_MSG_ERROR([sysfsgpio is only available on linux])
])
+
+ AS_IF([test "x$build_xlnx_pcie_xvc" = "xyes"], [
+ AC_MSG_ERROR([xlnx_pcie_xvc is only available on linux])
+ ])
+
+ AS_CASE([$host_os], [freebsd*], [],
+ [
+ AS_IF([test "x$build_rshim" = "xyes"], [
+ AC_MSG_ERROR([build_rshim is only available on linux or freebsd])
+ ])
+ ])
])
AC_ARG_ENABLE([minidriver_dummy],
@@ -337,10 +361,6 @@ AC_ARG_ENABLE([internal-libjaylink],
[Disable building internal libjaylink]),
[use_internal_libjaylink=$enableval], [use_internal_libjaylink=yes])
-AC_ARG_ENABLE([target64],
- AS_HELP_STRING([--disable-target64], [Disable 64-bit target address]),
- [build_target64=$enableval], [build_target64=yes])
-
build_minidriver=no
AC_MSG_CHECKING([whether to enable ZY1000 minidriver])
AS_IF([test "x$build_zy1000" = "xyes"], [
@@ -470,6 +490,12 @@ 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_dummy" = "xyes"], [
build_bitbang=yes
AC_DEFINE([BUILD_DUMMY], [1], [1 if you want dummy driver.])
@@ -581,13 +607,13 @@ AS_IF([test "x$build_sysfsgpio" = "xyes"], [
AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.])
])
-AS_IF([test "x$build_target64" = "xyes"], [
- AC_DEFINE([BUILD_TARGET64], [1], [1 if you want 64-bit addresses.])
+AS_IF([test "x$build_xlnx_pcie_xvc" = "xyes"], [
+ build_xlnx_pcie_xvc=yes
+ AC_DEFINE([BUILD_XLNX_PCIE_XVC], [1], [1 if you want the Xilinx XVC/PCIe driver.])
], [
- AC_DEFINE([BUILD_TARGET64], [0], [0 if you don't want 64-bit addresses.])
+ AC_DEFINE([BUILD_XLNX_PCIE_XVC], [0], [0 if you don't want Xilinx XVC/PCIe driver.])
])
-
PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [
use_libusb1=yes
AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x])
@@ -643,7 +669,6 @@ m4_define([PROCESS_ADAPTERS], [
])
PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x])
-PROCESS_ADAPTERS([USB_ADAPTERS], ["x$use_libusb1" = "xyes" -o "x$use_libusb0" = "xyes"], [libusb-1.x or libusb-0.1])
PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1])
PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi])
PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x])
@@ -700,6 +725,7 @@ AM_CONDITIONAL([OOCD_TRACE], [test "x$build_oocd_trace" = "xyes"])
AM_CONDITIONAL([REMOTE_BITBANG], [test "x$build_remote_bitbang" = "xyes"])
AM_CONDITIONAL([BUSPIRATE], [test "x$build_buspirate" = "xyes"])
AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"])
+AM_CONDITIONAL([XLNX_PCIE_XVC], [test "x$build_xlnx_pcie_xvc" = "xyes"])
AM_CONDITIONAL([USE_LIBUSB0], [test "x$use_libusb0" = "xyes"])
AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"])
AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"])
@@ -710,7 +736,7 @@ AM_CONDITIONAL([BITQ], [test "x$build_bitq" = "xyes"])
AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"])
AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"])
AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"])
-AM_CONDITIONAL([TARGET64], [test "x$build_target64" = "xyes"])
+AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"])
AM_CONDITIONAL([MINIDRIVER], [test "x$build_minidriver" = "xyes"])
AM_CONDITIONAL([MINIDRIVER_DUMMY], [test "x$build_minidriver_dummy" = "xyes"])
@@ -777,9 +803,9 @@ echo
echo
echo OpenOCD configuration summary
echo --------------------------------------------------
-m4_foreach([adapter], [USB1_ADAPTERS, USB_ADAPTERS, USB0_ADAPTERS,
+m4_foreach([adapter], [USB1_ADAPTERS, USB0_ADAPTERS,
HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS,
- LIBJAYLINK_ADAPTERS],
+ LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS],
[s=m4_format(["%-40s"], ADAPTER_DESC([adapter]))
AS_CASE([$ADAPTER_VAR([adapter])],
[auto], [
diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules
index bd607c461..617346d1c 100644
--- a/contrib/60-openocd.rules
+++ b/contrib/60-openocd.rules
@@ -141,6 +141,8 @@ ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev",
# TI XDS110 Debug Probe (Launchpads and Standalone)
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef3", MODE="660", GROUP="plugdev", TAG+="uaccess"
+ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef4", MODE="660", GROUP="plugdev", TAG+="uaccess"
+ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="02a5", MODE="660", GROUP="plugdev", TAG+="uaccess"
# TI Tiva-based ICDI and XDS110 probes in DFU mode
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE="660", GROUP="plugdev", TAG+="uaccess"
diff --git a/contrib/libdcc/README b/contrib/libdcc/README
index d67ccce3f..1135b247e 100644
--- a/contrib/libdcc/README
+++ b/contrib/libdcc/README
@@ -16,4 +16,3 @@ To see how many times the trace point was hit:
Spen
spen@spen-soft.co.uk
-
diff --git a/contrib/loaders/debug/xscale/debug_handler.S b/contrib/loaders/debug/xscale/debug_handler.S
index 66dfa8891..0f62d9c14 100644
--- a/contrib/loaders/debug/xscale/debug_handler.S
+++ b/contrib/loaders/debug/xscale/debug_handler.S
@@ -713,4 +713,3 @@ send_to_debugger:
receive_from_debugger:
m_receive_from_debugger r0
mov pc, lr
-
diff --git a/contrib/loaders/erase_check/stm8_erase_check.s b/contrib/loaders/erase_check/stm8_erase_check.s
index 62694006b..04cde5b1b 100644
--- a/contrib/loaders/erase_check/stm8_erase_check.s
+++ b/contrib/loaders/erase_check/stm8_erase_check.s
@@ -1,19 +1,19 @@
/*
- Copyright (C) 2017 Ake Rehnman
- ake.rehnman(at)gmail.com
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
+* Copyright (C) 2017 Ake Rehnman
+* ake.rehnman(at)gmail.com
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
*/
;;
;; erase check memory code
diff --git a/contrib/loaders/flash/armv7m_io.s b/contrib/loaders/flash/armv7m_io.s
index 797981c53..f6dbbe9bf 100644
--- a/contrib/loaders/flash/armv7m_io.s
+++ b/contrib/loaders/flash/armv7m_io.s
@@ -57,4 +57,3 @@ done_write:
bkpt #0
.end
-
diff --git a/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld b/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld
index ea06931d0..8cb21184f 100644
--- a/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld
+++ b/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld
@@ -129,4 +129,3 @@ SECTIONS
}
/*** EOF ***/
-
diff --git a/contrib/loaders/flash/at91sam7x/makefile b/contrib/loaders/flash/at91sam7x/makefile
index c3eaf126b..39482976e 100644
--- a/contrib/loaders/flash/at91sam7x/makefile
+++ b/contrib/loaders/flash/at91sam7x/makefile
@@ -127,4 +127,4 @@ clean:
#
#-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
-# *** EOF ***
\ No newline at end of file
+# *** EOF ***
diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c
index 3dd17b2fc..f09f7f58a 100644
--- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c
+++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c
@@ -2,6 +2,7 @@
/* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */
#include
+#include "../../../../src/flash/nor/bluenrg-x.h"
/* Status Values ----------------------------------------------------------*/
#define SUCCESS 0
@@ -13,43 +14,22 @@
#define ERR_ERASE_REQUIRED 6
#define ERR_VERIFY_FAILED 7
-/* Flash Controller defines ---------------------------------------------------*/
-#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000)
-#define FLASH_REG_CONFIG ((volatile uint32_t *)0x40100004)
-#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008)
-#define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4010000C)
-#define FLASH_REG_IRQRAW ((volatile uint32_t *)0x40100010)
-#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018)
-#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C)
-#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020)
-#define FLASH_REG_DATA0 ((volatile uint32_t *)0x40100040)
-#define FLASH_REG_DATA1 ((volatile uint32_t *)0x40100044)
-#define FLASH_REG_DATA2 ((volatile uint32_t *)0x40100048)
-#define FLASH_REG_DATA3 ((volatile uint32_t *)0x4010004C)
-#define FLASH_SIZE_REG 0x40100014
-
#define MFB_MASS_ERASE 0x01
#define MFB_PAGE_ERASE 0x02
#define DO_ERASE 0x0100
#define DO_VERIFY 0x0200
-#define FLASH_CMD_ERASE_PAGE 0x11
-#define FLASH_CMD_MASSERASE 0x22
-#define FLASH_CMD_WRITE 0x33
-#define FLASH_CMD_BURSTWRITE 0xCC
-#define FLASH_INT_CMDDONE 0x01
-#define MFB_BOTTOM (0x10040000)
-#define MFB_SIZE_B ((16 * (((*(uint32_t *) FLASH_SIZE_REG) + 1) >> 12)) * 1024)
-#define MFB_SIZE_W (MFB_SIZE_B/4)
-#define MFB_TOP (MFB_BOTTOM+MFB_SIZE_B-1)
-#define MFB_PAGE_SIZE_B (2048)
-#define MFB_PAGE_SIZE_W (MFB_PAGE_SIZE_B/4)
+
+#define MFB_BOTTOM (0x10040000)
+#define MFB_SIZE_B(regs_base) ((16 * (((*(volatile uint32_t *)(regs_base + FLASH_SIZE_REG)) + 1) >> 12)) * 1024)
+#define MFB_SIZE_W (MFB_SIZE_B/4)
+#define MFB_TOP (MFB_BOTTOM+MFB_SIZE_B-1)
+#define MFB_PAGE_SIZE_B (2048)
+#define MFB_PAGE_SIZE_W (MFB_PAGE_SIZE_B/4)
#define AREA_ERROR 0x01
#define AREA_MFB 0x04
-#define FLASH_WORD_LEN 4
-
typedef struct {
volatile uint8_t *wp;
uint8_t *rp;
@@ -57,29 +37,29 @@ typedef struct {
/* Flash Commands --------------------------------------------------------*/
static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data,
- uint32_t writeLength)
+ uint32_t writeLength, uint32_t flash_regs_base)
{
uint32_t index, flash_word[4];
uint8_t i;
- *FLASH_REG_IRQMASK = 0;
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQMASK)) = 0;
for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) {
for (i = 0; i < 4; i++)
flash_word[i] = (*(uint32_t *) (*data + i*4));
/* Clear the IRQ flags */
- *FLASH_REG_IRQRAW = 0x0000003F;
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) = 0x0000003F;
/* Load the flash address to write */
- *FLASH_REG_ADDRESS = (uint16_t)((address + index) >> 2);
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint16_t)((address + index - MFB_BOTTOM) >> 2);
/* Prepare and load the data to flash */
- *FLASH_REG_DATA0 = flash_word[0];
- *FLASH_REG_DATA1 = flash_word[1];
- *FLASH_REG_DATA2 = flash_word[2];
- *FLASH_REG_DATA3 = flash_word[3];
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA0)) = flash_word[0];
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA1)) = flash_word[1];
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA2)) = flash_word[2];
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA3)) = flash_word[3];
/* Flash write command */
- *FLASH_REG_COMMAND = FLASH_CMD_BURSTWRITE;
+ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_COMMAND)) = FLASH_CMD_BURSTWRITE;
/* Wait the end of the flash write command */
- while ((*FLASH_REG_IRQRAW & FLASH_INT_CMDDONE) == 0)
+ while ((*((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) & FLASH_INT_CMDDONE) == 0)
;
*data += (FLASH_WORD_LEN * 4);
}
@@ -90,7 +70,8 @@ static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t addres
__attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p,
uint8_t *fifo_end,
uint8_t *target_address,
- uint32_t count)
+ uint32_t count,
+ uint32_t flash_regs_base)
{
uint32_t retval;
volatile work_area_t *work_area = (work_area_t *) work_area_p;
@@ -118,7 +99,7 @@ __attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p
continue;
}
- retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size);
+ retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size, flash_regs_base);
if (retval != SUCCESS) {
work_area->rp = (uint8_t *)retval;
break;
diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc
index 47f331228..ff05634bb 100644
--- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc
+++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc
@@ -1,18 +1,17 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
-0x05,0x93,0x43,0x68,0x05,0x00,0x07,0x93,0x05,0x9b,0x06,0x91,0x03,0x92,0x35,0x4c,
-0x00,0x2b,0x5c,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0,0x2b,0x68,0x00,0x2b,
-0x55,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x52,0xd9,0x6b,0x68,0x06,0x9a,0xd3,0x1a,
-0x09,0x93,0x09,0x9b,0x0f,0x2b,0xed,0xdd,0x00,0x21,0x09,0x9b,0x04,0x93,0x1a,0x1e,
-0x29,0x4b,0x19,0x60,0x32,0xd0,0x29,0x4b,0x00,0x20,0x98,0x46,0x28,0x4b,0x6a,0x68,
-0x9c,0x46,0x28,0x4b,0x28,0x4e,0x9b,0x46,0x28,0x4b,0x9a,0x46,0x28,0x4b,0x99,0x46,
-0x01,0x23,0x51,0x68,0x17,0x68,0x00,0x91,0x91,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,
-0x3f,0x21,0x21,0x60,0x03,0x99,0x09,0x18,0x89,0x03,0x09,0x0c,0x31,0x60,0x41,0x46,
-0x0f,0x60,0x67,0x46,0x00,0x99,0x39,0x60,0x5f,0x46,0x01,0x99,0x39,0x60,0x57,0x46,
-0x02,0x99,0x39,0x60,0x49,0x46,0xcc,0x27,0x0f,0x60,0x21,0x68,0x0b,0x42,0xfc,0xd0,
-0x04,0x99,0x10,0x32,0x10,0x30,0x6a,0x60,0x81,0x42,0xda,0xd8,0x03,0x9a,0x09,0x9b,
-0x94,0x46,0x9c,0x44,0x63,0x46,0x06,0x9a,0x03,0x93,0x6b,0x68,0x9a,0x42,0x01,0xd8,
-0x07,0x9b,0x6b,0x60,0x05,0x9a,0x09,0x9b,0xd3,0x1a,0x05,0x93,0xa2,0xd1,0x00,0xbe,
-0x2b,0x68,0x6a,0x68,0x9b,0x1a,0x09,0x93,0x09,0x9b,0x00,0x2b,0xa9,0xda,0x00,0x23,
-0x09,0x93,0xa6,0xe7,0x10,0x00,0x10,0x40,0x0c,0x00,0x10,0x40,0x40,0x00,0x10,0x40,
-0x44,0x00,0x10,0x40,0x48,0x00,0x10,0x40,0x18,0x00,0x10,0x40,0x4c,0x00,0x10,0x40,
-0x00,0x00,0x10,0x40,
+0x05,0x93,0x43,0x68,0x14,0x9e,0x09,0x93,0x05,0x9b,0x05,0x00,0x07,0x91,0x06,0x92,
+0x01,0x24,0xb1,0x46,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0,
+0x2b,0x68,0x00,0x2b,0x61,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x5e,0xd9,0x6b,0x68,
+0x07,0x9a,0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x4a,0x46,0x00,0x21,0x03,0x93,0xd1,0x60,
+0x00,0x2b,0x42,0xd0,0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x00,0x92,
+0x48,0x22,0x4a,0x44,0x93,0x46,0x4c,0x22,0x27,0x4f,0x4a,0x44,0xbc,0x46,0x4e,0x46,
+0x92,0x46,0x06,0x99,0x4b,0x46,0x61,0x44,0x08,0x00,0x00,0x99,0x18,0x36,0x6a,0x68,
+0x08,0x95,0x8c,0x46,0x55,0x46,0xda,0x46,0xb3,0x46,0x10,0x33,0x04,0x92,0x11,0x68,
+0x5e,0x46,0x00,0x91,0x51,0x68,0x97,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,0x3f,0x21,
+0x19,0x60,0x81,0x03,0x09,0x0c,0x31,0x60,0x46,0x46,0x00,0x99,0x31,0x60,0x66,0x46,
+0x01,0x99,0x31,0x60,0x56,0x46,0x02,0x99,0x37,0x60,0x29,0x60,0xcc,0x26,0x49,0x46,
+0x0e,0x60,0x19,0x68,0x0c,0x42,0xfc,0xd0,0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30,
+0x51,0x1a,0x8e,0x42,0xdb,0xd8,0x08,0x9d,0x6a,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46,
+0x63,0x44,0x06,0x93,0x07,0x9a,0x6b,0x68,0x9a,0x42,0x01,0xd8,0x09,0x9b,0x6b,0x60,
+0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,0x96,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68,
+0x9b,0x1a,0x9f,0xd5,0x90,0xe7,0xc0,0x46,0x00,0x00,0xfc,0xef,
diff --git a/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds b/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds
index 7798b304a..0e7aa2dee 100644
--- a/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds
+++ b/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds
@@ -148,4 +148,3 @@ SECTIONS {
__stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK);
PROVIDE(__stack = __stack_top);
}
-
diff --git a/contrib/loaders/flash/nrf5/Makefile b/contrib/loaders/flash/nrf5/Makefile
new file mode 100644
index 000000000..67390b9bd
--- /dev/null
+++ b/contrib/loaders/flash/nrf5/Makefile
@@ -0,0 +1,28 @@
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= arm-none-eabi-
+
+CC=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+
+CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL
+
+all: nrf5.inc
+
+.PHONY: clean
+
+%.elf: %.S
+ $(CC) $(CFLAGS) $< -o $@
+
+%.lst: %.elf
+ $(OBJDUMP) -S $< > $@
+
+%.bin: %.elf
+ $(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+ $(BIN2C) < $< > $@
+
+clean:
+ -rm -f *.elf *.lst *.bin *.inc
diff --git a/contrib/loaders/flash/nrf5/nrf5.S b/contrib/loaders/flash/nrf5/nrf5.S
new file mode 100644
index 000000000..12b1d92b5
--- /dev/null
+++ b/contrib/loaders/flash/nrf5/nrf5.S
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2014 Angus Gratton *
+ * gus@projectgus.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc. *
+ ***************************************************************************/
+
+ .text
+ .syntax unified
+ .cpu cortex-m0
+ .thumb
+
+/*
+ * Params :
+ * r0 = byte count
+ * r1 = buffer start
+ * r2 = buffer end
+ * r3 = target address
+ * r6 = watchdog refresh value
+ * r7 = watchdog refresh register address
+ */
+
+ .thumb_func
+ .global _start
+_start:
+wait_fifo:
+ // Kick the watchdog
+ str r6, [r7, #0]
+ // Load write pointer
+ ldr r5, [r1, #0]
+ // Abort if it is NULL
+ cmp r5, #0
+ beq.n exit
+ // Load read pointer
+ ldr r4, [r1, #4]
+ // Continue waiting if it equals the write pointer
+ cmp r4, r5
+ beq.n wait_fifo
+ // Copy one word from buffer to target, and increment pointers
+ ldmia r4!, {r5}
+ stmia r3!, {r5}
+ // If at end of buffer, wrap back to buffer start
+ cmp r4, r2
+ bcc.n no_wrap
+ mov r4, r1
+ adds r4, #8
+no_wrap:
+ // Update read pointer inside the buffer
+ str r4, [r1, #4]
+ // Deduce the word transferred from the byte count
+ subs r0, #4
+ // Start again
+ bne.n wait_fifo
+exit:
+ // Wait for OpenOCD
+ bkpt #0x00
+
+ .pool
diff --git a/contrib/loaders/flash/nrf5/nrf5.inc b/contrib/loaders/flash/nrf5/nrf5.inc
new file mode 100644
index 000000000..2b35b5d6d
--- /dev/null
+++ b/contrib/loaders/flash/nrf5/nrf5.inc
@@ -0,0 +1,4 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x3e,0x60,0x0d,0x68,0x00,0x2d,0x0b,0xd0,0x4c,0x68,0xac,0x42,0xf8,0xd0,0x20,0xcc,
+0x20,0xc3,0x94,0x42,0x01,0xd3,0x0c,0x46,0x08,0x34,0x4c,0x60,0x04,0x38,0xef,0xd1,
+0x00,0xbe,
diff --git a/contrib/loaders/flash/sh_qspi/Makefile b/contrib/loaders/flash/sh_qspi/Makefile
new file mode 100644
index 000000000..2bfbad1b0
--- /dev/null
+++ b/contrib/loaders/flash/sh_qspi/Makefile
@@ -0,0 +1,37 @@
+CROSS_COMPILE=arm-linux-gnueabihf-
+BIN2C = ../../../../src/helper/bin2char.sh
+
+TGT = sh_qspi
+ASRC += sh_qspi.S
+LDS = sh_qspi.ld
+
+OBJS += $(ASRC:.S=.o)
+
+CC=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+LD=$(CROSS_COMPILE)ld
+NM=$(CROSS_COMPILE)nm
+SIZE=$(CROSS_COMPILE)size
+
+CFLAGS=-Os -Wall -nostartfiles -marm -nostdinc -ffreestanding -mabi=aapcs-linux -mword-relocations -fno-pic -mno-unaligned-access -ffunction-sections -fdata-sections -fno-common -msoft-float -pipe -march=armv7-a -mtune=generic-armv7-a
+LDFLAGS=-T$(LDS) -nostdlib -Map=$(TGT).map
+
+all: $(TGT).inc
+
+%.o: %.S
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(TGT).elf: $(OBJS)
+ $(LD) $(LDFLAGS) $^ -o $@
+
+$(TGT).bin: $(TGT).elf
+ $(OBJCOPY) $< -O binary $@
+ $(NM) -n $(TGT).elf > $(TGT).sym
+ $(SIZE) $(TGT).elf
+
+$(TGT).inc: $(TGT).bin
+ $(BIN2C) < $< > $@
+
+clean:
+ rm -rf *.elf *.hex *.map *.o *.disasm *.sym
diff --git a/contrib/loaders/flash/sh_qspi/sh_qspi.S b/contrib/loaders/flash/sh_qspi/sh_qspi.S
new file mode 100644
index 000000000..78eb1e818
--- /dev/null
+++ b/contrib/loaders/flash/sh_qspi/sh_qspi.S
@@ -0,0 +1,306 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * SH QSPI (Quad SPI) driver
+ * Copyright (C) 2019 Marek Vasut
+ */
+
+#define BIT(n) (1UL << (n))
+/* SH QSPI register bit masks _ */
+#define SPCR_MSTR 0x08
+#define SPCR_SPE 0x40
+#define SPSR_SPRFF 0x80
+#define SPSR_SPTEF 0x20
+#define SPPCR_IO3FV 0x04
+#define SPPCR_IO2FV 0x02
+#define SPPCR_IO1FV 0x01
+#define SPBDCR_RXBC0 BIT(0)
+#define SPCMD_SCKDEN BIT(15)
+#define SPCMD_SLNDEN BIT(14)
+#define SPCMD_SPNDEN BIT(13)
+#define SPCMD_SSLKP BIT(7)
+#define SPCMD_BRDV0 BIT(2)
+#define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \
+ SPCMD_SPNDEN | SPCMD_SSLKP | \
+ SPCMD_BRDV0
+#define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \
+ SPCMD_BRDV0
+#define SPBFCR_TXRST BIT(7)
+#define SPBFCR_RXRST BIT(6)
+#define SPBFCR_TXTRG 0x30
+#define SPBFCR_RXTRG 0x07
+
+/* SH QSPI register set */
+#define SH_QSPI_SPCR 0x00
+#define SH_QSPI_SSLP 0x01
+#define SH_QSPI_SPPCR 0x02
+#define SH_QSPI_SPSR 0x03
+#define SH_QSPI_SPDR 0x04
+#define SH_QSPI_SPSCR 0x08
+#define SH_QSPI_SPSSR 0x09
+#define SH_QSPI_SPBR 0x0a
+#define SH_QSPI_SPDCR 0x0b
+#define SH_QSPI_SPCKD 0x0c
+#define SH_QSPI_SSLND 0x0d
+#define SH_QSPI_SPND 0x0e
+#define SH_QSPI_DUMMY0 0x0f
+#define SH_QSPI_SPCMD0 0x10
+#define SH_QSPI_SPCMD1 0x12
+#define SH_QSPI_SPCMD2 0x14
+#define SH_QSPI_SPCMD3 0x16
+#define SH_QSPI_SPBFCR 0x18
+#define SH_QSPI_DUMMY1 0x19
+#define SH_QSPI_SPBDCR 0x1a
+#define SH_QSPI_SPBMUL0 0x1c
+#define SH_QSPI_SPBMUL1 0x20
+#define SH_QSPI_SPBMUL2 0x24
+#define SH_QSPI_SPBMUL3 0x28
+
+.syntax unified
+.arm
+.text
+
+.macro wait_for_spsr, spsrbit
+ 1: ldrb r12, [r0, #SH_QSPI_SPSR]
+ tst r12, \spsrbit
+ beq 1b
+.endm
+
+.macro sh_qspi_xfer
+ bl sh_qspi_cs_activate
+ str r6, [r0, SH_QSPI_SPBMUL0]
+ bl sh_qspi_xfer_common
+ bl sh_qspi_cs_deactivate
+.endm
+
+.macro sh_qspi_write_enable
+ ldr r4, =SPIFLASH_WRITE_ENABLE
+ adr r5, _start
+ add r4, r5
+ mov r5, #0x0
+ mov r6, #0x1
+ sh_qspi_xfer
+.endm
+
+.macro sh_qspi_wait_till_ready
+ 1: ldr r4, =SPIFLASH_READ_STATUS
+ adr r5, _start
+ add r4, r5
+ mov r5, #0x0
+ mov r6, #0x2
+ sh_qspi_xfer
+ and r13, #0x1
+ cmp r13, #0x1
+ beq 1b
+.endm
+
+/*
+ * r0: controller base address
+ * r1: data buffer base address
+ * r2: BIT(31) -- page program (not read)
+ * BIT(30) -- 4-byte address (not 3-byte)
+ * BIT(29) -- 512-byte page (not 256-byte)
+ * BIT(27:20) -- SF command
+ * BIT(19:0) -- amount of data to read/write
+ * r3: SF target address
+ *
+ * r7: data size
+ * r8: page size
+ *
+ * r14: lr, link register
+ * r15: pc, program counter
+ *
+ * Clobber: r4, r5, r6, r7, r8
+ */
+
+.global _start
+_start:
+ bic r7, r2, #0xff000000
+ bic r7, r7, #0x00f00000
+
+ and r8, r2, #(1 << 31)
+ cmp r8, #(1 << 31)
+ beq do_page_program
+
+/* fast read */
+
+ bl sh_qspi_cs_activate
+
+ bl sh_qspi_setup_command
+ add r8, r6, r7
+ str r8, [r0, SH_QSPI_SPBMUL0]
+ bl sh_qspi_xfer_common
+
+ mov r4, #0x0
+ mov r5, r1
+ mov r6, r7
+ bl sh_qspi_xfer_common
+
+ bl sh_qspi_cs_deactivate
+
+ b end
+
+do_page_program:
+
+ mov r8, #0x100
+ tst r2, (1 << 29)
+ movne r8, #0x200
+
+do_pp_next_page:
+ /* Check if less then page bytes left. */
+ cmp r7, r8
+ movlt r8, r7
+
+ sh_qspi_write_enable
+
+ bl sh_qspi_cs_activate
+
+ bl sh_qspi_setup_command
+ str r6, [r0, SH_QSPI_SPBMUL0]
+ bl sh_qspi_xfer_common
+
+ mov r4, r1
+ mov r5, #0x0
+ mov r6, r8
+
+ bl sh_qspi_xfer_common
+
+ bl sh_qspi_cs_deactivate
+
+ sh_qspi_wait_till_ready
+
+ add r1, r8
+ add r3, r8
+ sub r7, r8
+ cmp r7, #0
+
+ bne do_pp_next_page
+
+end:
+ bkpt #0
+
+sh_qspi_cs_activate:
+ /* Set master mode only */
+ mov r12, #SPCR_MSTR
+ strb r12, [r0, SH_QSPI_SPCR]
+
+ /* Set command */
+ mov r12, #SPCMD_INIT1
+ strh r12, [r0, SH_QSPI_SPCMD0]
+
+ /* Reset transfer and receive Buffer */
+ ldrb r12, [r0, SH_QSPI_SPSCR]
+ orr r12, #(SPBFCR_TXRST | SPBFCR_RXRST)
+ strb r12, [r0, SH_QSPI_SPBFCR]
+
+ /* Clear transfer and receive Buffer control bit */
+ ldrb r12, [r0, SH_QSPI_SPBFCR]
+ bic r12, #(SPBFCR_TXRST | SPBFCR_RXRST)
+ strb r12, [r0, SH_QSPI_SPBFCR]
+
+ /* Set sequence control method. Use sequence0 only */
+ mov r12, #0x00
+ strb r12, [r0, SH_QSPI_SPSCR]
+
+ /* Enable SPI function */
+ ldrb r12, [r0, SH_QSPI_SPCR]
+ orr r12, #SPCR_SPE
+ strb r12, [r0, SH_QSPI_SPCR]
+
+ mov pc, lr
+
+sh_qspi_cs_deactivate:
+ /* Disable SPI function */
+ ldrb r12, [r0, SH_QSPI_SPCR]
+ bic r12, #SPCR_SPE
+ strb r12, [r0, SH_QSPI_SPCR]
+
+ mov pc, lr
+
+/*
+ * r0, controller base address
+ * r4, tx buffer
+ * r5, rx buffer
+ * r6, xfer len, non-zero
+ *
+ * Upon exit, r13 contains the last byte in SPDR
+ *
+ * Clobber: r11, r12, r13
+ */
+sh_qspi_xfer_common:
+prepcopy:
+ ldr r13, [r0, #SH_QSPI_SPBFCR]
+ orr r13, #(SPBFCR_TXTRG | SPBFCR_RXTRG)
+ mov r11, #32
+ cmp r6, #32
+
+ biclt r13, #(SPBFCR_TXTRG | SPBFCR_RXTRG)
+ movlt r11, #1
+
+copy:
+ str r13, [r0, #SH_QSPI_SPBFCR]
+
+ wait_for_spsr SPSR_SPTEF
+
+ mov r12, r11
+ mov r13, #0
+ cmp r4, #0
+ beq 3f
+
+2: ldrb r13, [r4], #1
+ strb r13, [r0, #SH_QSPI_SPDR]
+ subs r12, #1
+ bne 2b
+ b 4f
+
+3: strb r13, [r0, #SH_QSPI_SPDR]
+ subs r12, #1
+ bne 3b
+
+4: wait_for_spsr SPSR_SPRFF
+
+ mov r12, r11
+ cmp r5, #0
+ beq 6f
+
+5: ldrb r13, [r0, #SH_QSPI_SPDR]
+ strb r13, [r5], #1
+ subs r12, #1
+ bne 5b
+ b 7f
+
+6: ldrb r13, [r0, #SH_QSPI_SPDR]
+ subs r12, #1
+ bne 6b
+
+7: subs r6, r11
+ bne prepcopy
+
+ mov pc, lr
+
+sh_qspi_setup_command:
+ ldr r4, =SPIFLASH_SCRATCH_DATA
+ adr r5, _start
+ add r4, r5
+ and r12, r2, #0x0ff00000
+ lsr r12, #20
+ strb r12, [r4]
+ mov r12, r3
+ strb r12, [r4, #4]
+ lsr r12, #8
+ strb r12, [r4, #3]
+ lsr r12, #8
+ strb r12, [r4, #2]
+ lsr r12, #8
+ strb r12, [r4, #1]
+ lsr r12, #8
+ mov r5, #0x0
+ mov r6, #0x4
+ tst r2, (1 << 30)
+ movne r6, #0x5
+
+ mov pc, lr
+
+SPIFLASH_READ_STATUS: .byte 0x05 /* Read Status Register */
+SPIFLASH_WRITE_ENABLE: .byte 0x06 /* Write Enable */
+SPIFLASH_NOOP: .byte 0x00
+SPIFLASH_SCRATCH_DATA: .byte 0x00, 0x0, 0x0, 0x0, 0x0
diff --git a/contrib/loaders/flash/sh_qspi/sh_qspi.inc b/contrib/loaders/flash/sh_qspi/sh_qspi.inc
new file mode 100644
index 000000000..ca913923f
--- /dev/null
+++ b/contrib/loaders/flash/sh_qspi/sh_qspi.inc
@@ -0,0 +1,37 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xff,0x74,0xc2,0xe3,0x0f,0x76,0xc7,0xe3,0x02,0x81,0x02,0xe2,0x02,0x01,0x58,0xe3,
+0x0a,0x00,0x00,0x0a,0x32,0x00,0x00,0xeb,0x6c,0x00,0x00,0xeb,0x07,0x80,0x86,0xe0,
+0x1c,0x80,0x80,0xe5,0x42,0x00,0x00,0xeb,0x00,0x40,0xa0,0xe3,0x01,0x50,0xa0,0xe1,
+0x07,0x60,0xa0,0xe1,0x3e,0x00,0x00,0xeb,0x39,0x00,0x00,0xeb,0x27,0x00,0x00,0xea,
+0x01,0x8c,0xa0,0xe3,0x02,0x02,0x12,0xe3,0x02,0x8c,0xa0,0x13,0x08,0x00,0x57,0xe1,
+0x07,0x80,0xa0,0xb1,0xcc,0x41,0x9f,0xe5,0x60,0x50,0x4f,0xe2,0x05,0x40,0x84,0xe0,
+0x00,0x50,0xa0,0xe3,0x01,0x60,0xa0,0xe3,0x1d,0x00,0x00,0xeb,0x1c,0x60,0x80,0xe5,
+0x2f,0x00,0x00,0xeb,0x2a,0x00,0x00,0xeb,0x19,0x00,0x00,0xeb,0x53,0x00,0x00,0xeb,
+0x1c,0x60,0x80,0xe5,0x2a,0x00,0x00,0xeb,0x01,0x40,0xa0,0xe1,0x00,0x50,0xa0,0xe3,
+0x08,0x60,0xa0,0xe1,0x26,0x00,0x00,0xeb,0x21,0x00,0x00,0xeb,0x88,0x41,0x9f,0xe5,
+0xa8,0x50,0x4f,0xe2,0x05,0x40,0x84,0xe0,0x00,0x50,0xa0,0xe3,0x02,0x60,0xa0,0xe3,
+0x0b,0x00,0x00,0xeb,0x1c,0x60,0x80,0xe5,0x1d,0x00,0x00,0xeb,0x18,0x00,0x00,0xeb,
+0x01,0xd0,0x0d,0xe2,0x01,0x00,0x5d,0xe3,0xf3,0xff,0xff,0x0a,0x08,0x10,0x81,0xe0,
+0x08,0x30,0x83,0xe0,0x08,0x70,0x47,0xe0,0x00,0x00,0x57,0xe3,0xda,0xff,0xff,0x1a,
+0x70,0x00,0x20,0xe1,0x08,0xc0,0xa0,0xe3,0x00,0xc0,0xc0,0xe5,0x84,0xc0,0x0e,0xe3,
+0xb0,0xc1,0xc0,0xe1,0x08,0xc0,0xd0,0xe5,0xc0,0xc0,0x8c,0xe3,0x18,0xc0,0xc0,0xe5,
+0x18,0xc0,0xd0,0xe5,0xc0,0xc0,0xcc,0xe3,0x18,0xc0,0xc0,0xe5,0x00,0xc0,0xa0,0xe3,
+0x08,0xc0,0xc0,0xe5,0x00,0xc0,0xd0,0xe5,0x40,0xc0,0x8c,0xe3,0x00,0xc0,0xc0,0xe5,
+0x0e,0xf0,0xa0,0xe1,0x00,0xc0,0xd0,0xe5,0x40,0xc0,0xcc,0xe3,0x00,0xc0,0xc0,0xe5,
+0x0e,0xf0,0xa0,0xe1,0x18,0xd0,0x90,0xe5,0x37,0xd0,0x8d,0xe3,0x20,0xb0,0xa0,0xe3,
+0x20,0x00,0x56,0xe3,0x37,0xd0,0xcd,0xb3,0x01,0xb0,0xa0,0xb3,0x18,0xd0,0x80,0xe5,
+0x03,0xc0,0xd0,0xe5,0x20,0x00,0x1c,0xe3,0xfc,0xff,0xff,0x0a,0x0b,0xc0,0xa0,0xe1,
+0x00,0xd0,0xa0,0xe3,0x00,0x00,0x54,0xe3,0x04,0x00,0x00,0x0a,0x01,0xd0,0xd4,0xe4,
+0x04,0xd0,0xc0,0xe5,0x01,0xc0,0x5c,0xe2,0xfb,0xff,0xff,0x1a,0x02,0x00,0x00,0xea,
+0x04,0xd0,0xc0,0xe5,0x01,0xc0,0x5c,0xe2,0xfc,0xff,0xff,0x1a,0x03,0xc0,0xd0,0xe5,
+0x80,0x00,0x1c,0xe3,0xfc,0xff,0xff,0x0a,0x0b,0xc0,0xa0,0xe1,0x00,0x00,0x55,0xe3,
+0x04,0x00,0x00,0x0a,0x04,0xd0,0xd0,0xe5,0x01,0xd0,0xc5,0xe4,0x01,0xc0,0x5c,0xe2,
+0xfb,0xff,0xff,0x1a,0x02,0x00,0x00,0xea,0x04,0xd0,0xd0,0xe5,0x01,0xc0,0x5c,0xe2,
+0xfc,0xff,0xff,0x1a,0x0b,0x60,0x56,0xe0,0xd9,0xff,0xff,0x1a,0x0e,0xf0,0xa0,0xe1,
+0x58,0x40,0x9f,0xe5,0x77,0x5f,0x4f,0xe2,0x05,0x40,0x84,0xe0,0xff,0xc6,0x02,0xe2,
+0x2c,0xca,0xa0,0xe1,0x00,0xc0,0xc4,0xe5,0x03,0xc0,0xa0,0xe1,0x04,0xc0,0xc4,0xe5,
+0x2c,0xc4,0xa0,0xe1,0x03,0xc0,0xc4,0xe5,0x2c,0xc4,0xa0,0xe1,0x02,0xc0,0xc4,0xe5,
+0x2c,0xc4,0xa0,0xe1,0x01,0xc0,0xc4,0xe5,0x2c,0xc4,0xa0,0xe1,0x00,0x50,0xa0,0xe3,
+0x04,0x60,0xa0,0xe3,0x01,0x01,0x12,0xe3,0x05,0x60,0xa0,0x13,0x0e,0xf0,0xa0,0xe1,
+0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x02,0x00,0x00,0x20,0x02,0x00,0x00,
+0x23,0x02,0x00,0x00,
diff --git a/contrib/loaders/flash/sh_qspi/sh_qspi.ld b/contrib/loaders/flash/sh_qspi/sh_qspi.ld
new file mode 100644
index 000000000..2683c520b
--- /dev/null
+++ b/contrib/loaders/flash/sh_qspi/sh_qspi.ld
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x0;
+ . = ALIGN(4);
+ .text : {
+ sh_qspi.o (.text*)
+ *(.text*)
+ }
+}
diff --git a/contrib/loaders/flash/stm32/stm32h7x.S b/contrib/loaders/flash/stm32/stm32h7x.S
index f0d32956f..99e416753 100644
--- a/contrib/loaders/flash/stm32/stm32h7x.S
+++ b/contrib/loaders/flash/stm32/stm32h7x.S
@@ -18,36 +18,42 @@
.text
.syntax unified
- .cpu cortex-m7
+ .cpu cortex-m4
.thumb
/*
* Code limitations:
* The workarea must have size multiple of 4 bytes, since R/W
* operations are all at 32 bits.
- * The workarea must be big enough to contain 32 bytes of data,
- * thus the minimum size is (rp, wp, data) = 4 + 4 + 32 = 40 bytes.
+ * The workarea must be big enough to contain rp, wp and data, thus the minumum
+ * workarea size is: min_wa_size = sizeof(rp, wp, data) = 4 + 4 + sizeof(data).
+ * - for 0x450 devices: sizeof(data) = 32 bytes, thus min_wa_size = 40 bytes.
+ * - for 0x480 devices: sizeof(data) = 16 bytes, thus min_wa_size = 24 bytes.
* To benefit from concurrent host write-to-buffer and target
* write-to-flash, the workarea must be way bigger than the minimum.
- */
+ *
+ * To avoid confusions the write word size is got from .block_size member of
+ * struct stm32h7x_part_info defined in stm32h7x.c
+*/
/*
* Params :
* r0 = workarea start, status (out)
* r1 = workarea end
* r2 = target address
- * r3 = count (256 bit words)
- * r4 = flash reg base
+ * r3 = count (of write words)
+ * r4 = size of write word
+ * r5 = flash reg base
*
* Clobbered:
- * r5 - rp
- * r6 - wp, status, tmp
- * r7 - loop index, tmp
+ * r6 - rp
+ * r7 - wp, status, tmp
+ * r8 - loop index, tmp
*/
#define STM32_FLASH_CR_OFFSET 0x0C /* offset of CR register in FLASH struct */
#define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */
-#define STM32_CR_PROG 0x00000032 /* PSIZE64 | PG */
+#define STM32_CR_PROG 0x00000002 /* PG */
#define STM32_SR_QW_MASK 0x00000004 /* QW */
#define STM32_SR_ERROR_MASK 0x07ee0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR
| INCERR | STRBERR | PGSERR | WRPERR */
@@ -55,55 +61,55 @@
.thumb_func
.global _start
_start:
- ldr r5, [r0, #4] /* read rp */
+ ldr r6, [r0, #4] /* read rp */
wait_fifo:
- ldr r6, [r0, #0] /* read wp */
- cbz r6, exit /* abort if wp == 0, status = 0 */
- subs r6, r6, r5 /* number of bytes available for read in r6 */
+ ldr r7, [r0, #0] /* read wp */
+ cbz r7, exit /* abort if wp == 0, status = 0 */
+ subs r7, r7, r6 /* number of bytes available for read in r7 */
ittt mi /* if wrapped around */
- addmi r6, r1 /* add size of buffer */
- submi r6, r0
- submi r6, #8
- cmp r6, #32 /* wait until 32 bytes are available */
+ addmi r7, r1 /* add size of buffer */
+ submi r7, r0
+ submi r7, #8
+ cmp r7, r4 /* wait until data buffer is full */
bcc wait_fifo
- mov r6, #STM32_CR_PROG
- str r6, [r4, #STM32_FLASH_CR_OFFSET]
+ mov r7, #STM32_CR_PROG
+ str r7, [r5, #STM32_FLASH_CR_OFFSET]
- mov r7, #8 /* program by 8 words = 32 bytes */
+ mov r8, #4
+ udiv r8, r4, r8 /* number of words is size of write word devided by 4*/
write_flash:
dsb
- ldr r6, [r5], #0x04 /* read one word from src, increment ptr */
- str r6, [r2], #0x04 /* write one word to dst, increment ptr */
+ ldr r7, [r6], #0x04 /* read one word from src, increment ptr */
+ str r7, [r2], #0x04 /* write one word to dst, increment ptr */
dsb
- cmp r5, r1 /* if rp >= end of buffer ... */
+ cmp r6, r1 /* if rp >= end of buffer ... */
it cs
- addcs r5, r0, #8 /* ... then wrap at buffer start */
- subs r7, r7, #1 /* decrement loop index */
+ addcs r6, r0, #8 /* ... then wrap at buffer start */
+ subs r8, r8, #1 /* decrement loop index */
bne write_flash /* loop if not done */
busy:
- ldr r6, [r4, #STM32_FLASH_SR_OFFSET]
- tst r6, #STM32_SR_QW_MASK
+ ldr r7, [r5, #STM32_FLASH_SR_OFFSET]
+ tst r7, #STM32_SR_QW_MASK
bne busy /* operation in progress, wait ... */
- ldr r7, =STM32_SR_ERROR_MASK
- tst r6, r7
+ ldr r8, =STM32_SR_ERROR_MASK
+ tst r7, r8
bne error /* fail... */
- str r5, [r0, #4] /* store rp */
+ str r6, [r0, #4] /* store rp */
subs r3, r3, #1 /* decrement count */
bne wait_fifo /* loop if not done */
b exit
error:
- movs r7, #0
- str r7, [r0, #4] /* set rp = 0 on error */
+ movs r8, #0
+ str r8, [r0, #4] /* set rp = 0 on error */
exit:
- mov r0, r6 /* return status in r0 */
+ mov r0, r7 /* return status in r0 */
bkpt #0x00
.pool
-
diff --git a/contrib/loaders/flash/stm32/stm32h7x.inc b/contrib/loaders/flash/stm32/stm32h7x.inc
index ec14de0ef..015644ffa 100644
--- a/contrib/loaders/flash/stm32/stm32h7x.inc
+++ b/contrib/loaders/flash/stm32/stm32h7x.inc
@@ -1,7 +1,8 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
-0x45,0x68,0x06,0x68,0x36,0xb3,0x76,0x1b,0x42,0xbf,0x76,0x18,0x36,0x1a,0x08,0x3e,
-0x20,0x2e,0xf6,0xd3,0x4f,0xf0,0x32,0x06,0xe6,0x60,0x4f,0xf0,0x08,0x07,0xbf,0xf3,
-0x4f,0x8f,0x55,0xf8,0x04,0x6b,0x42,0xf8,0x04,0x6b,0xbf,0xf3,0x4f,0x8f,0x8d,0x42,
-0x28,0xbf,0x00,0xf1,0x08,0x05,0x01,0x3f,0xf1,0xd1,0x26,0x69,0x16,0xf0,0x04,0x0f,
-0xfb,0xd1,0x05,0x4f,0x3e,0x42,0x03,0xd1,0x45,0x60,0x01,0x3b,0xd9,0xd1,0x01,0xe0,
-0x00,0x27,0x47,0x60,0x30,0x46,0x00,0xbe,0x00,0x00,0xee,0x07,
+0x46,0x68,0x07,0x68,0x6f,0xb3,0xbf,0x1b,0x42,0xbf,0x7f,0x18,0x3f,0x1a,0x08,0x3f,
+0xa7,0x42,0xf6,0xd3,0x4f,0xf0,0x02,0x07,0xef,0x60,0x4f,0xf0,0x04,0x08,0xb4,0xfb,
+0xf8,0xf8,0xbf,0xf3,0x4f,0x8f,0x56,0xf8,0x04,0x7b,0x42,0xf8,0x04,0x7b,0xbf,0xf3,
+0x4f,0x8f,0x8e,0x42,0x28,0xbf,0x00,0xf1,0x08,0x06,0xb8,0xf1,0x01,0x08,0xf0,0xd1,
+0x2f,0x69,0x17,0xf0,0x04,0x0f,0xfb,0xd1,0xdf,0xf8,0x1c,0x80,0x17,0xea,0x08,0x0f,
+0x03,0xd1,0x46,0x60,0x01,0x3b,0xd4,0xd1,0x03,0xe0,0x5f,0xf0,0x00,0x08,0xc0,0xf8,
+0x04,0x80,0x38,0x46,0x00,0xbe,0x00,0x00,0x00,0x00,0xee,0x07,
diff --git a/contrib/loaders/flash/stm32/stm32l4x.S b/contrib/loaders/flash/stm32/stm32l4x.S
index 9c49016df..9923ce772 100644
--- a/contrib/loaders/flash/stm32/stm32l4x.S
+++ b/contrib/loaders/flash/stm32/stm32l4x.S
@@ -8,6 +8,9 @@
* Copyright (C) 2015 Uwe Bonnes *
* bon@elektron.ikp.physik.tu-darmstadt.de *
* *
+ * Copyright (C) 2018 Andreas Bolsch *
+ * andreas.bolsch@mni.thm.de *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
@@ -25,68 +28,78 @@
.text
.syntax unified
- .cpu cortex-m4
+ .cpu cortex-m0
.thumb
/*
* Params :
* r0 = workarea start, status (out)
- * r1 = workarea end
+ * r1 = workarea end + 1
* r2 = target address
* r3 = count (64bit words)
- * r4 = flash base
+ * r4 = flash status register
+ * r5 = flash control register
*
* Clobbered:
- * r5 - rp
* r6/7 - temp (64-bit)
- * r8 - wp, tmp
*/
-#define STM32_FLASH_CR_OFFSET 0x14 /* offset of CR register in FLASH struct */
-#define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */
-
-#define STM32_PROG 0x1 /* PG */
+#include "../../../../src/flash/nor/stm32l4x.h"
.thumb_func
.global _start
+
_start:
+ mov r8, r3 /* copy dword count */
wait_fifo:
- ldr r8, [r0, #0] /* read wp */
- cmp r8, #0 /* abort if wp == 0 */
- beq exit
- ldr r5, [r0, #4] /* read rp */
- subs r6, r8, r5 /* number of bytes available for read in r6*/
- itt mi /* if wrapped around*/
- addmi r6, r1 /* add size of buffer */
- submi r6, r0
- cmp r6, #8 /* wait until 8 bytes are available */
- bcc wait_fifo
+ ldr r6, [r0, #0] /* read wp */
+ cmp r6, #0 /* if wp == 0, */
+ beq exit /* then abort */
+ ldr r3, [r0, #4] /* read rp */
+ subs r6, r6, r3 /* number of bytes available for read in r6 */
+ bpl fifo_stat /* if not wrapped around, skip */
+ adds r6, r6, r1 /* add end of buffer */
+ subs r6, r6, r0 /* sub start of buffer */
+fifo_stat:
+ cmp r6, #8 /* wait until at least one dword available */
+ bcc wait_fifo
- ldr r6, =STM32_PROG
- str r6, [r4, #STM32_FLASH_CR_OFFSET]
- ldrd r6, [r5], #0x08 /* read one word from src, increment ptr */
- strd r6, [r2], #0x08 /* write one word to dst, increment ptr */
+ movs r6, #FLASH_PG /* flash program enable */
+ str r6, [r5] /* write to FLASH_CR, start operation */
+ ldmia r3!, {r6, r7} /* read one dword from src, increment ptr */
+ stmia r2!, {r6, r7} /* write one dword to dst, increment ptr */
dsb
+ ldr r7, =FLASH_BSY /* FLASH_BSY mask */
busy:
- ldr r6, [r4, #STM32_FLASH_SR_OFFSET]
- tst r6, #0x10000 /* BSY (bit16) == 1 => operation in progress */
- bne busy /* wait more... */
- tst r6, #0xfa /* PGSERR | PGPERR | PGAERR | WRPERR | PROGERR*/
- bne error /* fail... */
+ ldr r6, [r4] /* get FLASH_SR register */
+ tst r6, r7 /* BSY == 1 => operation in progress */
+ bne busy /* if still set, wait more ... */
+ movs r7, #FLASH_ERROR /* all error bits */
+ tst r6, r7 /* check for any error bit */
+ bne error /* fail ... */
- cmp r5, r1 /* wrap rp at end of buffer */
- it cs
- addcs r5, r0, #8 /* skip loader args */
- str r5, [r0, #4] /* store rp */
- subs r3, r3, #1 /* decrement dword count */
- cbz r3, exit /* loop if not done */
- b wait_fifo
-error:
- movs r1, #0
- str r1, [r0, #4] /* set rp = 0 on error */
-exit:
- mov r0, r6 /* return status in r0 */
- bkpt #0x00
+ cmp r3, r1 /* rp at end of buffer? */
+ bcc upd_rp /* if no, then skip */
+ subs r3, r3, r1 /* sub end of buffer */
+ adds r3, r3, r0 /* add start of buffer */
+ adds r3, r3, #8 /* skip wp and rp */
+upd_rp:
+ str r3, [r0, #4] /* store rp */
+ mov r7, r8 /* get dword count */
+ subs r7, r7, #1 /* decrement dword count */
+ mov r8, r7 /* save dword count */
+ beq exit /* exit if done */
+ b wait_fifo
.pool
+error:
+ movs r3, #0
+ str r3, [r0, #4] /* set rp = 0 on error */
+exit:
+ mov r0, r6 /* return status in r0 */
+ movs r6, #0 /* flash program disable */
+ str r6, [r5] /* write to FLASH_CR */
+ movs r6, #FLASH_ERROR /* all error bits */
+ str r6, [r4] /* write to FLASH_CR to clear errors */
+ bkpt #0x00
diff --git a/contrib/loaders/flash/stm32/stm32l4x.inc b/contrib/loaders/flash/stm32/stm32l4x.inc
index 4065d14ef..df5c7edd1 100644
--- a/contrib/loaders/flash/stm32/stm32l4x.inc
+++ b/contrib/loaders/flash/stm32/stm32l4x.inc
@@ -1,7 +1,7 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
-0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x20,0xd0,0x45,0x68,0xb8,0xeb,0x05,0x06,
-0x44,0xbf,0x76,0x18,0x36,0x1a,0x08,0x2e,0xf2,0xd3,0x0d,0x4e,0x66,0x61,0xf5,0xe8,
-0x02,0x67,0xe2,0xe8,0x02,0x67,0xbf,0xf3,0x4f,0x8f,0x26,0x69,0x16,0xf4,0x80,0x3f,
-0xfb,0xd1,0x16,0xf0,0xfa,0x0f,0x07,0xd1,0x8d,0x42,0x28,0xbf,0x00,0xf1,0x08,0x05,
-0x45,0x60,0x01,0x3b,0x13,0xb1,0xdb,0xe7,0x00,0x21,0x41,0x60,0x30,0x46,0x00,0xbe,
-0x01,0x00,0x00,0x00,
+0x98,0x46,0x06,0x68,0x00,0x2e,0x23,0xd0,0x43,0x68,0xf6,0x1a,0x01,0xd5,0x76,0x18,
+0x36,0x1a,0x08,0x2e,0xf5,0xd3,0x01,0x26,0x2e,0x60,0xc0,0xcb,0xc0,0xc2,0xbf,0xf3,
+0x4f,0x8f,0x09,0x4f,0x26,0x68,0x3e,0x42,0xfc,0xd1,0xfa,0x27,0x3e,0x42,0x0d,0xd1,
+0x8b,0x42,0x02,0xd3,0x5b,0x1a,0x1b,0x18,0x08,0x33,0x43,0x60,0x47,0x46,0x01,0x3f,
+0xb8,0x46,0x05,0xd0,0xdd,0xe7,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x23,0x43,0x60,
+0x30,0x46,0x00,0x26,0x2e,0x60,0xfa,0x26,0x26,0x60,0x00,0xbe,
diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog.s b/contrib/loaders/watchdog/armv7m_kinetis_wdog.s
index d7241927c..2a7eb8984 100644
--- a/contrib/loaders/watchdog/armv7m_kinetis_wdog.s
+++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog.s
@@ -61,4 +61,3 @@ done:
bkpt #0
.end
-
diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s
index bf58327e9..1284ab0a2 100644
--- a/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s
+++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s
@@ -78,4 +78,3 @@ done:
bkpt #0
.end
-
diff --git a/contrib/rpc_examples/ocd_rpc_example.py b/contrib/rpc_examples/ocd_rpc_example.py
index 4b1516ad9..9d17e7695 100755
--- a/contrib/rpc_examples/ocd_rpc_example.py
+++ b/contrib/rpc_examples/ocd_rpc_example.py
@@ -49,10 +49,16 @@ class OpenOcd:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def __enter__(self):
- self.sock.connect((self.tclRpcIp, self.tclRpcPort))
+ self.connect()
return self
def __exit__(self, type, value, traceback):
+ self.disconnect()
+
+ def connect(self):
+ self.sock.connect((self.tclRpcIp, self.tclRpcPort))
+
+ def disconnect(self):
try:
self.send("exit")
finally:
diff --git a/contrib/xsvf_tools/svf2xsvf.py b/contrib/xsvf_tools/svf2xsvf.py
index 113e0a61a..6da7ff4a8 100644
--- a/contrib/xsvf_tools/svf2xsvf.py
+++ b/contrib/xsvf_tools/svf2xsvf.py
@@ -726,4 +726,3 @@ finally:
cmdbuf[0] = XCOMPLETE
output.write( cmdbuf )
output.close()
-
diff --git a/contrib/xsvf_tools/xsvfdump.py b/contrib/xsvf_tools/xsvfdump.py
index e65f8d5b2..0e00ca05c 100644
--- a/contrib/xsvf_tools/xsvfdump.py
+++ b/contrib/xsvf_tools/xsvfdump.py
@@ -265,4 +265,3 @@ def main():
if __name__ == "__main__":
main()
-
diff --git a/doc/.gitattributes b/doc/.gitattributes
new file mode 100644
index 000000000..dcf6d037c
--- /dev/null
+++ b/doc/.gitattributes
@@ -0,0 +1,3 @@
+# Avoid DOS conversion of texinfo files during git clone
+*.texi text eol=lf
+*.txt text eol=lf
diff --git a/doc/fdl.texi b/doc/fdl.texi
index a18c33ea0..33b2a1646 100644
--- a/doc/fdl.texi
+++ b/doc/fdl.texi
@@ -449,4 +449,3 @@ to permit their use in free software.
@c Local Variables:
@c ispell-local-pdict: "ispell-dict"
@c End:
-
diff --git a/doc/manual/target/mips.txt b/doc/manual/target/mips.txt
index 5121d1276..25978a3d5 100644
--- a/doc/manual/target/mips.txt
+++ b/doc/manual/target/mips.txt
@@ -395,7 +395,7 @@ for (i = 0; i < count; i++)
Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds in executing the handler. However, since handler is in a assembly loop,
CPU comes to next instruction which also fetches data from FASTDATA area. So it stalls.
-Then OpenOCD fills the data again, from it's (OpenOCD's) loop. And this game continues untill all the data has been filled.
+Then OpenOCD fills the data again, from it's (OpenOCD's) loop. And this game continues until all the data has been filled.
After the last data has been given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, this instruction do not point into dmseg, so
CPU executes bunch of handler instructions (all prologue) and in the end jumps to MIPS32_PRACC_TEXT address.
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 2624477ea..7bce4f4d2 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -536,16 +536,8 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/
@* Link: @url{http://www.keil.com/ulink1/}
@item @b{TI XDS110 Debug Probe}
-@* The XDS110 is included as the embedded debug probe on many Texas Instruments
-LaunchPad evaluation boards.
-@* The XDS110 is also available as a stand-alone USB debug probe. The XDS110
-stand-alone probe has the additional ability to supply voltage to the target
-board via its AUX FUNCTIONS port. Use the
-@command{xds110_supply_voltage } command to set the voltage. 0 turns
-off the supply. Otherwise, the supply can be set to any value in the range 1800
-to 3600 millivolts.
-@* Link: @url{http://processors.wiki.ti.com/index.php/XDS110}
-@* Link: @url{http://processors.wiki.ti.com/index.php/XDS_Emulation_Software_Package#XDS110_Support_Utilities}
+@* Link: @url{https://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds110.html}
+@* Link: @url{https://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds_software_package_download.html#xds110-support-utilities}
@end itemize
@section IBM PC Parallel Printer Port Based
@@ -617,6 +609,9 @@ produced, PDF schematics are easily found and it is easy to make.
@* A JTAG driver acting as a client for the JTAG VPI server interface.
@* Link: @url{http://github.com/fjullien/jtag_vpi}
+@item @b{xlnx_pcie_xvc}
+@* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG interface.
+
@end itemize
@node About Jim-Tcl
@@ -1479,7 +1474,7 @@ While the default is normally provided by the chip manufacturer,
board files may need to distinguish between instances of a chip.
@item @code{ENDIAN} ...
By default @option{little} - although chips may hard-wire @option{big}.
-Chips that can't change endianess don't need to use this variable.
+Chips that can't change endianness don't need to use this variable.
@item @code{CPUTAPID} ...
When OpenOCD examines the JTAG chain, it can be told verify the
chips against the JTAG IDCODE register.
@@ -1571,7 +1566,7 @@ solution just avoids using that instruction with JTAG debuggers.
If both the chip and the board support adaptive clocking,
use the @command{jtag_rclk}
command, in case your board is used with JTAG adapter which
-also supports it. Otherwise use @command{adapter_khz}.
+also supports it. Otherwise use @command{adapter speed}.
Set the slow rate at the beginning of the reset sequence,
and the faster rate as soon as the clocks are at full speed.
@@ -1611,12 +1606,12 @@ proc init_board @{@} @{
reset_config trst_and_srst trst_pulls_srst
$_TARGETNAME configure -event reset-start @{
- adapter_khz 100
+ adapter speed 100
@}
$_TARGETNAME configure -event reset-init @{
enable_fast_clock
- adapter_khz 10000
+ adapter speed 10000
@}
@}
@end example
@@ -2335,28 +2330,28 @@ A few cases are so simple that you only need to say what driver to use:
@example
# jlink interface
-interface jlink
+adapter driver jlink
@end example
Most adapters need a bit more configuration than that.
-@section Interface Configuration
+@section Adapter Configuration
-The interface command tells OpenOCD what type of debug adapter you are
+The @command{adapter driver} command tells OpenOCD what type of debug adapter you are
using. Depending on the type of adapter, you may need to use one or
more additional commands to further identify or configure the adapter.
-@deffn {Config Command} {interface} name
-Use the interface driver @var{name} to connect to the
+@deffn {Config Command} {adapter driver} name
+Use the adapter driver @var{name} to connect to the
target.
@end deffn
-@deffn Command {interface_list}
+@deffn Command {adapter list}
List the debug adapter drivers that have been built into
the running copy of OpenOCD.
@end deffn
-@deffn Command {interface transports} transport_name+
+@deffn 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
@@ -2365,7 +2360,7 @@ the hardware can support.
-@deffn Command {adapter_name}
+@deffn Command {adapter name}
Returns the name of the debug adapter driver being used.
@end deffn
@@ -2716,7 +2711,7 @@ For example, to connect remotely via TCP to the host foobar you might have
something like:
@example
-interface remote_bitbang
+adapter driver remote_bitbang
remote_bitbang_port 3335
remote_bitbang_host foobar
@end example
@@ -2725,7 +2720,7 @@ To connect to another process running locally via UNIX sockets with socket
named mysocket:
@example
-interface remote_bitbang
+adapter driver remote_bitbang
remote_bitbang_port 0
remote_bitbang_host mysocket
@end example
@@ -2990,7 +2985,7 @@ you may encounter a problem.
@deffn Command {parport_toggling_time} [nanoseconds]
Displays how many nanoseconds the hardware needs to toggle TCK;
the parport driver uses this value to obey the
-@command{adapter_khz} configuration.
+@command{adapter speed} configuration.
When the optional @var{nanoseconds} parameter is given,
that setting is changed before displaying the current value.
@@ -3001,7 +2996,7 @@ To measure the toggling time with a logic analyzer or a digital storage
oscilloscope, follow the procedure below:
@example
> parport_toggling_time 1000
-> adapter_khz 500
+> adapter speed 500
@end example
This sets the maximum JTAG clock speed of the hardware, but
the actual speed probably deviates from the requested 500 kHz.
@@ -3012,14 +3007,15 @@ Update the setting to match your measurement:
@example
> parport_toggling_time
@end example
-Now the clock speed will be a better match for @command{adapter_khz rate}
-commands given in OpenOCD scripts and event handlers.
+Now the clock speed will be a better match for @command{adapter speed}
+command given in OpenOCD scripts and event handlers.
You can do something similar with many digital multimeters, but note
that you'll probably need to run the clock continuously for several
seconds before it decides what clock rate to show. Adjust the
toggling time up or down until the measured clock rate is a good
-match for the adapter_khz rate you specified; be conservative.
+match with the rate you specified in the @command{adapter speed} command;
+be conservative.
@end quotation
@end deffn
@@ -3032,7 +3028,7 @@ For example, the interface configuration file for a
classic ``Wiggler'' cable on LPT2 might look something like this:
@example
-interface parport
+adapter driver parport
parport_port 0x278
parport_cable wiggler
@end example
@@ -3096,6 +3092,29 @@ passed as is to the underlying adapter layout handler.
@end deffn
@end deffn
+@anchor{st_link_dap_interface}
+@deffn {Interface Driver} {st-link}
+This is a driver that supports STMicroelectronics adapters ST-LINK/V2
+(from firmware V2J24) and STLINK-V3, thanks to a new API that provides
+directly access the arm ADIv5 DAP.
+
+The new API provide access to multiple AP on the same DAP, but the
+maximum number of the AP port is limited by the specific firmware version
+(e.g. firmware V2J29 has 3 as maximum AP number, while V2J32 has 8).
+An error is returned for any AP number above the maximum allowed value.
+
+@emph{Note:} Either these same adapters and their older versions are
+also supported by @ref{hla_interface, the hla interface driver}.
+
+@deffn {Config Command} {st-link serial} serial
+Specifies the serial number of the adapter.
+@end deffn
+
+@deffn {Config Command} {st-link vid_pid} [vid pid]+
+Pairs of vendor IDs and product IDs of the device.
+@end deffn
+@end deffn
+
@deffn {Interface Driver} {opendous}
opendous-jtag is a freely programmable USB adapter.
@end deffn
@@ -3104,6 +3123,48 @@ opendous-jtag is a freely programmable USB adapter.
This is the Keil ULINK v1 JTAG debugger.
@end deffn
+@deffn {Interface Driver} {xds110}
+The XDS110 is included as the embedded debug probe on many Texas Instruments
+LaunchPad evaluation boards. The XDS110 is also available as a stand-alone USB
+debug probe with the added capability to supply power to the target board. The
+following commands are supported by the XDS110 driver:
+
+@deffn {Config Command} {xds110 serial} serial_string
+Specifies the serial number of which XDS110 probe to use. Otherwise, the first
+XDS110 found will be used.
+@end deffn
+
+@deffn {Config Command} {xds110 supply} voltage_in_millivolts
+Available only on the XDS110 stand-alone probe. Sets the voltage level of the
+XDS110 power supply. A value of 0 leaves the supply off. Otherwise, the supply
+can be set to any value in the range 1800 to 3600 millivolts.
+@end deffn
+
+@deffn {Command} {xds110 info}
+Displays information about the connected XDS110 debug probe (e.g. firmware
+version).
+@end deffn
+@end deffn
+
+@deffn {Interface Driver} {xlnx_pcie_xvc}
+This driver supports the Xilinx Virtual Cable (XVC) over PCI Express.
+It is commonly found in Xilinx based PCI Express designs. It allows debugging
+fabric based JTAG devices such as Cortex-M1/M3 microcontrollers. Access to this is
+exposed via extended capability registers in the PCI Express configuration space.
+
+For more information see Xilinx PG245 (Section on From_PCIE_to_JTAG mode).
+
+@deffn {Config Command} {xlnx_pcie_xvc_config} device
+Specifies the PCI Express device via parameter @var{device} to use.
+
+The correct value for @var{device} can be obtained by looking at the output
+of lscpi -D (first column) for the corresponding device.
+
+The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1".
+
+@end deffn
+@end deffn
+
@deffn {Interface Driver} {ZY1000}
This is the Zylin ZY1000 JTAG debugger.
@end deffn
@@ -3204,9 +3265,10 @@ JTAG supports both debugging and boundary scan testing.
Flash programming support is built on top of debug support.
JTAG transport is selected with the command @command{transport select
-jtag}. Unless your adapter uses @ref{hla_interface,the hla interface
-driver}, in which case the command is @command{transport select
-hla_jtag}.
+jtag}. Unless your adapter uses either @ref{hla_interface,the hla interface
+driver} (in which case the command is @command{transport select hla_jtag})
+or @ref{st_link_dap_interface,the st-link interface driver} (in which case
+the command is @command{transport select dapdirect_jtag}).
@subsection SWD Transport
@cindex SWD
@@ -3219,9 +3281,10 @@ Flash programming support is built on top of debug support.
(Some processors support both JTAG and SWD.)
SWD transport is selected with the command @command{transport select
-swd}. Unless your adapter uses @ref{hla_interface,the hla interface
-driver}, in which case the command is @command{transport select
-hla_swd}.
+swd}. Unless your adapter uses either @ref{hla_interface,the hla interface
+driver} (in which case the command is @command{transport select hla_swd})
+or @ref{st_link_dap_interface,the st-link interface driver} (in which case
+the command is @command{transport select dapdirect_swd}).
@deffn Command {swd newdap} ...
Declares a single DAP which uses SWD transport.
@@ -3241,6 +3304,24 @@ 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
+@cindex Single Wire Interface Module
+The Single Wire Interface Module (SWIM) is a low-pin-count debug protocol used
+by the STMicroelectronics MCU family STM8 and documented in the
+@uref{https://www.st.com/resource/en/user_manual/cd00173911.pdf, User Manual UM470}.
+
+SWIM does not support boundary scan testing nor multiple cores.
+
+The SWIM transport is selected with the command @command{transport select swim}.
+
+The concept of TAPs does not fit in the protocol since SWIM does not implement
+a scan chain. Nevertheless, the current SW model of OpenOCD requires defining a
+virtual SWIM TAP through the command @command{swim newtap basename tap_type}.
+The TAP definition must precede the target definition command
+@command{target create target_name stm8 -chain-position basename.tap_type}.
+
@anchor{jtagspeed}
@section JTAG Speed
JTAG clock setup is part of system setup.
@@ -3282,10 +3363,10 @@ However, it introduces delays to synchronize clocks; so it
may not be the fastest solution.
@b{NOTE:} Script writers should consider using @command{jtag_rclk}
-instead of @command{adapter_khz}, but only for (ARM) cores and boards
+instead of @command{adapter speed}, but only for (ARM) cores and boards
which support adaptive clocking.
-@deffn {Command} adapter_khz max_speed_kHz
+@deffn {Command} adapter speed max_speed_kHz
A non-zero speed is in KHZ. Hence: 3000 is 3mhz.
JTAG interfaces usually support a limited number of
speeds. The speed actually used won't be faster
@@ -3415,7 +3496,7 @@ stops issuing the reset. For example, there may be chip or board
requirements that all reset pulses last for at least a
certain amount of time; and reset buttons commonly have
hardware debouncing.
-Use the @command{adapter_nsrst_delay} and @command{jtag_ntrst_delay}
+Use the @command{adapter srst delay} and @command{jtag_ntrst_delay}
commands to say when extra delays are needed.
@item @emph{Drive type} ... Reset lines often have a pullup
@@ -3455,13 +3536,13 @@ needing to cope with both architecture and board specific constraints.
@section Commands for Handling Resets
-@deffn {Command} adapter_nsrst_assert_width milliseconds
+@deffn {Command} adapter srst pulse_width milliseconds
Minimum amount of time (in milliseconds) OpenOCD should wait
after asserting nSRST (active-low system reset) before
allowing it to be deasserted.
@end deffn
-@deffn {Command} adapter_nsrst_delay milliseconds
+@deffn {Command} adapter srst delay milliseconds
How long (in milliseconds) OpenOCD should wait after deasserting
nSRST (active-low system reset) before starting new JTAG operations.
When a board has a reset button connected to SRST line it will
@@ -3599,7 +3680,8 @@ the @command{reset_config} mechanism doesn't address;
or asserting both might trigger a stronger reset, which
needs special attention.
-Experiment with lower level operations, such as @command{jtag_reset}
+Experiment with lower level operations, such as
+@command{adapter assert}, @command{adapter deassert}
and the @command{jtag arp_*} operations shown here,
to find a sequence of operations that works.
@xref{JTAG Commands}.
@@ -3626,7 +3708,7 @@ or potentially some other value.
The default implementation just invokes @command{jtag arp_init-reset}.
Replacements will normally build on low level JTAG
-operations such as @command{jtag_reset}.
+operations such as @command{adapter assert} and @command{adapter deassert}.
Operations here must not address individual TAPs
(or their associated targets)
until the JTAG scan chain has first been verified to work.
@@ -4351,34 +4433,41 @@ Lists all supported target types.
At this writing, the supported CPU types are:
@itemize @bullet
-@item @code{arm11} -- this is a generation of ARMv6 cores
-@item @code{arm720t} -- this is an ARMv4 core with an MMU
-@item @code{arm7tdmi} -- this is an ARMv4 core
-@item @code{arm920t} -- this is an ARMv4 core with an MMU
-@item @code{arm926ejs} -- this is an ARMv5 core with an MMU
-@item @code{arm966e} -- this is an ARMv5 core
-@item @code{arm9tdmi} -- this is an ARMv4 core
+@item @code{aarch64} -- this is an ARMv8-A core with an MMU.
+@item @code{arm11} -- this is a generation of ARMv6 cores.
+@item @code{arm720t} -- this is an ARMv4 core with an MMU.
+@item @code{arm7tdmi} -- this is an ARMv4 core.
+@item @code{arm920t} -- this is an ARMv4 core with an MMU.
+@item @code{arm926ejs} -- this is an ARMv5 core with an MMU.
+@item @code{arm946e} -- this is an ARMv5 core with an MMU.
+@item @code{arm966e} -- this is an ARMv5 core.
+@item @code{arm9tdmi} -- this is an ARMv4 core.
@item @code{avr} -- implements Atmel's 8-bit AVR instruction set.
(Support for this is preliminary and incomplete.)
-@item @code{cortex_a} -- this is an ARMv7 core with an MMU
-@item @code{cortex_m} -- this is an ARMv7 core, supporting only the
-compact Thumb2 instruction set.
-@item @code{aarch64} -- this is an ARMv8-A core with an MMU
-@item @code{dragonite} -- resembles arm966e
+@item @code{avr32_ap7k} -- this an AVR32 core.
+@item @code{cortex_a} -- this is an ARMv7-A core with an MMU.
+@item @code{cortex_m} -- this is an ARMv7-M core, supporting only the
+compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores
+@item @code{cortex_r4} -- this is an ARMv7-R core.
+@item @code{dragonite} -- resembles arm966e.
@item @code{dsp563xx} -- implements Freescale's 24-bit DSP.
(Support for this is still incomplete.)
+@item @code{dsp5680xx} -- implements Freescale's 5680x DSP.
@item @code{esirisc} -- this is an EnSilica eSi-RISC core.
The current implementation supports eSi-32xx cores.
-@item @code{fa526} -- resembles arm920 (w/o Thumb)
-@item @code{feroceon} -- resembles arm926
-@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs.
-@item @code{mips_m4k} -- a MIPS core
-@item @code{xscale} -- this is actually an architecture,
-not a CPU type. It is based on the ARMv5 architecture.
-@item @code{openrisc} -- this is an OpenRISC 1000 core.
-The current implementation supports three JTAG TAP cores:
+@item @code{fa526} -- resembles arm920 (w/o Thumb).
+@item @code{feroceon} -- resembles arm926.
+@item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link.
@item @code{ls1_sap} -- this is the SAP on NXP LS102x CPUs,
allowing access to physical memory addresses independently of CPU cores.
+@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs.
+@item @code{mips_m4k} -- a MIPS core.
+@item @code{mips_mips64} -- a MIPS64 core.
+@item @code{nds32_v2} -- this is an Andes NDS32 v2 core.
+@item @code{nds32_v3} -- this is an Andes NDS32 v3 core.
+@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core.
+@item @code{or1k} -- this is an OpenRISC 1000 core.
+The current implementation supports three JTAG TAP cores:
@itemize @minus
@item @code{OpenCores TAP} (See: @url{http://opencores.org/project@comma{}jtag})
@item @code{Altera Virtual JTAG TAP} (See: @url{http://www.altera.com/literature/ug/ug_virtualjtag.pdf})
@@ -4389,6 +4478,13 @@ And two debug interfaces cores:
@item @code{Advanced debug interface} (See: @url{http://opencores.org/project@comma{}adv_debug_sys})
@item @code{SoC Debug Interface} (See: @url{http://opencores.org/project@comma{}dbg_interface})
@end itemize
+@item @code{quark_d20xx} -- an Intel Quark D20xx core.
+@item @code{quark_x10xx} -- an Intel Quark X10xx core.
+@item @code{riscv} -- a RISC-V core.
+@item @code{stm8} -- implements an STM8 core.
+@item @code{testee} -- a dummy target for cases without a real CPU, e.g. CPLD.
+@item @code{xscale} -- this is actually an architecture,
+not a CPU type. It is based on the ARMv5 architecture.
@end itemize
@end deffn
@@ -4771,6 +4867,8 @@ The following target events are defined:
@* Before target examine is called.
@item @b{examine-end}
@* After target examine is called with no errors.
+@item @b{examine-fail}
+@* After target examine fails.
@item @b{gdb-attach}
@* When GDB connects. Issued before any GDB communication with the target
starts. GDB expects the target is halted during attachment.
@@ -4841,7 +4939,7 @@ the target clocks are fully set up.)
before @command{reset-assert-pre} is called.
This is the most robust place to use @command{jtag_rclk}
-or @command{adapter_khz} to switch to a low JTAG clock rate,
+or @command{adapter speed} to switch to a low JTAG clock rate,
when reset disables PLLs needed to use a fast clock.
@item @b{resume-start}
@* Before any target is resumed
@@ -4849,6 +4947,10 @@ when reset disables PLLs needed to use a fast clock.
@* After all targets have resumed
@item @b{resumed}
@* Target has resumed
+@item @b{step-start}
+@* Before a target is single-stepped
+@item @b{step-end}
+@* After single-step has completed
@item @b{trace-config}
@* After target hardware trace configuration was changed
@end itemize
@@ -4949,6 +5051,20 @@ flash drivers can distinguish between probing and autoprobing,
but most don't bother.
@end deffn
+@section Preparing a Target before Flash Programming
+
+The target device should be in well defined state before the flash programming
+begins.
+
+@emph{Always issue} @command{reset init} before @ref{flashprogrammingcommands,,Flash Programming Commands}.
+Do not issue another @command{reset} or @command{reset halt} or @command{resume}
+until the programming session is finished.
+
+If you use @ref{programmingusinggdb,,Programming using GDB},
+the target is prepared automatically in the event gdb-flash-erase-start
+
+The jimtcl script @command{program} calls @command{reset init} explicitly.
+
@section Erasing, Reading, Writing to Flash
@cindex flash erasing
@cindex flash reading
@@ -5011,10 +5127,11 @@ If @option{unlock} is specified, then the flash is unprotected
before erase starts.
@end deffn
-@deffn Command {flash fillw} address word length
+@deffn Command {flash filld} address double-word length
+@deffnx Command {flash fillw} address word length
@deffnx Command {flash fillh} address halfword length
@deffnx Command {flash fillb} address byte length
-Fills flash memory with the specified @var{word} (32 bits),
+Fills flash memory with the specified @var{double-word} (64 bits), @var{word} (32 bits),
@var{halfword} (16 bits), or @var{byte} (8-bit) pattern,
starting at @var{address} and continuing
for @var{length} units (word/halfword/byte).
@@ -5027,6 +5144,19 @@ each block, and the specified length must stay within that bank.
@end deffn
@comment no current checks for errors if fill blocks touch multiple banks!
+@deffn Command {flash mdw} addr [count]
+@deffnx Command {flash mdh} addr [count]
+@deffnx Command {flash mdb} addr [count]
+Display contents of address @var{addr}, as
+32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}),
+or 8-bit bytes (@command{mdb}).
+If @var{count} is specified, displays that many units.
+Reads from flash using the flash driver, therefore it enables reading
+from a bank not mapped in target address space.
+The flash bank to use is inferred from the @var{address} of
+each block, and the specified length must stay within that bank.
+@end deffn
+
@deffn Command {flash write_bank} num filename [offset]
Write the binary @file{filename} to flash bank @var{num},
starting at @var{offset} bytes from the beginning of the bank. If @var{offset}
@@ -5124,7 +5254,7 @@ command or the flash driver then it defaults to 0xff.
@end deffn
@anchor{program}
-@deffn Command {program} filename [verify] [reset] [exit] [offset]
+@deffn Command {program} filename [preverify] [verify] [reset] [exit] [offset]
This is a helper script that simplifies using OpenOCD as a standalone
programmer. The only required parameter is @option{filename}, the others are optional.
@xref{Flash Programming}.
@@ -5766,7 +5896,7 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory.
@end deffn
@deffn {Flash Driver} bluenrg-x
-STMicroelectronics BlueNRG-1 and BlueNRG-2 Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0 core and internal flash memory.
+STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory.
The driver automatically recognizes these chips using
the chip identification registers, and autoconfigures itself.
@@ -5778,11 +5908,7 @@ Note that when users ask to erase all the sectors of the flash, a mass erase com
each single sector one by one.
@example
-flash erase_sector 0 0 79 # It will perform a mass erase on BlueNRG-1
-@end example
-
-@example
-flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2
+flash erase_sector 0 0 last # It will perform a mass erase
@end example
Triggering a mass erase is also useful when users want to disable readout protection.
@@ -5931,7 +6057,8 @@ Used in kinetis 'fcf_source protection' mode only.
@end deffn
@deffn Command {kinetis mdm check_security}
-Checks status of device security lock. Used internally in examine-end event.
+Checks status of device security lock. Used internally in examine-end
+and examine-fail event.
@end deffn
@deffn Command {kinetis mdm halt}
@@ -6239,14 +6366,14 @@ if @{ [info exists IMEMORY] && [string equal $IMEMORY true] @} @{
All versions of the SimpleLink MSP432 microcontrollers from Texas
Instruments include internal flash. The msp432 flash driver automatically
recognizes the specific version's flash parameters and autoconfigures itself.
-Main program flash (starting at address 0) is flash bank 0. Information flash
-region on MSP432P4 versions (starting at address 0x200000) is flash bank 1.
+Main program flash starts at address 0. The information flash region on
+MSP432P4 versions starts at address 0x200000.
@example
flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME
@end example
-@deffn Command {msp432 mass_erase} [main|all]
+@deffn Command {msp432 mass_erase} bank_id [main|all]
Performs a complete erase of flash. By default, @command{mass_erase} will erase
only the main program flash.
@@ -6255,7 +6382,7 @@ main program and information flash regions. To also erase the BSL in information
flash, the user must first use the @command{bsl} command.
@end deffn
-@deffn Command {msp432 bsl} [unlock|lock]
+@deffn Command {msp432 bsl} bank_id [unlock|lock]
On MSP432P4 versions, @command{bsl} unlocks and locks the bootstrap loader (BSL)
region in information flash so that flash commands can erase or write the BSL.
Leave the BSL locked to prevent accidentally corrupting the bootstrap loader.
@@ -6349,6 +6476,10 @@ works only for chips that do not have factory pre-programmed region 0
code.
@end deffn
+@deffn Command {nrf5 info}
+Decodes and shows information from FICR and UICR registers.
+@end deffn
+
@end deffn
@deffn {Flash Driver} ocl
@@ -6751,10 +6882,41 @@ The @var{num} parameter is a value shown by @command{flash banks}.
Mass erases the entire stm32h7x device.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
+
+@deffn Command {stm32h7x option_read} num reg_offset
+Reads an option byte register from the stm32h7x device.
+The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset}
+is the register offset of the option byte to read from the used bank registers' base.
+For example: in STM32H74x/H75x the bank 1 registers' base is 0x52002000 and 0x52002100 for bank 2.
+
+Example usage:
+@example
+# read OPTSR_CUR
+stm32h7x option_read 0 0x1c
+# read WPSN_CUR1R
+stm32h7x option_read 0 0x38
+# read WPSN_CUR2R
+stm32h7x option_read 1 0x38
+@end example
+@end deffn
+
+@deffn Command {stm32h7x option_write} num reg_offset value [reg_mask]
+Writes an option byte register of the stm32h7x device.
+The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset}
+is the register offset of the option byte to write from the used bank register base,
+and @var{reg_mask} is the mask to apply when writing the register (only bits with a '1'
+will be touched).
+
+Example usage:
+@example
+# swap bank 1 and bank 2 in dual bank devices, by setting SWAP_BANK_OPT bit in OPTSR_PRG
+stm32h7x option_write 0 0x20 0x8000000 0x8000000
+@end example
+@end deffn
@end deffn
@deffn {Flash Driver} stm32lx
-All members of the STM32L microcontroller families from STMicroelectronics
+All members of the STM32L0 and STM32L1 microcontroller families from STMicroelectronics
include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores.
The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself.
@@ -6794,8 +6956,10 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@deffn {Flash Driver} stm32l4x
-All members of the STM32L4 microcontroller families from STMicroelectronics
-include internal flash and use ARM Cortex-M4 cores.
+All members of the STM32L4, STM32L4+, STM32WB, STM32WL and STM32G4
+microcontroller families from STMicroelectronics include internal flash
+and use ARM Cortex-M4 cores.
+Additionally this driver supports STM32G0 family with ARM Cortex-M0+ core.
The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself.
@@ -6805,7 +6969,8 @@ flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
Note that some devices have been found that have a flash size register that contains
an invalid value, to workaround this issue you can override the probed value used by
-the flash driver.
+the flash driver. However, specifying a wrong value might lead to a completely
+wrong flash layout, so this feature must be used carefully.
@example
flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME
@@ -6836,7 +7001,9 @@ is the register offset of the Option byte to read.
For example to read the FLASH_OPTR register:
@example
stm32l4x option_read 0 0x20
-# Option Register: <0x40022020> = 0xffeff8aa
+# Option Register (for STM32L4x): <0x40022020> = 0xffeff8aa
+# Option Register (for STM32WBx): <0x58004020> = ...
+# The correct flash base address will be used automatically
@end example
The above example will read out the FLASH_OPTR register which contains the RDP
@@ -6860,7 +7027,7 @@ This will effectively write protect all sectors in flash bank 1.
@end deffn
@deffn Command {stm32l4x option_load} num
-Forces a re-load of the option byte registers. Will cause a reset of the device.
+Forces a re-load of the option byte registers. Will cause a system reset of the device.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@end deffn
@@ -6935,7 +7102,7 @@ configured for flash bank 0.
@example
# assert srst, we do not want core running
# while accessing str9xpec flash driver
-jtag_reset 0 1
+adapter assert srst
# turn off target polling
poll off
# disable str9 core
@@ -7503,7 +7670,7 @@ change any behavior.
@chapter Flash Programming
OpenOCD implements numerous ways to program the target flash, whether internal or external.
-Programming can be achieved by either using GDB @ref{programmingusinggdb,,Programming using GDB},
+Programming can be achieved by either using @ref{programmingusinggdb,,Programming using GDB},
or using the commands given in @ref{flashprogrammingcommands,,Flash Programming Commands}.
@*To simplify using the flash commands directly a jimtcl script is available that handles the programming and verify stage.
@@ -7514,6 +7681,7 @@ The script is executed as follows and by default the following actions will be p
@item 'init' is executed.
@item 'reset init' is called to reset and halt the target, any 'reset init' scripts are executed.
@item @code{flash write_image} is called to erase and write any flash using the filename given.
+@item If the @option{preverify} parameter is given, the target is "verified" first and only flashed if this fails.
@item @code{verify_image} is called if @option{verify} parameter is given.
@item @code{reset run} is called if @option{reset} parameter is given.
@item OpenOCD is shutdown if @option{exit} parameter is given.
@@ -7689,9 +7857,9 @@ echo "Downloading kernel -- please wait"
@end example
@end deffn
-@deffn Command log_output [filename]
-Redirect logging to @var{filename};
-the initial log output channel is stderr.
+@deffn Command log_output [filename | "default"]
+Redirect logging to @var{filename} or set it back to default output;
+the default log output channel is stderr.
@end deffn
@deffn Command add_script_search_dir [directory]
@@ -7835,6 +8003,36 @@ the code that was executed may have left the hardware in an unknown
state.
@end deffn
+@deffn Command {adapter assert} [signal [assert|deassert signal]]
+@deffnx Command {adapter deassert} [signal [assert|deassert signal]]
+Set values of reset signals.
+Without parameters returns current status of the signals.
+The @var{signal} parameter values may be
+@option{srst}, indicating that srst signal is to be asserted or deasserted,
+@option{trst}, indicating that trst signal is to be asserted or deasserted.
+
+The @command{reset_config} command should already have been used
+to configure how the board and the adapter treat these two
+signals, and to say if either signal is even present.
+@xref{Reset Configuration}.
+Trying to assert a signal that is not present triggers an error.
+If a signal is present on the adapter and not specified in the command,
+the signal will not be modified.
+
+@quotation Note
+TRST is specially handled.
+It actually signifies JTAG's @sc{reset} state.
+So if the board doesn't support the optional TRST signal,
+or it doesn't support it along with the specified SRST value,
+JTAG reset is triggered with TMS and TCK signals
+instead of the TRST signal.
+And no matter how that JTAG reset is triggered, once
+the scan chain enters @sc{reset} with TRST inactive,
+TAP @code{post-reset} events are delivered to all TAPs
+with handlers for that event.
+@end quotation
+@end deffn
+
@section I/O Utilities
These commands are available when
@@ -8029,8 +8227,8 @@ in which case it will be a hardware breakpoint.
for similar mechanisms that do not consume hardware breakpoints.)
@end deffn
-@deffn Command {rbp} address
-Remove the breakpoint at @var{address}.
+@deffn Command {rbp} @option{all} | address
+Remove the breakpoint at @var{address} or all breakpoints.
@end deffn
@deffn Command {rwp} address
@@ -8386,6 +8584,15 @@ Write @var{value} to the CTI register with the symbolic name @var{reg_name}.
Print the value read from the CTI register with the symbolic name @var{reg_name}.
@end deffn
+@deffn Command {$cti_name ack} @var{event}
+Acknowledge a CTI @var{event}.
+@end deffn
+
+@deffn Command {$cti_name channel} @var{channel_number} @var{operation}
+Perform a specific channel operation, the possible operations are:
+gate, ungate, set, clear and pulse
+@end deffn
+
@deffn Command {$cti_name testmode} @option{on|off}
Enable (@option{on}) or disable (@option{off}) the integration test mode
of the CTI.
@@ -9557,6 +9764,141 @@ Perform a 32-bit DMI read at address, returning the value.
Perform a 32-bit DMI write of value at address.
@end deffn
+@section ARC Architecture
+@cindex ARC
+
+Synopsys DesignWare ARC Processors are a family of 32-bit CPUs that SoC
+designers can optimize for a wide range of uses, from deeply embedded to
+high-performance host applications in a variety of market segments. See more
+at: http://www.synopsys.com/IP/ProcessorIP/ARCProcessors/Pages/default.aspx.
+OpenOCD currently supports ARC EM processors.
+There is a set ARC-specific OpenOCD commands that allow low-level
+access to the core and provide necessary support for ARC extensibility and
+configurability capabilities. ARC processors has much more configuration
+capabilities than most of the other processors and in addition there is an
+extension interface that allows SoC designers to add custom registers and
+instructions. For the OpenOCD that mostly means that set of core and AUX
+registers in target will vary and is not fixed for a particular processor
+model. To enable extensibility several TCL commands are provided that allow to
+describe those optional registers in OpenOCD configuration files. Moreover
+those commands allow for a dynamic target features discovery.
+
+
+@subsection General ARC commands
+
+@deffn {Config Command} {arc add-reg} configparams
+
+Add a new register to processor target. By default newly created register is
+marked as not existing. @var{configparams} must have following required
+arguments:
+
+@itemize @bullet
+
+@item @code{-name} name
+@*Name of a register.
+
+@item @code{-num} number
+@*Architectural register number: core register number or AUX register number.
+
+@item @code{-feature} XML_feature
+@*Name of GDB XML target description feature.
+
+@end itemize
+
+@var{configparams} may have following optional arguments:
+
+@itemize @bullet
+
+@item @code{-gdbnum} number
+@*GDB register number. It is recommended to not assign GDB register number
+manually, because there would be a risk that two register will have same
+number. When register GDB number is not set with this option, then register
+will get a previous register number + 1. This option is required only for those
+registers that must be at particular address expected by GDB.
+
+@item @code{-core}
+@*This option specifies that register is a core registers. If not - this is an
+AUX register. AUX registers and core registers reside in different address
+spaces.
+
+@item @code{-bcr}
+@*This options specifies that register is a BCR register. BCR means Build
+Configuration Registers - this is a special type of AUX registers that are read
+only and non-volatile, that is - they never change their value. Therefore OpenOCD
+never invalidates values of those registers in internal caches. Because BCR is a
+type of AUX registers, this option cannot be used with @code{-core}.
+
+@item @code{-type} type_name
+@*Name of type of this register. This can be either one of the basic GDB types,
+or a custom types described with @command{arc add-reg-type-[flags|struct]}.
+
+@item @code{-g}
+@* If specified then this is a "general" register. General registers are always
+read by OpenOCD on context save (when core has just been halted) and is always
+transferred to GDB client in a response to g-packet. Contrary to this,
+non-general registers are read and sent to GDB client on-demand. In general it
+is not recommended to apply this option to custom registers.
+
+@end itemize
+
+@end deffn
+
+@deffn {Config Command} {arc add-reg-type-flags} -name name flags...
+Adds new register type of ``flags'' class. ``Flags'' types can contain only
+one-bit fields. Each flag definition looks like @code{-flag name bit-position}.
+@end deffn
+
+@anchor{add-reg-type-struct}
+@deffn {Config Command} {arc add-reg-type-struct} -name name structs...
+Adds new register type of ``struct'' class. ``Struct'' types can contain either
+bit-fields or fields of other types, however at the moment only bit fields are
+supported. Structure bit field definition looks like @code{-bitfield name
+startbit endbit}.
+@end deffn
+
+@deffn {Command} {arc get-reg-field} reg-name field-name
+Returns value of bit-field in a register. Register must be ``struct'' register
+type, @xref{add-reg-type-struct} command definition.
+@end deffn
+
+@deffn {Command} {arc set-reg-exists} reg-names...
+Specify that some register exists. Any amount of names can be passed
+as an argument for a single command invocation.
+@end deffn
+
+@subsection ARC JTAG commands
+
+@deffn {Command} {arc jtag set-aux-reg} regnum value
+This command writes value to AUX register via its number. This command access
+register in target directly via JTAG, bypassing any OpenOCD internal caches,
+therefore it is unsafe to use if that register can be operated by other means.
+
+@end deffn
+
+@deffn {Command} {arc jtag set-core-reg} regnum value
+This command is similar to @command{arc jtag set-aux-reg} but is for core
+registers.
+@end deffn
+
+@deffn {Command} {arc jtag get-aux-reg} regnum
+This command returns the value storded in AUX register via its number. This commands access
+register in target directly via JTAG, bypassing any OpenOCD internal caches,
+therefore it is unsafe to use if that register can be operated by other means.
+
+@end deffn
+
+@deffn {Command} {arc jtag get-core-reg} regnum
+This command is similar to @command{arc jtag get-aux-reg} but is for core
+registers.
+@end deffn
+
+@section STM8 Architecture
+@uref{http://st.com/stm8/, STM8} is a 8-bit microcontroller platform from
+STMicroelectronics, based on a proprietary 8-bit core architecture.
+
+OpenOCD supports debugging STM8 through the STMicroelectronics debug
+protocol SWIM, @pxref{swimtransport,,SWIM}.
+
@anchor{softwaredebugmessagesandtracing}
@section Software Debug Messages and Tracing
@cindex Linux-ARM DCC support
@@ -9751,28 +10093,6 @@ portable scripts currently must issue only BYPASS instructions.
@end quotation
@end deffn
-@deffn Command {jtag_reset} trst srst
-Set values of reset signals.
-The @var{trst} and @var{srst} parameter values may be
-@option{0}, indicating that reset is inactive (pulled or driven high),
-or @option{1}, indicating it is active (pulled or driven low).
-The @command{reset_config} command should already have been used
-to configure how the board and JTAG adapter treat these two
-signals, and to say if either signal is even present.
-@xref{Reset Configuration}.
-
-Note that TRST is specially handled.
-It actually signifies JTAG's @sc{reset} state.
-So if the board doesn't support the optional TRST signal,
-or it doesn't support it along with the specified SRST value,
-JTAG reset is triggered with TMS and TCK signals
-instead of the TRST signal.
-And no matter how that JTAG reset is triggered, once
-the scan chain enters @sc{reset} with TRST inactive,
-TAP @code{post-reset} events are delivered to all TAPs
-with handlers for that event.
-@end deffn
-
@deffn Command {pathmove} start_state [next_state ...]
Start by moving to @var{start_state}, which
must be one of the @emph{stable} states.
@@ -10662,7 +10982,7 @@ To set the JTAG frequency use the command:
@example
# Example: 1.234MHz
-adapter_khz 1234
+adapter speed 1234
@end example
@@ -10740,7 +11060,7 @@ bytes. Painful...
"Warning: arm7_9_common.c:679 arm7_9_assert_reset(): srst resets test logic, too".
This warning doesn't indicate any serious problem, as long as you don't want to
-debug your core right out of reset. Your .cfg file specified @option{jtag_reset
+debug your core right out of reset. Your .cfg file specified @option{reset_config
trst_and_srst srst_pulls_trst} to tell OpenOCD that either your board,
your debugger or your target uC (e.g. LPC2000) can't assert the two reset signals
independently. With this setup, it's not possible to halt the core right out of
diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c
index b9ac793f2..baef5d59c 100644
--- a/src/flash/nand/core.c
+++ b/src/flash/nand/core.c
@@ -263,6 +263,7 @@ int nand_read_status(struct nand_device *nand, uint8_t *status)
return ERROR_NAND_DEVICE_NOT_PROBED;
/* Send read status command */
+ /* FIXME: errors returned from nand->controller are mostly ignored! */
nand->controller->command(nand, NAND_CMD_STATUS);
alive_sleep(1);
@@ -301,7 +302,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout)
int nand_probe(struct nand_device *nand)
{
uint8_t manufacturer_id, device_id;
- uint8_t id_buff[6];
+ uint8_t id_buff[6] = { 0 }; /* zero buff to silence false warning
+ * from clang static analyzer */
int retval;
int i;
@@ -392,19 +394,34 @@ int nand_probe(struct nand_device *nand)
if (nand->device->page_size == 0 ||
nand->device->erase_size == 0) {
if (nand->bus_width == 8) {
- nand->controller->read_data(nand, id_buff + 3);
- nand->controller->read_data(nand, id_buff + 4);
- nand->controller->read_data(nand, id_buff + 5);
+ retval = nand->controller->read_data(nand, id_buff + 3);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = nand->controller->read_data(nand, id_buff + 4);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = nand->controller->read_data(nand, id_buff + 5);
+ if (retval != ERROR_OK)
+ return retval;
+
} else {
uint16_t data_buf;
- nand->controller->read_data(nand, &data_buf);
+ retval = nand->controller->read_data(nand, &data_buf);
+ if (retval != ERROR_OK)
+ return retval;
id_buff[3] = data_buf;
- nand->controller->read_data(nand, &data_buf);
+ retval = nand->controller->read_data(nand, &data_buf);
+ if (retval != ERROR_OK)
+ return retval;
id_buff[4] = data_buf;
- nand->controller->read_data(nand, &data_buf);
+ retval = nand->controller->read_data(nand, &data_buf);
+ if (retval != ERROR_OK)
+ return retval;
id_buff[5] = data_buf >> 8;
}
}
diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c
index 17e6f680d..167b40150 100644
--- a/src/flash/nand/davinci.c
+++ b/src/flash/nand/davinci.c
@@ -730,7 +730,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
goto fail;
}
- info = calloc(1, sizeof *info);
+ info = calloc(1, sizeof(*info));
if (info == NULL)
goto fail;
diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c
index 5fdc92305..da141b742 100644
--- a/src/flash/nand/mx3.c
+++ b/src/flash/nand/mx3.c
@@ -685,7 +685,6 @@ static int do_data_output(struct nand_device *nand)
case 2 << 2:
LOG_DEBUG("main area readed with more than 1 (incorrectable) error");
return ERROR_NAND_OPERATION_FAILED;
- break;
}
switch (ecc_status & 0x0003) {
case 1:
@@ -694,7 +693,6 @@ static int do_data_output(struct nand_device *nand)
case 2:
LOG_DEBUG("main area readed with more than 1 (incorrectable) error");
return ERROR_NAND_OPERATION_FAILED;
- break;
}
}
break;
diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c
index b54115731..ee093c056 100644
--- a/src/flash/nand/mxc.c
+++ b/src/flash/nand/mxc.c
@@ -874,7 +874,6 @@ int ecc_status_v1(struct nand_device *nand)
case 2 << 2:
LOG_INFO("main area read with more than 1 (incorrectable) error");
return ERROR_NAND_OPERATION_FAILED;
- break;
}
switch (ecc_status & 0x0003) {
case 1:
@@ -883,7 +882,6 @@ int ecc_status_v1(struct nand_device *nand)
case 2:
LOG_INFO("main area read with more than 1 (incorrectable) error");
return ERROR_NAND_OPERATION_FAILED;
- break;
}
return ERROR_OK;
}
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 34f91ce1e..b95b003df 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -51,6 +51,8 @@ NOR_DRIVERS = \
%D%/psoc4.c \
%D%/psoc5lp.c \
%D%/psoc6.c \
+ %D%/renesas_rpchf.c \
+ %D%/sh_qspi.c \
%D%/sim3x.c \
%D%/spi.c \
%D%/stmsmi.c \
@@ -74,6 +76,7 @@ NOR_DRIVERS = \
NORHEADERS = \
%D%/core.h \
%D%/cc3220sf.h \
+ %D%/bluenrg-x.h \
%D%/cc26xx.h \
%D%/cfi.h \
%D%/driver.h \
@@ -81,4 +84,5 @@ NORHEADERS = \
%D%/non_cfi.h \
%D%/ocl.h \
%D%/spi.h \
+ %D%/stm32l4x.h \
%D%/msp432.h
diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c
index f468c89a5..7c5596d48 100644
--- a/src/flash/nor/aducm360.c
+++ b/src/flash/nor/aducm360.c
@@ -434,10 +434,8 @@ static int aducm360_write_block(struct flash_bank *bank,
switch (choice) {
case 0:
return aducm360_write_block_sync(bank, buffer, offset, count);
- break;
case 1:
return aducm360_write_block_async(bank, buffer, offset, count);
- break;
default:
LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c
index b1e3e72a9..b41b15c07 100644
--- a/src/flash/nor/ambiqmicro.c
+++ b/src/flash/nor/ambiqmicro.c
@@ -253,8 +253,7 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank)
}
- if (ambiqmicro_info->target_class <
- (sizeof(ambiqmicroParts)/sizeof(ambiqmicroParts[0])))
+ if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicroParts))
ambiqmicro_info->target_name =
ambiqmicroParts[ambiqmicro_info->target_class].partname;
else
diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c
index 2457c15f3..c9ffa653b 100644
--- a/src/flash/nor/at91sam3.c
+++ b/src/flash/nor/at91sam3.c
@@ -3068,7 +3068,6 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
((unsigned int)(FLASH_BANK1_BASE_256K_AX)),
((unsigned int)(FLASH_BANK1_BASE_512K_AX)));
return ERROR_FAIL;
- break;
/* at91sam3s and at91sam3n series only has bank 0*/
/* at91sam3u and at91sam3ax series has the same address for bank 0*/
@@ -3621,10 +3620,8 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command)
switch (CMD_ARGC) {
default:
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
case 0:
goto showall;
- break;
case 1:
who = -1;
break;
@@ -3653,7 +3650,8 @@ showall:
}
if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
- command_print(CMD, "sam3-gpnvm%u: %u", who, v);
+ if (r == ERROR_OK)
+ command_print(CMD, "sam3-gpnvm%u: %u", who, v);
return r;
} else {
command_print(CMD, "sam3-gpnvm invalid GPNVM: %u", who);
@@ -3707,7 +3705,6 @@ COMMAND_HANDLER(sam3_handle_slowclk_command)
/* error */
command_print(CMD, "Too many parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
}
command_print(CMD, "Slowclk freq: %d.%03dkhz",
(int)(pChip->cfg.slow_freq / 1000),
@@ -3729,7 +3726,7 @@ static const struct command_registration at91sam3_exec_command_handlers[] = {
.name = "info",
.handler = sam3_handle_info_command,
.mode = COMMAND_EXEC,
- .help = "Print information about the current at91sam3 chip"
+ .help = "Print information about the current at91sam3 chip "
"and its flash configuration.",
.usage = "",
},
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index 621754c90..5b56c4241 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -2482,7 +2482,6 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command)
((unsigned int)(bank->base)),
((unsigned int)(FLASH_BANK_BASE_S)));
return ERROR_FAIL;
- break;
/* at91sam4s series only has bank 0*/
/* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/
@@ -3101,10 +3100,8 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command)
switch (CMD_ARGC) {
default:
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
case 0:
goto showall;
- break;
case 1:
who = -1;
break;
@@ -3188,7 +3185,6 @@ COMMAND_HANDLER(sam4_handle_slowclk_command)
/* error */
command_print(CMD, "Too many parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
}
command_print(CMD, "Slowclk freq: %d.%03dkhz",
(int)(pChip->cfg.slow_freq / 1000),
@@ -3210,7 +3206,7 @@ static const struct command_registration at91sam4_exec_command_handlers[] = {
.name = "info",
.handler = sam4_handle_info_command,
.mode = COMMAND_EXEC,
- .help = "Print information about the current at91sam4 chip"
+ .help = "Print information about the current at91sam4 chip "
"and its flash configuration.",
.usage = "",
},
diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c
index d356398dc..d4bfe5310 100644
--- a/src/flash/nor/at91sam4l.c
+++ b/src/flash/nor/at91sam4l.c
@@ -601,6 +601,7 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer,
/* There's at least one aligned page to write out. */
if (count >= chip->page_size) {
+ assert(chip->page_size > 0);
int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0);
for (int i = 0; i < np; i++) {
diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c
index 232260b93..039746c16 100644
--- a/src/flash/nor/at91sam7.c
+++ b/src/flash/nor/at91sam7.c
@@ -711,8 +711,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
uint16_t page_size;
uint16_t num_nvmbits;
- char *target_name_t;
-
int bnk, sec;
at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
@@ -753,9 +751,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
return ERROR_OK;
}
- target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
- strcpy(target_name_t, CMD_ARGV[7]);
-
/* calculate bank size */
bank_size = num_sectors * pages_per_sector * page_size;
@@ -794,7 +789,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
at91sam7_info = t_bank->driver_priv;
- at91sam7_info->target_name = target_name_t;
+ at91sam7_info->target_name = strdup(CMD_ARGV[7]);
at91sam7_info->flashmode = 0;
at91sam7_info->ext_freq = ext_freq;
at91sam7_info->num_nvmbits = num_nvmbits;
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index b6cff9a67..6e89099ab 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -181,6 +181,23 @@ static const struct samd_part samd21_parts[] = {
{ 0x26, "SAMD21E16B", 64, 8 },
{ 0x27, "SAMD21E15B", 32, 4 },
+ /* SAMD21 D and L Variants (from Errata)
+ http://ww1.microchip.com/downloads/en/DeviceDoc/
+ SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */
+ { 0x55, "SAMD21E16BU", 64, 8 },
+ { 0x56, "SAMD21E15BU", 32, 4 },
+ { 0x57, "SAMD21G16L", 64, 8 },
+ { 0x3E, "SAMD21E16L", 64, 8 },
+ { 0x3F, "SAMD21E15L", 32, 4 },
+ { 0x62, "SAMD21E16CU", 64, 8 },
+ { 0x63, "SAMD21E15CU", 32, 4 },
+ { 0x92, "SAMD21J17D", 128, 16 },
+ { 0x93, "SAMD21G17D", 128, 16 },
+ { 0x94, "SAMD21E17D", 128, 16 },
+ { 0x95, "SAMD21E17DU", 128, 16 },
+ { 0x96, "SAMD21G17L", 128, 16 },
+ { 0x97, "SAMD21E17L", 128, 16 },
+
/* Known SAMDA1 parts.
SAMD-A1 series uses the same series identifier like the SAMD21
taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */
diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c
index d6f1a0a48..9a53369a7 100644
--- a/src/flash/nor/atsamv.c
+++ b/src/flash/nor/atsamv.c
@@ -375,7 +375,6 @@ static int samv_probe(struct flash_bank *bank)
default:
LOG_ERROR("unrecognized flash size code: %d", nvm_size_code);
return ERROR_FAIL;
- break;
}
struct samv_flash_bank *samv_info = bank->driver_priv;
@@ -645,7 +644,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command)
switch (CMD_ARGC) {
case 0:
goto showall;
- break;
case 1:
who = -1;
break;
@@ -660,7 +658,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command)
break;
default:
return ERROR_COMMAND_SYNTAX_ERROR;
- break;
}
uint32_t v;
diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c
index 178567e6b..93f6872bd 100644
--- a/src/flash/nor/avrf.c
+++ b/src/flash/nor/avrf.c
@@ -58,7 +58,7 @@ struct avrf_type {
struct avrf_flash_bank {
int ppage_size;
- int probed;
+ bool probed;
};
static const struct avrf_type avft_chips_info[] = {
@@ -67,6 +67,7 @@ static const struct avrf_type avft_chips_info[] = {
*/
{"atmega128", 0x9702, 256, 512, 8, 512},
{"atmega128rfa1", 0xa701, 128, 512, 8, 512},
+ {"atmega256rfr2", 0xa802, 256, 1024, 8, 1024},
{"at90can128", 0x9781, 256, 512, 8, 512},
{"at90usb128", 0x9782, 256, 512, 8, 512},
{"atmega164p", 0x940a, 128, 128, 4, 128},
@@ -142,16 +143,24 @@ static int avr_jtagprg_chiperase(struct avr_common *avr)
}
static int avr_jtagprg_writeflashpage(struct avr_common *avr,
+ const bool ext_addressing,
const uint8_t *page_buf,
uint32_t buf_size,
uint32_t addr,
uint32_t page_size)
{
- uint32_t i, poll_value;
+ uint32_t poll_value;
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
+ /* load extended high byte */
+ if (ext_addressing)
+ avr_jtag_senddat(avr->jtag_info.tap,
+ NULL,
+ 0x0b00 | ((addr >> 17) & 0xFF),
+ AVR_JTAG_REG_ProgrammingCommand_Len);
+
/* load addr high byte */
avr_jtag_senddat(avr->jtag_info.tap,
NULL,
@@ -166,7 +175,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr,
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
- for (i = 0; i < page_size; i++) {
+ for (uint32_t i = 0; i < page_size; i++) {
if (i < buf_size)
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
else
@@ -204,7 +213,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
avrf_info = malloc(sizeof(struct avrf_flash_bank));
bank->driver_priv = avrf_info;
- avrf_info->probed = 0;
+ avrf_info->probed = false;
return ERROR_OK;
}
@@ -238,6 +247,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
uint32_t cur_size, cur_buffer_size, page_size;
+ bool ext_addressing;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -258,6 +268,11 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
return ERROR_FAIL;
+ if (bank->size > 0x20000)
+ ext_addressing = true;
+ else
+ ext_addressing = false;
+
cur_size = 0;
while (count > 0) {
if (count > page_size)
@@ -265,6 +280,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
else
cur_buffer_size = count;
avr_jtagprg_writeflashpage(avr,
+ ext_addressing,
buffer + cur_size,
cur_buffer_size,
offset + cur_size,
@@ -288,7 +304,6 @@ static int avrf_probe(struct flash_bank *bank)
struct avrf_flash_bank *avrf_info = bank->driver_priv;
struct avr_common *avr = target->arch_info;
const struct avrf_type *avr_info = NULL;
- int i;
uint32_t device_id;
if (bank->target->state != TARGET_HALTED) {
@@ -296,7 +311,7 @@ static int avrf_probe(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
- avrf_info->probed = 0;
+ avrf_info->probed = false;
avr_jtag_read_jtagid(avr, &device_id);
if (ERROR_OK != mcu_execute_queue())
@@ -308,7 +323,7 @@ static int avrf_probe(struct flash_bank *bank)
EXTRACT_MFG(device_id),
0x1F);
- for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) {
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
avr_info = &avft_chips_info[i];
LOG_INFO("target device is %s", avr_info->name);
@@ -328,20 +343,20 @@ static int avrf_probe(struct flash_bank *bank)
bank->num_sectors = avr_info->flash_page_num;
bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
- for (i = 0; i < avr_info->flash_page_num; i++) {
+ for (int i = 0; i < avr_info->flash_page_num; i++) {
bank->sectors[i].offset = i * avr_info->flash_page_size;
bank->sectors[i].size = avr_info->flash_page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
- avrf_info->probed = 1;
+ avrf_info->probed = true;
return ERROR_OK;
} else {
/* chip not supported */
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
- avrf_info->probed = 1;
+ avrf_info->probed = true;
return ERROR_FAIL;
}
}
@@ -359,7 +374,6 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
const struct avrf_type *avr_info = NULL;
- int i;
uint32_t device_id;
if (bank->target->state != TARGET_HALTED) {
@@ -377,7 +391,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
EXTRACT_MFG(device_id),
0x1F);
- for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) {
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
avr_info = &avft_chips_info[i];
LOG_INFO("target device is %s", avr_info->name);
@@ -418,8 +432,6 @@ static int avrf_mass_erase(struct flash_bank *bank)
COMMAND_HANDLER(avrf_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -430,7 +442,7 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command)
if (avrf_mass_erase(bank) == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "avr mass erase complete");
diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c
index f6a249273..fbce20d55 100644
--- a/src/flash/nor/bluenrg-x.c
+++ b/src/flash/nor/bluenrg-x.c
@@ -24,35 +24,62 @@
#include
#include
#include "imp.h"
+#include "bluenrg-x.h"
-#define FLASH_SIZE_REG (0x40100014)
-#define DIE_ID_REG (0x4090001C)
-#define JTAG_IDCODE_REG (0x40900028)
-#define BLUENRG2_IDCODE (0x0200A041)
-#define FLASH_BASE (0x10040000)
-#define FLASH_PAGE_SIZE (2048)
-#define FLASH_REG_COMMAND (0x40100000)
-#define FLASH_REG_IRQRAW (0x40100010)
-#define FLASH_REG_ADDRESS (0x40100018)
-#define FLASH_REG_DATA (0x40100040)
-#define FLASH_CMD_ERASE_PAGE 0x11
-#define FLASH_CMD_MASSERASE 0x22
-#define FLASH_CMD_WRITE 0x33
-#define FLASH_CMD_BURSTWRITE 0xCC
-#define FLASH_INT_CMDDONE 0x01
-#define FLASH_WORD_LEN 4
+#define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg)
+#define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg)
-struct bluenrgx_flash_bank {
- int probed;
- uint32_t idcode;
- uint32_t die_id;
+#define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg)
+#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg)
+#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size)
+
+struct flash_ctrl_priv_data {
+ uint32_t die_id_reg;
+ uint32_t jtag_idcode_reg;
+ uint32_t flash_base;
+ uint32_t flash_regs_base;
+ uint32_t flash_page_size;
+ uint32_t jtag_idcode;
+ char *part_name;
};
-static int bluenrgx_protect_check(struct flash_bank *bank)
-{
- /* Nothing to do. Protection is only handled in SW. */
- return ERROR_OK;
-}
+const struct flash_ctrl_priv_data flash_priv_data_1 = {
+ .die_id_reg = 0x4090001C,
+ .jtag_idcode_reg = 0x40900028,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40100000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x00000000,
+ .part_name = "BLUENRG-1",
+};
+
+const struct flash_ctrl_priv_data flash_priv_data_2 = {
+ .die_id_reg = 0x4090001C,
+ .jtag_idcode_reg = 0x40900028,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40100000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x0200A041,
+ .part_name = "BLUENRG-2",
+};
+
+const struct flash_ctrl_priv_data flash_priv_data_lp = {
+ .die_id_reg = 0x40000000,
+ .jtag_idcode_reg = 0x40000004,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40001000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x0201E041,
+ .part_name = "BLUENRG-LP",
+};
+
+struct bluenrgx_flash_bank {
+ bool probed;
+ uint32_t die_id;
+ const struct flash_ctrl_priv_data *flash_ptr;
+};
+
+const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp};
/* flash_bank bluenrg-x 0 0 0 0 */
FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
@@ -67,9 +94,12 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
return ERROR_FAIL;
}
+ bank->write_start_alignment = 16;
+ bank->write_end_alignment = 16;
+
bank->driver_priv = bluenrgx_info;
- bluenrgx_info->probed = 0;
+ bluenrgx_info->probed = false;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -77,6 +107,22 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
return ERROR_OK;
}
+static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
+{
+ struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+ return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset;
+}
+
+static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
+{
+ return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
+}
+
+static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
+}
+
static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
{
int retval = ERROR_OK;
@@ -87,7 +133,7 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
uint32_t address, command;
/* check preconditions */
- if (bluenrgx_info->probed == 0)
+ if (!bluenrgx_info->probed)
return ERROR_FLASH_BANK_NOT_PROBED;
if (bank->target->state != TARGET_HALTED) {
@@ -103,24 +149,25 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
if (mass_erase) {
command = FLASH_CMD_MASSERASE;
address = bank->base;
- if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
+ (address - bank->base) >> 2) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- for (int i = 0; i < 100; i++) {
+ for (unsigned int i = 0; i < 100; i++) {
uint32_t value;
- if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
+ if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
@@ -135,26 +182,28 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
} else {
command = FLASH_CMD_ERASE_PAGE;
for (int i = first; i <= last; i++) {
- address = bank->base+i*FLASH_PAGE_SIZE;
+ address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info);
+ LOG_DEBUG("address = %08x, index = %d", address, i);
- if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
+ (address - bank->base) >> 2) != ERROR_OK) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
- if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
LOG_ERROR("Failed");
return ERROR_FAIL;
}
- for (int j = 0; j < 100; j++) {
+ for (unsigned int j = 0; j < 100; j++) {
uint32_t value;
- if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
+ if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
LOG_ERROR("Register write failed");
return ERROR_FAIL;
}
@@ -172,140 +221,10 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
}
-static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last)
-{
- /* Protection is only handled in software: no hardware write protection
- available in BlueNRG-x devices */
- int sector;
-
- for (sector = first; sector <= last; sector++)
- bank->sectors[sector].is_protected = set;
- return ERROR_OK;
-}
-static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count)
-{
- int retval = ERROR_OK;
-
- retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- for (uint32_t i = 0; i < count; i++) {
- uint32_t address = address_base + i * FLASH_WORD_LEN;
-
- retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE);
- if (retval != ERROR_OK) {
- LOG_ERROR("Register write failed, error code: %d", retval);
- return retval;
- }
-
- for (int j = 0; j < 100; j++) {
- uint32_t reg_value;
- retval = target_read_u32(target, FLASH_REG_IRQRAW, ®_value);
-
- if (retval != ERROR_OK) {
- LOG_ERROR("Register read failed, error code: %d", retval);
- return retval;
- }
-
- if (reg_value & FLASH_INT_CMDDONE)
- break;
-
- if (j == 99) {
- LOG_ERROR("Write command failed (timeout)");
- return ERROR_FAIL;
- }
- }
- }
- return retval;
-}
-
-static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count)
-{
- int retval = ERROR_OK;
- uint8_t *new_buffer = NULL;
- uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address;
-
- if (count == 0) {
- /* Just return if there are no bytes to write */
- return retval;
- }
-
- if (address_base & 3) {
- pre_bytes = address_base & 3;
- pre_address = address_base - pre_bytes;
- }
-
- if ((count + pre_bytes) & 3) {
- post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes);
- post_address = (address_base + count) & ~3;
- }
-
- if (pre_bytes || post_bytes) {
- uint32_t old_count = count;
-
- count = old_count + pre_bytes + post_bytes;
-
- new_buffer = malloc(count);
-
- if (new_buffer == NULL) {
- LOG_ERROR("odd number of bytes to write and no memory "
- "for padding buffer");
- return ERROR_FAIL;
- }
-
- LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %"
- PRIu32 " ", old_count, count);
-
- if (pre_bytes) {
- if (target_read_u32(target, pre_address, &pre_word)) {
- LOG_ERROR("Memory read failed");
- free(new_buffer);
- return ERROR_FAIL;
- }
-
- }
-
- if (post_bytes) {
- if (target_read_u32(target, post_address, &post_word)) {
- LOG_ERROR("Memory read failed");
- free(new_buffer);
- return ERROR_FAIL;
- }
-
- }
-
- memcpy(new_buffer, &pre_word, pre_bytes);
- memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4);
- memcpy(new_buffer+pre_bytes, buffer, old_count);
- buffer = new_buffer;
- }
-
- retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4);
-
- if (new_buffer)
- free(new_buffer);
-
- return retval;
-}
-
static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
+ struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size = 16384 + 8;
struct working_area *write_algorithm;
@@ -313,10 +232,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
struct working_area *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[5];
+ struct mem_param mem_params[1];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
- uint32_t pre_size = 0, fast_size = 0, post_size = 0;
- uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0;
/* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and
* hints how to generate the data!
@@ -325,6 +243,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
};
+ /* check preconditions */
+ if (!bluenrgx_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
if ((offset + count) > bank->size) {
LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d",
(offset + count),
@@ -337,132 +259,105 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_TARGET_NOT_HALTED;
}
- /* We are good here and we need to compute pre_size, fast_size, post_size */
- pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset);
- pre_offset = offset;
- fast_size = 16*((count - pre_size) / 16);
- fast_offset = offset + pre_size;
- post_size = (count-pre_size-fast_size) % 16;
- post_offset = fast_offset + fast_size;
-
- LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset);
- LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset);
- LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset);
-
- /* Program initial chunk not 16 bytes aligned */
- retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size);
- if (retval) {
- LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
- return ERROR_FAIL;
+ if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
+ &write_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- /* Program chunk 16 bytes aligned in fast mode */
- if (fast_size) {
+ retval = target_write_buffer(target, write_algorithm->address,
+ sizeof(bluenrgx_flash_write_code),
+ bluenrgx_flash_write_code);
+ if (retval != ERROR_OK)
+ return retval;
- if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
- &write_algorithm) != ERROR_OK) {
- LOG_WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ /* memory buffer */
+ if (target_alloc_working_area(target, buffer_size, &source)) {
+ LOG_WARNING("no large enough working area available");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
- retval = target_write_buffer(target, write_algorithm->address,
- sizeof(bluenrgx_flash_write_code),
- bluenrgx_flash_write_code);
- if (retval != ERROR_OK)
- return retval;
+ /* Stack pointer area */
+ if (target_alloc_working_area(target, 128,
+ &write_algorithm_sp) != ERROR_OK) {
+ LOG_DEBUG("no working area for write code stack pointer");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
- /* memory buffer */
- if (target_alloc_working_area(target, buffer_size, &source)) {
- LOG_WARNING("no large enough working area available");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ armv7m_info.core_mode = ARM_MODE_THREAD;
- /* Stack pointer area */
- if (target_alloc_working_area(target, 64,
- &write_algorithm_sp) != ERROR_OK) {
- LOG_DEBUG("no working area for write code stack pointer");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
+ init_reg_param(®_params[4], "sp", 32, PARAM_OUT);
+ /* Put the parameter at the first available stack location */
+ init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT);
- armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
- armv7m_info.core_mode = ARM_MODE_THREAD;
+ /* FIFO start address (first two words used for write and read pointers) */
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);
+ /* FIFO end address (first two words used for write and read pointers) */
+ buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
+ /* Flash memory address */
+ buf_set_u32(reg_params[2].value, 0, 32, address);
+ /* Number of bytes */
+ buf_set_u32(reg_params[3].value, 0, 32, count);
+ /* Stack pointer for program working area */
+ buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
+ /* Flash register base address */
+ buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base);
- init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
- init_reg_param(®_params[4], "sp", 32, PARAM_OUT);
+ LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
+ LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
+ LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
+ LOG_DEBUG("address = %08x", address);
+ LOG_DEBUG("count = %08x", count);
- /* FIFO start address (first two words used for write and read pointers) */
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- /* FIFO end address (first two words used for write and read pointers) */
- buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
- /* Flash memory address */
- buf_set_u32(reg_params[2].value, 0, 32, address+pre_size);
- /* Number of bytes */
- buf_set_u32(reg_params[3].value, 0, 32, fast_size);
- /* Stack pointer for program working area */
- buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
+ retval = target_run_flash_async_algorithm(target,
+ buffer,
+ count/16,
+ 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
+ 1,
+ mem_params,
+ 5,
+ reg_params,
+ source->address,
+ source->size,
+ write_algorithm->address,
+ 0,
+ &armv7m_info);
- LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
- LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
- LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
- LOG_DEBUG("address = %08x", address+pre_size);
- LOG_DEBUG("count = %08x", count);
+ if (retval == ERROR_FLASH_OPERATION_FAILED) {
+ LOG_ERROR("error executing bluenrg-x flash write algorithm");
- retval = target_run_flash_async_algorithm(target,
- buffer+pre_size,
- fast_size/16,
- 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
- 0,
- NULL,
- 5,
- reg_params,
- source->address,
- source->size,
- write_algorithm->address,
- 0,
- &armv7m_info);
+ uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
- if (retval == ERROR_FLASH_OPERATION_FAILED) {
- LOG_ERROR("error executing bluenrg-x flash write algorithm");
-
- uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
-
- if (error != 0)
- LOG_ERROR("flash write failed = %08" PRIx32, error);
- }
+ if (error != 0)
+ LOG_ERROR("flash write failed = %08" PRIx32, error);
+ }
+ if (retval == ERROR_OK) {
+ uint32_t rp;
+ /* Read back rp and check that is valid */
+ retval = target_read_u32(target, source->address+4, &rp);
if (retval == ERROR_OK) {
- uint32_t rp;
- /* Read back rp and check that is valid */
- retval = target_read_u32(target, source->address+4, &rp);
- if (retval == ERROR_OK) {
- if ((rp < source->address+8) || (rp > (source->address + source->size))) {
- LOG_ERROR("flash write failed = %08" PRIx32, rp);
- retval = ERROR_FLASH_OPERATION_FAILED;
- }
+ if ((rp < source->address+8) || (rp > (source->address + source->size))) {
+ LOG_ERROR("flash write failed = %08" PRIx32, rp);
+ retval = ERROR_FLASH_OPERATION_FAILED;
}
}
- target_free_working_area(target, source);
- target_free_working_area(target, write_algorithm);
- target_free_working_area(target, write_algorithm_sp);
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_params[4]);
- if (retval != ERROR_OK)
- return retval;
-
}
+ target_free_working_area(target, source);
+ target_free_working_area(target, write_algorithm);
+ target_free_working_area(target, write_algorithm_sp);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+ destroy_mem_param(&mem_params[0]);
- /* Program chunk at end, not addressable by fast burst write algorithm */
- retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size);
- if (retval) {
- LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
- return ERROR_FAIL;
- }
return retval;
}
@@ -470,33 +365,50 @@ static int bluenrgx_probe(struct flash_bank *bank)
{
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
uint32_t idcode, size_info, die_id;
- int i;
- int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode);
- if (retval != ERROR_OK)
- return retval;
- retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info);
+ int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode);
+
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(bank->target, DIE_ID_REG, &die_id);
+ if (idcode != flash_priv_data_lp.jtag_idcode) {
+ retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* Default device is BlueNRG-1 */
+ bluenrgx_info->flash_ptr = &flash_priv_data_1;
+ bank->base = flash_priv_data_1.flash_base;
+
+ for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) {
+ if (idcode == (*flash_ctrl[i]).jtag_idcode) {
+ bluenrgx_info->flash_ptr = flash_ctrl[i];
+ bank->base = (*flash_ctrl[i]).flash_base;
+ break;
+ }
+ }
+ retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info);
if (retval != ERROR_OK)
return retval;
- bank->size = (size_info + 1) * 4;
- bank->base = FLASH_BASE;
- bank->num_sectors = bank->size/FLASH_PAGE_SIZE;
+ retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id);
+ if (retval != ERROR_OK)
+ return retval;
+
+ bank->size = (size_info + 1) * FLASH_WORD_LEN;
+ bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
- for (i = 0; i < bank->num_sectors; i++) {
- bank->sectors[i].offset = i * FLASH_PAGE_SIZE;
- bank->sectors[i].size = FLASH_PAGE_SIZE;
+ for (int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info);
+ bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
}
- bluenrgx_info->probed = 1;
+ bluenrgx_info->probed = true;
bluenrgx_info->die_id = die_id;
- bluenrgx_info->idcode = idcode;
+
return ERROR_OK;
}
@@ -515,7 +427,6 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
int mask_number, cut_number;
- char *part_name;
if (!bluenrgx_info->probed) {
int retval = bluenrgx_probe(bank);
@@ -526,16 +437,11 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
}
}
- if (bluenrgx_info->idcode == BLUENRG2_IDCODE)
- part_name = "BLUENRG-2";
- else
- part_name = "BLUENRG-1";
-
mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
cut_number = bluenrgx_info->die_id & 0xF;
snprintf(buf, buf_size,
- "%s - Rev: %d.%d", part_name, mask_number, cut_number);
+ "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number);
return ERROR_OK;
}
@@ -543,12 +449,12 @@ const struct flash_driver bluenrgx_flash = {
.name = "bluenrg-x",
.flash_bank_command = bluenrgx_flash_bank_command,
.erase = bluenrgx_erase,
- .protect = bluenrgx_protect,
+ .protect = NULL,
.write = bluenrgx_write,
.read = default_flash_read,
.probe = bluenrgx_probe,
.erase_check = default_flash_blank_check,
- .protect_check = bluenrgx_protect_check,
+ .protect_check = NULL,
.auto_probe = bluenrgx_auto_probe,
.info = bluenrgx_get_info,
};
diff --git a/src/jtag/drivers/libusb_common.h b/src/flash/nor/bluenrg-x.h
similarity index 57%
rename from src/jtag/drivers/libusb_common.h
rename to src/flash/nor/bluenrg-x.h
index 599a0a9b0..3b84b8b19 100644
--- a/src/jtag/drivers/libusb_common.h
+++ b/src/flash/nor/bluenrg-x.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2011 by Mauro Gamba *
+ * Copyright (C) 2019 by STMicroelectronics. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -15,13 +15,31 @@
* along with this program. If not, see . *
***************************************************************************/
-#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H
-#define OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H
+#ifndef OPENOCD_FLASH_NOR_BLUENRGX_H
+#define OPENOCD_FLASH_NOR_BLUENRGX_H
-#ifdef HAVE_LIBUSB1
-#include "libusb1_common.h"
-#else
-#include "libusb0_common.h"
-#endif
+/* Flash Controller registers offsets */
+#define FLASH_REG_COMMAND 0x00
+#define FLASH_REG_CONFIG 0x04
+#define FLASH_REG_IRQSTAT 0x08
+#define FLASH_REG_IRQMASK 0x0C
+#define FLASH_REG_IRQRAW 0x10
+#define FLASH_REG_ADDRESS 0x18
+#define FLASH_REG_UNLOCKM 0x1C
+#define FLASH_REG_UNLOCKL 0x20
+#define FLASH_REG_DATA0 0x40
+#define FLASH_REG_DATA1 0x44
+#define FLASH_REG_DATA2 0x48
+#define FLASH_REG_DATA3 0x4C
+#define FLASH_SIZE_REG 0x14
-#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H */
+/* Flash Controller commands */
+#define FLASH_CMD_ERASE_PAGE 0x11
+#define FLASH_CMD_MASSERASE 0x22
+#define FLASH_CMD_WRITE 0x33
+#define FLASH_CMD_BURSTWRITE 0xCC
+#define FLASH_INT_CMDDONE 0x01
+
+#define FLASH_WORD_LEN 4
+
+#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */
diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c
index afdb7f491..c8de7d002 100644
--- a/src/flash/nor/cc3220sf.c
+++ b/src/flash/nor/cc3220sf.c
@@ -363,6 +363,8 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_ERROR("cc3220sf: Flash operation failed");
break;
}
+
+ keep_alive();
}
/* Do one word write for any final bytes less than a full word */
diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c
index 04fa83b55..50ab207c1 100644
--- a/src/flash/nor/cfi.c
+++ b/src/flash/nor/cfi.c
@@ -34,9 +34,6 @@
#include
#include
-#define CFI_MAX_BUS_WIDTH 4
-#define CFI_MAX_CHIP_WIDTH 4
-
/* defines internal maximum size for code fragment in cfi_intel_write_block() */
#define CFI_MAX_INTEL_CODESIZE 256
@@ -103,16 +100,15 @@ static const struct cfi_fixup cfi_0001_fixups[] = {
static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- const struct cfi_fixup *f;
- for (f = fixups; f->fixup; f++) {
+ for (const struct cfi_fixup *f = fixups; f->fixup; f++) {
if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) &&
((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id)))
f->fixup(bank, f->param);
}
}
-static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset)
+uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -131,32 +127,55 @@ static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32
}
}
+static int cfi_target_write_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, const uint8_t *buffer)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ if (cfi_info->write_mem) {
+ return cfi_info->write_mem(bank, addr, count, buffer);
+ } else {
+ return target_write_memory(bank->target, addr, bank->bus_width,
+ count, buffer);
+ }
+}
+
+int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ if (cfi_info->read_mem) {
+ return cfi_info->read_mem(bank, addr, count, buffer);
+ } else {
+ return target_read_memory(bank->target, addr, bank->bus_width,
+ count, buffer);
+ }
+}
+
static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
{
- int i;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
/* clear whole buffer, to ensure bits that exceed the bus_width
* are set to zero
*/
- for (i = 0; i < CFI_MAX_BUS_WIDTH; i++)
+ for (size_t i = 0; i < CFI_MAX_BUS_WIDTH; i++)
cmd_buf[i] = 0;
if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) {
- for (i = bank->bus_width; i > 0; i--)
+ for (int i = bank->bus_width; i > 0; i--)
*cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
} else {
- for (i = 1; i <= bank->bus_width; i++)
+ for (int i = 1; i <= bank->bus_width; i++)
*cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
}
}
-static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address)
+int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address)
{
uint8_t command[CFI_MAX_BUS_WIDTH];
cfi_command(bank, cmd, command);
- return target_write_memory(bank->target, address, bank->bus_width, 1, command);
+ return cfi_target_write_memory(bank, address, 1, command);
}
/* read unsigned 8-bit value from the bank
@@ -165,13 +184,12 @@ static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t addre
*/
static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH];
int retval;
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 1, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 1, data);
if (retval != ERROR_OK)
return retval;
@@ -189,25 +207,23 @@ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, ui
*/
static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH];
- int i;
int retval;
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 1, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 1, data);
if (retval != ERROR_OK)
return retval;
if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) {
- for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+ for (int i = 0; i < bank->bus_width / bank->chip_width; i++)
data[0] |= data[i];
*val = data[0];
} else {
uint8_t value = 0;
- for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+ for (int i = 0; i < bank->bus_width / bank->chip_width; i++)
value |= data[bank->bus_width - 1 - i];
*val = value;
@@ -217,22 +233,20 @@ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint
static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, uint16_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH * 2];
int retval;
if (cfi_info->x16_as_x8) {
- uint8_t i;
- for (i = 0; i < 2; i++) {
- retval = target_read_memory(target, flash_address(bank, sector, offset + i),
- bank->bus_width, 1, &data[i * bank->bus_width]);
+ for (uint8_t i = 0; i < 2; i++) {
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i),
+ 1, &data[i * bank->bus_width]);
if (retval != ERROR_OK)
return retval;
}
} else {
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 2, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 2, data);
if (retval != ERROR_OK)
return retval;
}
@@ -247,22 +261,20 @@ static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, u
static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, uint32_t *val)
{
- struct target *target = bank->target;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
uint8_t data[CFI_MAX_BUS_WIDTH * 4];
int retval;
if (cfi_info->x16_as_x8) {
- uint8_t i;
- for (i = 0; i < 4; i++) {
- retval = target_read_memory(target, flash_address(bank, sector, offset + i),
- bank->bus_width, 1, &data[i * bank->bus_width]);
+ for (uint8_t i = 0; i < 4; i++) {
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i),
+ 1, &data[i * bank->bus_width]);
if (retval != ERROR_OK)
return retval;
}
} else {
- retval = target_read_memory(target, flash_address(bank, sector, offset),
- bank->bus_width, 4, data);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset),
+ 4, data);
if (retval != ERROR_OK)
return retval;
}
@@ -278,16 +290,16 @@ static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, u
return ERROR_OK;
}
-static int cfi_reset(struct flash_bank *bank)
+int cfi_reset(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
int retval = ERROR_OK;
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -295,7 +307,7 @@ static int cfi_reset(struct flash_bank *bank)
(cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E)) {
/* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state
* so we send an extra 0xF0 reset to fix the bug */
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x00));
if (retval != ERROR_OK)
return retval;
}
@@ -305,7 +317,7 @@ static int cfi_reset(struct flash_bank *bank)
static void cfi_intel_clear_status_register(struct flash_bank *bank)
{
- cfi_send_command(bank, 0x50, flash_address(bank, 0, 0x0));
+ cfi_send_command(bank, 0x50, cfi_flash_address(bank, 0, 0x0));
}
static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint8_t *val)
@@ -359,7 +371,7 @@ static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint
return retval;
}
-static int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
+int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
{
uint8_t status, oldstatus;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -534,7 +546,7 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank)
pri_ext->_reversed_geometry = 0;
if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
LOG_ERROR("Could not read spansion bank information");
@@ -641,7 +653,7 @@ static int cfi_read_atmel_pri_ext(struct flash_bank *bank)
if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R')
|| (atmel_pri_ext.pri[2] != 'I')) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
LOG_ERROR("Could not read atmel bank information");
@@ -799,14 +811,12 @@ static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
-/* flash_bank cfi [options]
- */
-FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
+int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv)
{
struct cfi_flash_bank *cfi_info;
int bus_swap = 0;
- if (CMD_ARGC < 6)
+ if (argc < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
/* both widths must:
@@ -826,7 +836,7 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
}
cfi_info = malloc(sizeof(struct cfi_flash_bank));
- cfi_info->probed = 0;
+ cfi_info->probed = false;
cfi_info->erase_region_info = NULL;
cfi_info->pri_ext = NULL;
bank->driver_priv = cfi_info;
@@ -836,14 +846,14 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
cfi_info->not_cfi = 0;
cfi_info->data_swap = 0;
- for (unsigned i = 6; i < CMD_ARGC; i++) {
- if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0)
+ for (unsigned i = 6; i < argc; i++) {
+ if (strcmp(argv[i], "x16_as_x8") == 0)
cfi_info->x16_as_x8 = 1;
- else if (strcmp(CMD_ARGV[i], "data_swap") == 0)
+ else if (strcmp(argv[i], "data_swap") == 0)
cfi_info->data_swap = 1;
- else if (strcmp(CMD_ARGV[i], "bus_swap") == 0)
+ else if (strcmp(argv[i], "bus_swap") == 0)
bus_swap = 1;
- else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0)
+ else if (strcmp(argv[i], "jedec_probe") == 0)
cfi_info->jedec_probe = 1;
}
@@ -860,20 +870,26 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
return ERROR_OK;
}
+/* flash_bank cfi [options]
+ */
+FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
+{
+ return cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV);
+}
+
static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- int i;
cfi_intel_clear_status_register(bank);
- for (i = first; i <= last; i++) {
- retval = cfi_send_command(bank, 0x20, flash_address(bank, i, 0x0));
+ for (int i = first; i <= last; i++) {
+ retval = cfi_send_command(bank, 0x20, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -885,7 +901,7 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
if (status == 0x80)
bank->sectors[i].is_erased = 1;
else {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -895,7 +911,24 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
}
}
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
+}
+
+int cfi_spansion_unlock_seq(struct flash_bank *bank)
+{
+ int retval;
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+ retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, pri_ext->_unlock1));
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, pri_ext->_unlock2));
+ if (retval != ERROR_OK)
+ return retval;
+
+ return ERROR_OK;
}
static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
@@ -903,37 +936,28 @@ static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
- int i;
- for (i = first; i <= last; i++) {
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
+ for (int i = first; i <= last; i++) {
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_send_command(bank, 0x80, cfi_flash_address(bank, 0, pri_ext->_unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x80, flash_address(bank, 0, pri_ext->_unlock1));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
-
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
- if (retval != ERROR_OK)
- return retval;
-
- retval = cfi_send_command(bank, 0x30, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x30, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK)
bank->sectors[i].is_erased = 1;
else {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -943,10 +967,10 @@ static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
}
}
- return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_erase(struct flash_bank *bank, int first, int last)
+int cfi_erase(struct flash_bank *bank, int first, int last)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -965,10 +989,8 @@ static int cfi_erase(struct flash_bank *bank, int first, int last)
case 1:
case 3:
return cfi_intel_erase(bank, first, last);
- break;
case 2:
return cfi_spansion_erase(bank, first, last);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -983,7 +1005,6 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
int retry = 0;
- int i;
/* if the device supports neither legacy lock/unlock (bit 3) nor
* instant individual block locking (bit 5).
@@ -995,17 +1016,17 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
cfi_intel_clear_status_register(bank);
- for (i = first; i <= last; i++) {
- retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0));
+ for (int i = first; i <= last; i++) {
+ retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
if (set) {
- retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
bank->sectors[i].is_protected = 1;
} else {
- retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
bank->sectors[i].is_protected = 0;
@@ -1022,7 +1043,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
} else {
uint8_t block_status;
/* read block lock bit, to verify status */
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55));
if (retval != ERROR_OK)
return retval;
retval = cfi_get_u8(bank, i, 0x2, &block_status);
@@ -1033,7 +1054,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
LOG_ERROR(
"couldn't change block lock status (set = %i, block_status = 0x%2.2x)",
set, block_status);
- retval = cfi_send_command(bank, 0x70, flash_address(bank, 0, 0x55));
+ retval = cfi_send_command(bank, 0x70, cfi_flash_address(bank, 0, 0x55));
if (retval != ERROR_OK)
return retval;
uint8_t status;
@@ -1066,15 +1087,15 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
* 3. re-protect what should be protected.
*
*/
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
if (bank->sectors[i].is_protected == 1) {
cfi_intel_clear_status_register(bank);
- retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0));
+ retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -1086,10 +1107,10 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
}
}
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
+int cfi_protect(struct flash_bank *bank, int set, int first, int last)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -1105,7 +1126,6 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
case 1:
case 3:
return cfi_intel_protect(bank, set, first, last);
- break;
default:
LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
return ERROR_OK;
@@ -1121,13 +1141,10 @@ static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd)
switch (bank->bus_width) {
case 1:
return buf[0];
- break;
case 2:
return target_buffer_get_u16(target, buf);
- break;
case 4:
return target_buffer_get_u32(target, buf);
- break;
default:
LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes",
bank->bus_width);
@@ -1558,9 +1575,9 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0));
buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80));
- buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
+ buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1));
buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa);
- buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
+ buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2));
buf_set_u32(reg_params[9].value, 0, 32, 0x55555555);
retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
@@ -1937,9 +1954,9 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0));
buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80));
- buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
+ buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1));
buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa);
- buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
+ buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2));
buf_set_u32(reg_params[9].value, 0, 32, 0x55555555);
retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
@@ -1981,14 +1998,13 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
cfi_intel_clear_status_register(bank);
retval = cfi_send_command(bank, 0x40, address);
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, 1, word);
+ retval = cfi_target_write_memory(bank, address, 1, word);
if (retval != ERROR_OK)
return retval;
@@ -1997,7 +2013,7 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t
if (retval != ERROR_OK)
return retval;
if (status != 0x80) {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2015,7 +2031,6 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
/* Calculate buffer size and boundary mask
* buffersize is (buffer size per chip) * (number of chips)
@@ -2052,7 +2067,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
if (retval != ERROR_OK)
return retval;
if (status != 0x80) {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2069,7 +2084,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word);
+ retval = cfi_target_write_memory(bank, address, bufferwsize, word);
if (retval != ERROR_OK)
return retval;
@@ -2083,7 +2098,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word,
return retval;
if (status != 0x80) {
- retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2100,26 +2115,21 @@ static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint3
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
- struct target *target = bank->target;
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0xa0, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
-
- retval = target_write_memory(target, address, bank->bus_width, 1, word);
+ retval = cfi_target_write_memory(bank, address, 1, word);
if (retval != ERROR_OK)
return retval;
if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2136,8 +2146,6 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
{
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
- struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
/* Calculate buffer size and boundary mask
* buffersize is (buffer size per chip) * (number of chips)
@@ -2163,11 +2171,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
}
/* Unlock */
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
-
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
@@ -2181,7 +2185,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word);
+ retval = cfi_target_write_memory(bank, address, bufferwsize, word);
if (retval != ERROR_OK)
return retval;
@@ -2191,7 +2195,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
return retval;
if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK) {
- retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
if (retval != ERROR_OK)
return retval;
@@ -2204,7 +2208,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word
return ERROR_OK;
}
-static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
+int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -2212,10 +2216,8 @@ static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t addre
case 1:
case 3:
return cfi_intel_write_word(bank, word, address);
- break;
case 2:
return cfi_spansion_write_word(bank, word, address);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -2239,10 +2241,8 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word,
case 1:
case 3:
return cfi_intel_write_words(bank, word, wordcount, address);
- break;
case 2:
return cfi_spansion_write_words(bank, word, wordcount, address);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -2254,12 +2254,10 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word,
static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
uint32_t address = bank->base + offset;
uint32_t read_p;
int align; /* number of unaligned bytes */
uint8_t current_word[CFI_MAX_BUS_WIDTH];
- int i;
int retval;
LOG_DEBUG("reading buffer of %i byte at 0x%8.8x",
@@ -2283,12 +2281,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
LOG_INFO("Fixup %d unaligned read head bytes", align);
/* read a complete word from flash */
- retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, read_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* take only bytes we need */
- for (i = align; (i < bank->bus_width) && (count > 0); i++, count--)
+ for (int i = align; (i < bank->bus_width) && (count > 0); i++, count--)
*buffer++ = current_word[i];
read_p += bank->bus_width;
@@ -2296,7 +2294,7 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
align = count / bank->bus_width;
if (align) {
- retval = target_read_memory(target, read_p, bank->bus_width, align, buffer);
+ retval = cfi_target_read_memory(bank, read_p, align, buffer);
if (retval != ERROR_OK)
return retval;
@@ -2309,12 +2307,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
LOG_INFO("Fixup %" PRIu32 " unaligned read tail bytes", count);
/* read a complete word from flash */
- retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, read_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* take only bytes we need */
- for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
+ for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
*buffer++ = current_word[i];
}
@@ -2324,7 +2322,6 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u
static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
- struct target *target = bank->target;
uint32_t address = bank->base + offset; /* address of first byte to be programmed */
uint32_t write_p;
int align; /* number of unaligned bytes */
@@ -2333,7 +2330,6 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
*programmed */
uint8_t *swapped_buffer = NULL;
const uint8_t *real_buffer = NULL;
- int i;
int retval;
if (bank->target->state != TARGET_HALTED) {
@@ -2354,12 +2350,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
LOG_INFO("Fixup %d unaligned head bytes", align);
/* read a complete word from flash */
- retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* replace only bytes that must be written */
- for (i = align;
+ for (int i = align;
(i < bank->bus_width) && (count > 0);
i++, count--)
if (cfi_info->data_swap)
@@ -2425,12 +2421,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
/* fall back to memory writes */
while (count >= (uint32_t)bank->bus_width) {
- int fallback;
+ bool fallback;
if ((write_p & 0xff) == 0) {
LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08"
PRIx32 " bytes remaining", write_p, count);
}
- fallback = 1;
+ fallback = true;
if ((bufferwsize > 0) && (count >= buffersize) &&
!(write_p & buffermask)) {
retval = cfi_write_words(bank, buffer, bufferwsize, write_p);
@@ -2438,13 +2434,13 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
buffer += buffersize;
write_p += buffersize;
count -= buffersize;
- fallback = 0;
+ fallback = false;
} else if (retval != ERROR_FLASH_OPER_UNSUPPORTED)
return retval;
}
/* try the slow way? */
if (fallback) {
- for (i = 0; i < bank->bus_width; i++)
+ for (int i = 0; i < bank->bus_width; i++)
current_word[i] = *buffer++;
retval = cfi_write_word(bank, current_word, write_p);
@@ -2474,12 +2470,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of
LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
/* read a complete word from flash */
- retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word);
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
if (retval != ERROR_OK)
return retval;
/* replace only bytes that must be written */
- for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
+ for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
if (cfi_info->data_swap)
/* data bytes are swapped (reverse endianness) */
current_word[bank->bus_width - i] = *buffer++;
@@ -2506,7 +2502,6 @@ static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void
static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param)
{
- int i;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
(void) param;
@@ -2514,7 +2509,7 @@ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *pa
if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) {
LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device");
- for (i = 0; i < cfi_info->num_erase_regions / 2; i++) {
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions / 2; i++) {
int j = (cfi_info->num_erase_regions - 1) - i;
uint32_t swap;
@@ -2549,7 +2544,7 @@ static int cfi_query_string(struct flash_bank *bank, int address)
struct cfi_flash_bank *cfi_info = bank->driver_priv;
int retval;
- retval = cfi_send_command(bank, 0x98, flash_address(bank, 0, address));
+ retval = cfi_send_command(bank, 0x98, cfi_flash_address(bank, 0, address));
if (retval != ERROR_OK)
return retval;
@@ -2577,12 +2572,11 @@ static int cfi_query_string(struct flash_bank *bank, int address)
return ERROR_OK;
}
-static int cfi_probe(struct flash_bank *bank)
+int cfi_probe(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct target *target = bank->target;
int num_sectors = 0;
- int i;
int sector = 0;
uint32_t unlock1 = 0x555;
uint32_t unlock2 = 0x2aa;
@@ -2594,7 +2588,7 @@ static int cfi_probe(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
- cfi_info->probed = 0;
+ cfi_info->probed = false;
cfi_info->num_erase_regions = 0;
if (bank->sectors) {
free(bank->sectors);
@@ -2614,22 +2608,22 @@ static int cfi_probe(struct flash_bank *bank)
}
/* switch to read identifier codes mode ("AUTOSELECT") */
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, unlock1));
+ retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, unlock2));
+ retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, unlock2));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, unlock1));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, unlock1));
if (retval != ERROR_OK)
return retval;
- retval = target_read_memory(target, flash_address(bank, 0, 0x00),
- bank->bus_width, 1, value_buf0);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x00),
+ 1, value_buf0);
if (retval != ERROR_OK)
return retval;
- retval = target_read_memory(target, flash_address(bank, 0, 0x01),
- bank->bus_width, 1, value_buf1);
+ retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x01),
+ 1, value_buf1);
if (retval != ERROR_OK)
return retval;
switch (bank->chip_width) {
@@ -2766,7 +2760,7 @@ static int cfi_probe(struct flash_bank *bank)
if (cfi_info->num_erase_regions) {
cfi_info->erase_region_info = malloc(sizeof(*cfi_info->erase_region_info)
* cfi_info->num_erase_regions);
- for (i = 0; i < cfi_info->num_erase_regions; i++) {
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) {
retval = cfi_query_u32(bank,
0,
0x2d + (4 * i),
@@ -2881,15 +2875,14 @@ static int cfi_probe(struct flash_bank *bank)
} else {
uint32_t offset = 0;
- for (i = 0; i < cfi_info->num_erase_regions; i++)
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++)
num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
bank->num_sectors = num_sectors;
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
- for (i = 0; i < cfi_info->num_erase_regions; i++) {
- uint32_t j;
- for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) {
+ for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) {
+ for (uint32_t j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) {
bank->sectors[sector].offset = offset;
bank->sectors[sector].size =
((cfi_info->erase_region_info[i] >> 16) * 256)
@@ -2902,18 +2895,18 @@ static int cfi_probe(struct flash_bank *bank)
}
if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) {
LOG_WARNING(
- "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \
+ "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "",
(cfi_info->dev_size * bank->bus_width / bank->chip_width),
offset);
}
}
- cfi_info->probed = 1;
+ cfi_info->probed = true;
return ERROR_OK;
}
-static int cfi_auto_probe(struct flash_bank *bank)
+int cfi_auto_probe(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
if (cfi_info->probed)
@@ -2926,17 +2919,16 @@ static int cfi_intel_protect_check(struct flash_bank *bank)
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
- int i;
/* check if block lock bits are supported on this device */
if (!(pri_ext->blk_status_reg_mask & 0x1))
return ERROR_FLASH_OPERATION_FAILED;
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55));
if (retval != ERROR_OK)
return retval;
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
uint8_t block_status;
retval = cfi_get_u8(bank, i, 0x2, &block_status);
if (retval != ERROR_OK)
@@ -2948,7 +2940,7 @@ static int cfi_intel_protect_check(struct flash_bank *bank)
bank->sectors[i].is_protected = 0;
}
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0));
}
static int cfi_spansion_protect_check(struct flash_bank *bank)
@@ -2956,21 +2948,16 @@ static int cfi_spansion_protect_check(struct flash_bank *bank)
int retval;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
- int i;
- retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1));
+ retval = cfi_spansion_unlock_seq(bank);
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2));
+ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, pri_ext->_unlock1));
if (retval != ERROR_OK)
return retval;
- retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, pri_ext->_unlock1));
- if (retval != ERROR_OK)
- return retval;
-
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
uint8_t block_status;
retval = cfi_get_u8(bank, i, 0x2, &block_status);
if (retval != ERROR_OK)
@@ -2982,10 +2969,10 @@ static int cfi_spansion_protect_check(struct flash_bank *bank)
bank->sectors[i].is_protected = 0;
}
- return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0));
+ return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
}
-static int cfi_protect_check(struct flash_bank *bank)
+int cfi_protect_check(struct flash_bank *bank)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -3001,10 +2988,8 @@ static int cfi_protect_check(struct flash_bank *bank)
case 1:
case 3:
return cfi_intel_protect_check(bank);
- break;
case 2:
return cfi_spansion_protect_check(bank);
- break;
default:
LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
break;
@@ -3013,7 +2998,7 @@ static int cfi_protect_check(struct flash_bank *bank)
return ERROR_OK;
}
-static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size)
+int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
int printed;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
@@ -3124,6 +3109,6 @@ const struct flash_driver cfi_flash = {
/* FIXME: access flash at bus_width size */
.erase_check = default_flash_blank_check,
.protect_check = cfi_protect_check,
- .info = get_cfi_info,
+ .info = cfi_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h
index ed858a9de..aef7a04f9 100644
--- a/src/flash/nor/cfi.h
+++ b/src/flash/nor/cfi.h
@@ -73,6 +73,12 @@ struct cfi_flash_bank {
unsigned buf_write_timeout;
unsigned block_erase_timeout;
unsigned chip_erase_timeout;
+
+ /* memory accessors */
+ int (*write_mem)(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, const uint8_t *buffer);
+ int (*read_mem)(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer);
};
/* Intel primary extended query table
@@ -148,6 +154,24 @@ struct cfi_fixup {
const void *param;
};
+int cfi_erase(struct flash_bank *bank, int first, int last);
+int cfi_protect(struct flash_bank *bank, int set, int first, int last);
+int cfi_probe(struct flash_bank *bank);
+int cfi_auto_probe(struct flash_bank *bank);
+int cfi_protect_check(struct flash_bank *bank);
+int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size);
+int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv);
+
+uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset);
+int cfi_spansion_unlock_seq(struct flash_bank *bank);
+int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address);
+int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address);
+int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout);
+int cfi_reset(struct flash_bank *bank);
+
+int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer);
+
#define CFI_MFR_AMD 0x0001
#define CFI_MFR_FUJITSU 0x0004
#define CFI_MFR_ATMEL 0x001F
@@ -160,4 +184,7 @@ struct cfi_fixup {
#define CFI_MFR_ANY 0xffff
#define CFI_ID_ANY 0xffff
+#define CFI_MAX_BUS_WIDTH 4
+#define CFI_MAX_CHIP_WIDTH 4
+
#endif /* OPENOCD_FLASH_NOR_CFI_H */
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 551f389de..d52e072ee 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -66,6 +66,8 @@ extern const struct flash_driver psoc5lp_flash;
extern const struct flash_driver psoc5lp_eeprom_flash;
extern const struct flash_driver psoc5lp_nvl_flash;
extern const struct flash_driver psoc6_flash;
+extern const struct flash_driver renesas_rpchf_flash;
+extern const struct flash_driver sh_qspi_flash;
extern const struct flash_driver sim3x_flash;
extern const struct flash_driver stellaris_flash;
extern const struct flash_driver stm32f1x_flash;
@@ -136,6 +138,8 @@ static const struct flash_driver * const flash_drivers[] = {
&psoc5lp_eeprom_flash,
&psoc5lp_nvl_flash,
&psoc6_flash,
+ &renesas_rpchf_flash,
+ &sh_qspi_flash,
&sim3x_flash,
&stellaris_flash,
&stm32f1x_flash,
diff --git a/src/flash/nor/dsp5680xx_flash.c b/src/flash/nor/dsp5680xx_flash.c
index 37b60f001..da675856f 100644
--- a/src/flash/nor/dsp5680xx_flash.c
+++ b/src/flash/nor/dsp5680xx_flash.c
@@ -154,7 +154,7 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
*
* @return
*/
-static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t* buffer,
+static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
int retval;
diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c
index 83d133ff6..fe4ddd47e 100644
--- a/src/flash/nor/efm32.c
+++ b/src/flash/nor/efm32.c
@@ -99,7 +99,7 @@ struct efm32_family_data {
};
struct efm32x_flash_bank {
- int probed;
+ bool probed;
uint32_t lb_page[LOCKBITS_PAGE_SZ/4];
uint32_t reg_base;
uint32_t reg_lock;
@@ -140,6 +140,7 @@ static const struct efm32_family_data efm32_families[] = {
{ 43, "EFR32BG13P Blue", .series = 1 },
{ 44, "EFR32BG13B Blue", .series = 1 },
{ 45, "EFR32BG13V Blue", .series = 1 },
+ { 46, "EFR32ZG13P Zen", .series = 1 },
{ 49, "EFR32FG13P Flex", .series = 1 },
{ 50, "EFR32FG13B Flex", .series = 1 },
{ 51, "EFR32FG13V Flex", .series = 1 },
@@ -149,6 +150,7 @@ static const struct efm32_family_data efm32_families[] = {
{ 55, "EFR32BG14P Blue", .series = 1 },
{ 56, "EFR32BG14B Blue", .series = 1 },
{ 57, "EFR32BG14V Blue", .series = 1 },
+ { 58, "EFR32ZG14P Zen", .series = 1 },
{ 61, "EFR32FG14P Flex", .series = 1 },
{ 62, "EFR32FG14B Flex", .series = 1 },
{ 63, "EFR32FG14V Flex", .series = 1 },
@@ -166,7 +168,8 @@ static const struct efm32_family_data efm32_families[] = {
{ 89, "EFM32PG13B Pearl", .series = 1 },
{ 91, "EFM32JG13B Jade", .series = 1 },
{ 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 },
- { 103, "EFM32TG11B Tiny", .series = 1 },
+ { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 },
+ { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 },
{ 120, "EZR32WG Wonder", .series = 0 },
{ 121, "EZR32LG Leopard", .series = 0 },
{ 122, "EZR32HG Happy", .series = 0, .page_size = 1024 },
@@ -348,7 +351,7 @@ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command)
efm32x_info = malloc(sizeof(struct efm32x_flash_bank));
bank->driver_priv = efm32x_info;
- efm32x_info->probed = 0;
+ efm32x_info->probed = false;
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
return ERROR_OK;
@@ -467,7 +470,6 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
static int efm32x_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
- int i = 0;
int ret = 0;
if (TARGET_HALTED != target->state) {
@@ -482,7 +484,7 @@ static int efm32x_erase(struct flash_bank *bank, int first, int last)
return ret;
}
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
ret = efm32x_erase_page(bank, bank->sectors[i].offset);
if (ERROR_OK != ret)
LOG_ERROR("Failed to erase page %d", i);
@@ -498,7 +500,6 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
{
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
struct target *target = bank->target;
- int i = 0;
int data_size = 0;
uint32_t *ptr = NULL;
int ret = 0;
@@ -510,7 +511,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
ptr = efm32x_info->lb_page;
- for (i = 0; i < data_size; i++, ptr++) {
+ for (int i = 0; i < data_size; i++, ptr++) {
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to read PLW %d", i);
@@ -616,7 +617,6 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set)
static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
- int i = 0;
int ret = 0;
if (!set) {
@@ -629,7 +629,7 @@ static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_TARGET_NOT_HALTED;
}
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
ret = efm32x_set_page_lock(bank, i, set);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to set lock on page %d", i);
@@ -960,11 +960,10 @@ static int efm32x_probe(struct flash_bank *bank)
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
struct efm32_info efm32_mcu_info;
int ret;
- int i;
uint32_t base_address = 0x00000000;
char buf[256];
- efm32x_info->probed = 0;
+ efm32x_info->probed = false;
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
ret = efm32x_read_info(bank, &efm32_mcu_info);
@@ -1003,14 +1002,14 @@ static int efm32x_probe(struct flash_bank *bank)
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
- for (i = 0; i < num_pages; i++) {
+ for (int i = 0; i < num_pages; i++) {
bank->sectors[i].offset = i * efm32_mcu_info.page_size;
bank->sectors[i].size = efm32_mcu_info.page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
- efm32x_info->probed = 1;
+ efm32x_info->probed = true;
return ERROR_OK;
}
@@ -1027,7 +1026,6 @@ static int efm32x_protect_check(struct flash_bank *bank)
{
struct target *target = bank->target;
int ret = 0;
- int i = 0;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -1042,7 +1040,7 @@ static int efm32x_protect_check(struct flash_bank *bank)
assert(NULL != bank->sectors);
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i);
return ERROR_OK;
diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c
index 6b0533251..bc192b677 100644
--- a/src/flash/nor/fespi.c
+++ b/src/flash/nor/fespi.c
@@ -183,7 +183,7 @@ static int fespi_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_
}
static int fespi_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value)
-{ \
+{
struct target *target = bank->target;
struct fespi_flash_bank *fespi_info = bank->driver_priv;
diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c
index a8877b4fb..7e3a1c51f 100644
--- a/src/flash/nor/fm4.c
+++ b/src/flash/nor/fm4.c
@@ -207,7 +207,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
uint32_t result;
unsigned i;
- int retval;
+ int retval, retval2 = ERROR_OK;
const uint8_t write_block_code[] = {
#include "../../../contrib/loaders/flash/fm4/write.inc"
};
@@ -327,7 +327,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
err_run_ret:
err_run:
err_write_data:
- retval = fm4_enter_flash_cpu_rom_mode(target);
+ retval2 = fm4_enter_flash_cpu_rom_mode(target);
err_flash_mode:
for (i = 0; i < ARRAY_SIZE(reg_params); i++)
@@ -338,7 +338,9 @@ err_alloc_data:
err_write_code:
target_free_working_area(target, code_workarea);
- return retval;
+ if (retval != ERROR_OK)
+ return retval;
+ return retval2;
}
static int mb9bf_probe(struct flash_bank *bank)
diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c
index a9f2dd4a4..d841579ff 100644
--- a/src/flash/nor/jtagspi.c
+++ b/src/flash/nor/jtagspi.c
@@ -59,7 +59,7 @@ static void jtagspi_set_ir(struct flash_bank *bank)
{
struct jtagspi_flash_bank *info = bank->driver_priv;
struct scan_field field;
- uint8_t buf[4];
+ uint8_t buf[4] = { 0 };
LOG_DEBUG("loading jtagspi ir");
buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
@@ -153,12 +153,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
jtagspi_set_ir(bank);
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
- jtag_execute_queue();
+ int retval = jtag_execute_queue();
if (is_read)
flip_u8(data_buf, data, lenb);
free(data_buf);
- return ERROR_OK;
+ return retval;
}
static int jtagspi_probe(struct flash_bank *bank)
@@ -228,13 +228,16 @@ static int jtagspi_probe(struct flash_bank *bank)
return ERROR_OK;
}
-static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
+static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
{
uint8_t buf;
- if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) {
+ int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8);
+ if (err == ERROR_OK) {
*status = buf;
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
}
+
+ return err;
}
static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
@@ -245,7 +248,11 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
do {
dt = timeval_ms() - t0;
- jtagspi_read_status(bank, &status);
+
+ int retval = jtagspi_read_status(bank, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
if ((status & SPIFLASH_BSY_BIT) == 0) {
LOG_DEBUG("waited %" PRId64 " ms", dt);
return ERROR_OK;
@@ -262,7 +269,11 @@ static int jtagspi_write_enable(struct flash_bank *bank)
uint32_t status;
jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0);
- jtagspi_read_status(bank, &status);
+
+ int retval = jtagspi_read_status(bank, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
if ((status & SPIFLASH_WE_BIT) == 0) {
LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
return ERROR_FAIL;
diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c
index 687a3370b..084e009ee 100644
--- a/src/flash/nor/kinetis.c
+++ b/src/flash/nor/kinetis.c
@@ -787,9 +787,8 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) {
uint32_t stats[32];
- int i;
- for (i = 0; i < 32; i++) {
+ for (unsigned int i = 0; i < 32; i++) {
stats[i] = MDM_STAT_FREADY;
dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]);
}
@@ -798,7 +797,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
LOG_DEBUG("MDM: dap_run failed when validating secured state");
return ERROR_OK;
}
- for (i = 0; i < 32; i++) {
+ for (unsigned int i = 0; i < 32; i++) {
if (stats[i] & MDM_STAT_SYSSEC)
secured_score++;
if (!(stats[i] & MDM_STAT_FREADY))
@@ -860,8 +859,7 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target)
static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[])
{
- int i;
- for (i = 0; i < argc; i++) {
+ for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "-sim-base") == 0) {
if (i + 1 < argc)
k_chip->sim_base = strtoul(argv[++i], NULL, 0);
@@ -933,7 +931,6 @@ static void kinetis_free_driver_priv(struct flash_bank *bank)
static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
{
- unsigned bank_idx;
unsigned num_blocks;
struct kinetis_flash_bank *k_bank;
struct flash_bank *bank;
@@ -968,7 +965,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
*p = '\0';
}
- for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) {
+ for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) {
k_bank = &(k_chip->banks[bank_idx]);
bank = k_bank->bank;
@@ -1219,11 +1216,11 @@ static int kinetis_ftfx_clear_error(struct target *target)
static int kinetis_ftfx_prepare(struct target *target)
{
- int result, i;
+ int result;
uint8_t fstat;
/* wait until busy */
- for (i = 0; i < 50; i++) {
+ for (unsigned int i = 0; i < 50; i++) {
result = target_read_u8(target, FTFx_FSTAT, &fstat);
if (result != ERROR_OK)
return result;
@@ -1343,8 +1340,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
static int kinetis_protect(struct flash_bank *bank, int set, int first, int last)
{
- int i;
-
if (allow_fcf_writes) {
LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!");
return ERROR_FAIL;
@@ -1355,7 +1350,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last
return ERROR_FLASH_BANK_INVALID;
}
- for (i = first; i < bank->num_prot_blocks && i <= last; i++)
+ for (int i = first; i < bank->num_prot_blocks && i <= last; i++)
bank->prot_blocks[i].is_protected = set;
LOG_INFO("Protection bits will be written at the next FCF sector erase or write.");
@@ -1369,7 +1364,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
{
struct kinetis_flash_bank *k_bank = bank->driver_priv;
int result;
- int i, b;
+ int b;
uint32_t fprot;
if (k_bank->flash_class == FC_PFLASH) {
@@ -1397,7 +1392,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
}
b = k_bank->protection_block;
- for (i = 0; i < bank->num_prot_blocks; i++) {
+ for (int i = 0; i < bank->num_prot_blocks; i++) {
if ((fprot >> b) & 1)
bank->prot_blocks[i].is_protected = 0;
else
@@ -1415,8 +1410,6 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
uint32_t fprot = 0xffffffff;
uint8_t fsec = 0xfe; /* set MCU unsecure */
uint8_t fdprot = 0xff;
- int i;
- unsigned bank_idx;
unsigned num_blocks;
uint32_t pflash_bit;
uint8_t dflash_bit;
@@ -1432,7 +1425,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
/* iterate over all kinetis banks */
/* current bank is bank 0, it contains FCF */
num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks;
- for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) {
+ for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) {
k_bank = &(k_chip->banks[bank_idx]);
bank_iter = k_bank->bank;
@@ -1443,8 +1436,10 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
kinetis_auto_probe(bank_iter);
+ assert(bank_iter->prot_blocks);
+
if (k_bank->flash_class == FC_PFLASH) {
- for (i = 0; i < bank_iter->num_prot_blocks; i++) {
+ for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
if (bank_iter->prot_blocks[i].is_protected == 1)
fprot &= ~pflash_bit;
@@ -1452,7 +1447,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
}
} else if (k_bank->flash_class == FC_FLEX_NVM) {
- for (i = 0; i < bank_iter->num_prot_blocks; i++) {
+ for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
if (bank_iter->prot_blocks[i].is_protected == 1)
fdprot &= ~dflash_bit;
@@ -1540,7 +1535,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat)
static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
{
- int result, i;
+ int result;
uint8_t pmstat;
struct target *target;
@@ -1578,7 +1573,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
if (result != ERROR_OK)
return result;
- for (i = 100; i; i--) {
+ for (unsigned int i = 100; i > 0; i--) {
result = kinetis_read_pmstat(k_chip, &pmstat);
if (result != ERROR_OK)
return result;
@@ -1623,7 +1618,7 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip)
static int kinetis_erase(struct flash_bank *bank, int first, int last)
{
- int result, i;
+ int result;
struct kinetis_flash_bank *k_bank = bank->driver_priv;
struct kinetis_chip *k_chip = k_bank->k_chip;
@@ -1644,7 +1639,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
* requested erase is PFlash or NVM and encompasses the entire
* block. Should be quicker.
*/
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
/* set command and sector address */
result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset,
0, 0, 0, 0, 0, 0, 0, 0, NULL);
@@ -1798,6 +1793,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
buffer += size;
offset += size;
count -= size;
+
+ keep_alive();
}
free(buffer_aligned);
@@ -1808,25 +1805,26 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
- int result, fallback = 0;
+ int result;
+ bool fallback = false;
struct kinetis_flash_bank *k_bank = bank->driver_priv;
struct kinetis_chip *k_chip = k_bank->k_chip;
if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) {
/* fallback to longword write */
- fallback = 1;
+ fallback = true;
LOG_INFO("This device supports Program Longword execution only.");
} else {
result = kinetis_make_ram_ready(bank->target);
if (result != ERROR_OK) {
- fallback = 1;
+ fallback = true;
LOG_WARNING("FlexRAM not ready, fallback to slow longword write.");
}
}
LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset);
- if (fallback == 0) {
+ if (!fallback) {
/* program section command */
kinetis_write_sections(bank, buffer, offset, count);
} else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) {
@@ -1889,6 +1887,8 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
buffer += 4;
offset += 4;
words_remaining--;
+
+ keep_alive();
}
}
free(new_buffer);
@@ -2018,7 +2018,6 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
unsigned familyid = 0, subfamid = 0;
unsigned cpu_mhz = 120;
- unsigned idx;
bool use_nvm_marking = false;
char flash_marking[12], nvm_marking[2];
char name[40];
@@ -2113,7 +2112,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
LOG_ERROR("Unsupported K-family FAMID");
}
- for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) {
+ for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) {
if (kinetis_types_old[idx].sdid == mcu_type) {
strcpy(name, kinetis_types_old[idx].name);
use_nvm_marking = true;
@@ -2619,12 +2618,15 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
static int kinetis_probe(struct flash_bank *bank)
{
- int result, i;
+ int result;
uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1;
unsigned num_blocks, first_nvm_bank;
uint32_t size_k;
struct kinetis_flash_bank *k_bank = bank->driver_priv;
- struct kinetis_chip *k_chip = k_bank->k_chip;
+ struct kinetis_chip *k_chip;
+
+ assert(k_bank);
+ k_chip = k_bank->k_chip;
k_bank->probed = false;
@@ -2668,6 +2670,7 @@ static int kinetis_probe(struct flash_bank *bank)
if (k_chip->dflash_size == 0) {
k_bank->protection_size = 0;
} else {
+ int i;
for (i = k_chip->dflash_size; ~i & 1; i >>= 1)
;
if (i == 1)
@@ -2824,8 +2827,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
if (block_dirty) {
/* the whole bank is not erased, check sector-by-sector */
- int i;
- for (i = 0; i < bank->num_sectors; i++) {
+ for (int i = 0; i < bank->num_sectors; i++) {
/* normal margin */
result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT,
k_bank->prog_base + bank->sectors[i].offset,
@@ -2841,8 +2843,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
}
} else {
/* the whole bank is erased, update all sectors */
- int i;
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
}
} else {
diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c
index 27b6d3a83..cfc04928b 100644
--- a/src/flash/nor/kinetis_ke.c
+++ b/src/flash/nor/kinetis_ke.c
@@ -814,7 +814,7 @@ static int kinetis_ke_protect_check(struct flash_bank *bank)
kinfo->protection_size = 0;
} else {
- LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", \
+ LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i",
fpopen ? 1 : 0, fpldis ? 1 : 0, fphdis ? 1 : 0, fpls, fphs);
/* Retrieve which region is protected and how much */
diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c
index 19d754b0f..04ac3bb4d 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -177,8 +177,8 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
retval = target_alloc_working_area(target, sizeof(spifi_init_code)
+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
if (retval != ERROR_OK) {
- LOG_ERROR("Insufficient working area to initialize SPIFI "\
- "module. You must allocate at least %zdB of working "\
+ LOG_ERROR("Insufficient working area to initialize SPIFI "
+ "module. You must allocate at least %zdB of working "
"area in order to use this driver.",
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
);
@@ -452,7 +452,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
* it, use a bulk erase instead of going sector-by-sector. */
if (first == 0 && last == (bank->num_sectors - 1)
&& lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) {
- LOG_DEBUG("Chip supports the bulk erase command."\
+ LOG_DEBUG("Chip supports the bulk erase command."
" Will use bulk erase instead of sector-by-sector erase.");
retval = lpcspifi_bulk_erase(bank);
@@ -525,7 +525,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code),
&erase_algorithm);
if (retval != ERROR_OK) {
- LOG_ERROR("Insufficient working area. You must configure a working"\
+ LOG_ERROR("Insufficient working area. You must configure a working"
" area of at least %zdB in order to erase SPIFI flash.",
sizeof(lpcspifi_flash_erase_code));
return retval;
@@ -685,7 +685,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
&write_algorithm) != ERROR_OK) {
- LOG_ERROR("Insufficient working area. You must configure"\
+ LOG_ERROR("Insufficient working area. You must configure"
" a working area > %zdB in order to write to SPIFI flash.",
sizeof(lpcspifi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -707,15 +707,15 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
* space, free the algorithm */
target_free_working_area(target, write_algorithm);
- LOG_ERROR("Insufficient working area. Please allocate at least"\
+ LOG_ERROR("Insufficient working area. Please allocate at least"
" %zdB of working area to enable flash writes.",
sizeof(lpcspifi_flash_write_code) + 1
);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} else if (fifo_size < page_size)
- LOG_WARNING("Working area size is limited; flash writes may be"\
- " slow. Increase working area size to at least %zdB"\
+ LOG_WARNING("Working area size is limited; flash writes may be"
+ " slow. Increase working area size to at least %zdB"
" to reduce write times.",
(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
);
diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c
index 803e84a91..7a06b3d09 100644
--- a/src/flash/nor/mrvlqspi.c
+++ b/src/flash/nor/mrvlqspi.c
@@ -563,7 +563,7 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last)
if (first == 0 && last == (bank->num_sectors - 1)
&& mrvlqspi_info->dev->chip_erase_cmd !=
mrvlqspi_info->dev->erase_cmd) {
- LOG_DEBUG("Chip supports the bulk erase command."\
+ LOG_DEBUG("Chip supports the bulk erase command."
" Will use bulk erase instead of sector-by-sector erase.");
retval = mrvlqspi_bulk_erase(bank);
if (retval == ERROR_OK) {
@@ -681,7 +681,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code),
&write_algorithm) != ERROR_OK) {
- LOG_ERROR("Insufficient working area. You must configure"\
+ LOG_ERROR("Insufficient working area. You must configure"
" a working area > %zdB in order to write to SPIFI flash.",
sizeof(mrvlqspi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -703,15 +703,15 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
* space, free the algorithm */
target_free_working_area(target, write_algorithm);
- LOG_ERROR("Insufficient working area. Please allocate at least"\
+ LOG_ERROR("Insufficient working area. Please allocate at least"
" %zdB of working area to enable flash writes.",
sizeof(mrvlqspi_flash_write_code) + 1
);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} else if (fifo_size < page_size)
- LOG_WARNING("Working area size is limited; flash writes may be"\
- " slow. Increase working area size to at least %zdB"\
+ LOG_WARNING("Working area size is limited; flash writes may be"
+ " slow. Increase working area size to at least %zdB"
" to reduce write times.",
(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
);
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
index e9e4be33a..95c99b970 100644
--- a/src/flash/nor/msp432.c
+++ b/src/flash/nor/msp432.c
@@ -49,7 +49,8 @@ struct msp432_bank {
int family_type;
int device_type;
uint32_t sector_length;
- bool probed[2];
+ bool probed_main;
+ bool probed_info;
bool unlock_bsl;
struct working_area *working_area;
struct armv7m_algorithm armv7m_info;
@@ -194,8 +195,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params
return retval;
/* Write out command to target memory */
- retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR,
- sizeof(command), (uint8_t *)&command);
+ retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command);
return retval;
}
@@ -210,8 +210,7 @@ static int msp432_wait_return_code(struct target *target)
start_ms = timeval_ms();
while ((0 == return_code) || (FLASH_BUSY == return_code)) {
- retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR,
- sizeof(return_code), (uint8_t *)&return_code);
+ retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code);
if (ERROR_OK != retval)
return retval;
@@ -253,8 +252,7 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer)
start_ms = timeval_ms();
while (BUFFER_INACTIVE != status_code) {
- retval = target_read_buffer(target, status_addr, sizeof(status_code),
- (uint8_t *)&status_code);
+ retval = target_read_u32(target, status_addr, &status_code);
if (ERROR_OK != retval)
return retval;
@@ -477,15 +475,23 @@ COMMAND_HANDLER(msp432_mass_erase_command)
struct flash_bank *bank;
struct msp432_bank *msp432_bank;
bool all;
+
int retval;
- if (0 == CMD_ARGC) {
+ if (1 > CMD_ARGC)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (1 == CMD_ARGC) {
all = false;
- } else if (1 == CMD_ARGC) {
+ } else if (2 == CMD_ARGC) {
/* Check argument for how much to erase */
- if (0 == strcmp(CMD_ARGV[0], "main"))
+ if (0 == strcmp(CMD_ARGV[1], "main"))
all = false;
- else if (0 == strcmp(CMD_ARGV[0], "all"))
+ else if (0 == strcmp(CMD_ARGV[1], "all"))
all = true;
else
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -493,10 +499,6 @@ COMMAND_HANDLER(msp432_mass_erase_command)
return ERROR_COMMAND_SYNTAX_ERROR;
}
- retval = get_flash_bank_by_num(0, &bank);
- if (ERROR_OK != retval)
- return retval;
-
msp432_bank = bank->driver_priv;
if (MSP432E4 == msp432_bank->family_type) {
@@ -513,7 +515,7 @@ COMMAND_HANDLER(msp432_mass_erase_command)
LOG_INFO("msp432: Mass erase of flash is complete");
} else {
LOG_INFO("msp432: Mass erase of %s is complete",
- all ? "main + info flash" : "main flash");
+ all ? "main + information flash" : "main flash");
}
return ERROR_OK;
@@ -523,13 +525,14 @@ COMMAND_HANDLER(msp432_bsl_command)
{
struct flash_bank *bank;
struct msp432_bank *msp432_bank;
+
int retval;
- if (1 < CMD_ARGC)
+ if (1 > CMD_ARGC)
return ERROR_COMMAND_SYNTAX_ERROR;
- retval = get_flash_bank_by_num(0, &bank);
- if (ERROR_OK != retval)
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
return retval;
msp432_bank = bank->driver_priv;
@@ -539,13 +542,16 @@ COMMAND_HANDLER(msp432_bsl_command)
return ERROR_OK;
}
- if (1 == CMD_ARGC) {
- if (0 == strcmp(CMD_ARGV[0], "lock"))
+ if (2 == CMD_ARGC) {
+ if (0 == strcmp(CMD_ARGV[1], "lock"))
msp432_bank->unlock_bsl = false;
- else if (0 == strcmp(CMD_ARGV[0], "unlock"))
+ else if (0 == strcmp(CMD_ARGV[1], "unlock"))
msp432_bank->unlock_bsl = true;
else
return ERROR_COMMAND_SYNTAX_ERROR;
+ } else if (1 != CMD_ARGC) {
+ /* Extra, unknown argument passed in */
+ return ERROR_COMMAND_SYNTAX_ERROR;
}
LOG_INFO("msp432: BSL flash region is currently %slocked",
@@ -561,6 +567,7 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
+ /* Create shared private struct for flash banks */
msp432_bank = malloc(sizeof(struct msp432_bank));
if (NULL == msp432_bank)
return ERROR_FAIL;
@@ -571,14 +578,14 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
msp432_bank->family_type = MSP432_NO_FAMILY;
msp432_bank->device_type = MSP432_NO_TYPE;
msp432_bank->sector_length = 0x1000;
- msp432_bank->probed[0] = false;
- msp432_bank->probed[1] = false;
+ msp432_bank->probed_main = false;
+ msp432_bank->probed_info = false;
msp432_bank->unlock_bsl = false;
msp432_bank->working_area = NULL;
- /* Finish initialization of bank 0 (main flash) */
+ /* Finish up initial settings here */
bank->driver_priv = msp432_bank;
- bank->next = NULL;
+ bank->base = FLASH_BASE;
return ERROR_OK;
}
@@ -589,6 +596,9 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
struct msp432_bank *msp432_bank = bank->driver_priv;
struct msp432_algo_params algo_params;
+ bool is_main = FLASH_BASE == bank->base;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
+
int retval;
if (TARGET_HALTED != target->state) {
@@ -597,8 +607,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
}
/* Do a mass erase if user requested all sectors of main flash */
- if ((0 == bank->bank_number) && (first == 0) &&
- (last == (bank->num_sectors - 1))) {
+ if (is_main && (first == 0) && (last == (bank->num_sectors - 1))) {
/* Request mass erase of main flash */
return msp432_mass_erase(bank, false);
}
@@ -611,7 +620,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
msp432_init_params(&algo_params);
/* Adjust params if this is the info bank */
- if (1 == bank->bank_number) {
+ if (is_info) {
buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO);
/* And flag if BSL is unlocked */
if (msp432_bank->unlock_bsl)
@@ -622,11 +631,11 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
for (int i = first; i <= last; i++) {
/* Skip TVL (read-only) sector of the info bank */
- if (1 == bank->bank_number && 1 == i)
+ if (is_info && 1 == i)
continue;
/* Skip BSL sectors of info bank if locked */
- if (1 == bank->bank_number && (2 == i || 3 == i) &&
+ if (is_info && (2 == i || 3 == i) &&
!msp432_bank->unlock_bsl)
continue;
@@ -666,6 +675,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
long long start_ms;
long long elapsed_ms;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
+
int retval;
if (TARGET_HALTED != target->state) {
@@ -679,7 +690,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
* The BSL region in sectors 2 and 3 of the info flash may be unlocked
* The helper algorithm will hang on attempts to write to TVL
*/
- if (1 == bank->bank_number) {
+ if (is_info) {
/* Set read-only start to TVL sector */
uint32_t start = 0x1000;
/* Set read-only end after BSL region if locked */
@@ -722,7 +733,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
buf_set_u32(algo_params.length, 0, 32, count);
/* Check if this is the info bank */
- if (1 == bank->bank_number) {
+ if (is_info) {
/* And flag if BSL is unlocked */
if (msp432_bank->unlock_bsl)
buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
@@ -753,8 +764,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* Signal the flash helper algorithm that data is ready to flash */
- retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR,
- sizeof(data_ready), (uint8_t *)&data_ready);
+ retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR,
+ data_ready);
if (ERROR_OK != retval) {
(void)msp432_quit(bank);
return ERROR_FLASH_OPERATION_FAILED;
@@ -793,20 +804,23 @@ static int msp432_probe(struct flash_bank *bank)
struct target *target = bank->target;
struct msp432_bank *msp432_bank = bank->driver_priv;
- char *name;
-
uint32_t device_id;
uint32_t hardware_rev;
- uint32_t base;
uint32_t sector_length;
uint32_t size;
int num_sectors;
- int bank_id;
+
+ bool is_main = FLASH_BASE == bank->base;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
int retval;
- bank_id = bank->bank_number;
+ /* Check if this bank has already been successfully probed */
+ if (is_main && msp432_bank->probed_main)
+ return ERROR_OK;
+ if (is_info && msp432_bank->probed_info)
+ return ERROR_OK;
/* Read the flash size register to determine this is a P4 or not */
/* MSP432P4s will return the size of flash. MSP432E4s will return zero */
@@ -849,63 +863,16 @@ static int msp432_probe(struct flash_bank *bank)
msp432_bank->device_type = msp432_device_type(msp432_bank->family_type,
msp432_bank->device_id, msp432_bank->hardware_rev);
- /* If not already allocated, create the info bank for MSP432P4 */
- /* We could not determine it was needed until device was probed */
- if (MSP432P4 == msp432_bank->family_type) {
- /* If we've been given bank 1, then this was already done */
- if (0 == bank_id) {
- /* And only allocate it if it doesn't exist yet */
- if (NULL == bank->next) {
- struct flash_bank *info_bank;
- info_bank = malloc(sizeof(struct flash_bank));
- if (NULL == info_bank)
- return ERROR_FAIL;
-
- name = malloc(strlen(bank->name)+1);
- if (NULL == name) {
- free(info_bank);
- return ERROR_FAIL;
- }
- strcpy(name, bank->name);
-
- /* Initialize bank 1 (info region) */
- info_bank->name = name;
- info_bank->target = bank->target;
- info_bank->driver = bank->driver;
- info_bank->driver_priv = bank->driver_priv;
- info_bank->bank_number = 1;
- info_bank->base = 0x00200000;
- info_bank->size = 0;
- info_bank->chip_width = 0;
- info_bank->bus_width = 0;
- info_bank->erased_value = 0xff;
- info_bank->default_padded_value = 0xff;
- info_bank->write_start_alignment = 0;
- info_bank->write_end_alignment = 0;
- info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
- info_bank->num_sectors = 0;
- info_bank->sectors = NULL;
- info_bank->num_prot_blocks = 0;
- info_bank->prot_blocks = NULL;
- info_bank->next = NULL;
-
- /* Enable the new bank */
- bank->next = info_bank;
- }
- }
- }
-
if (MSP432P4 == msp432_bank->family_type) {
/* Set up MSP432P4 specific flash parameters */
- if (0 == bank_id) {
+ if (is_main) {
retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
if (ERROR_OK != retval)
return retval;
- base = P4_FLASH_MAIN_BASE;
sector_length = P4_SECTOR_LENGTH;
num_sectors = size / sector_length;
- } else if (1 == bank_id) {
+ } else if (is_info) {
if (msp432_bank->device_type == MSP432P411X ||
msp432_bank->device_type == MSP432P411X_GUESS) {
/* MSP432P411x has an info size register, use that for size */
@@ -916,19 +883,22 @@ static int msp432_probe(struct flash_bank *bank)
/* All other MSP432P401x devices have fixed info region size */
size = 0x4000; /* 16 KB info region */
}
- base = P4_FLASH_INFO_BASE;
sector_length = P4_SECTOR_LENGTH;
num_sectors = size / sector_length;
} else {
- /* Invalid bank number somehow */
+ /* Invalid bank somehow */
return ERROR_FAIL;
}
} else {
/* Set up MSP432E4 specific flash parameters */
- base = E4_FLASH_BASE;
- size = E4_FLASH_SIZE;
- sector_length = E4_SECTOR_LENGTH;
- num_sectors = size / sector_length;
+ if (is_main) {
+ size = E4_FLASH_SIZE;
+ sector_length = E4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ } else {
+ /* Invalid bank somehow */
+ return ERROR_FAIL;
+ }
}
if (NULL != bank->sectors) {
@@ -936,11 +906,12 @@ static int msp432_probe(struct flash_bank *bank)
bank->sectors = NULL;
}
- bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
- if (NULL == bank->sectors)
- return ERROR_FAIL;
+ if (num_sectors > 0) {
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+ if (NULL == bank->sectors)
+ return ERROR_FAIL;
+ }
- bank->base = base;
bank->size = size;
bank->write_start_alignment = 0;
bank->write_end_alignment = 0;
@@ -955,7 +926,31 @@ static int msp432_probe(struct flash_bank *bank)
}
/* We've successfully determined the stats on this flash bank */
- msp432_bank->probed[bank_id] = true;
+ if (is_main)
+ msp432_bank->probed_main = true;
+ if (is_info)
+ msp432_bank->probed_info = true;
+
+ if (is_main && MSP432P4 == msp432_bank->family_type) {
+ /* Create the info flash bank needed by MSP432P4 variants */
+ struct flash_bank *info = calloc(sizeof(struct flash_bank), 1);
+ if (NULL == info)
+ return ERROR_FAIL;
+
+ /* Create a name for the info bank, append "_1" to main name */
+ char *name = malloc(strlen(bank->name) + 3);
+ strcpy(name, bank->name);
+ strcat(name, "_1");
+
+ /* Initialize info bank */
+ info->name = name;
+ info->target = bank->target;
+ info->driver = bank->driver;
+ info->driver_priv = msp432_bank;
+ info->base = P4_FLASH_INFO_BASE;
+
+ flash_bank_add(info);
+ }
/* If we fall through to here, then all went well */
@@ -966,15 +961,17 @@ static int msp432_auto_probe(struct flash_bank *bank)
{
struct msp432_bank *msp432_bank = bank->driver_priv;
+ bool is_main = FLASH_BASE == bank->base;
+ bool is_info = P4_FLASH_INFO_BASE == bank->base;
+
int retval = ERROR_OK;
- if (bank->bank_number < 0 || bank->bank_number > 1) {
- /* Invalid bank number somehow */
- return ERROR_FAIL;
- }
-
- if (!msp432_bank->probed[bank->bank_number])
- retval = msp432_probe(bank);
+ if (is_main)
+ if (!msp432_bank->probed_main)
+ retval = msp432_probe(bank);
+ if (is_info)
+ if (!msp432_bank->probed_info)
+ retval = msp432_probe(bank);
return retval;
}
@@ -1036,12 +1033,21 @@ static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
+static int msp432_protect_check(struct flash_bank *bank)
+{
+ /* Added to suppress warning, not needed for MSP432 flash */
+ return ERROR_OK;
+}
+
static void msp432_flash_free_driver_priv(struct flash_bank *bank)
{
+ bool is_main = FLASH_BASE == bank->base;
+
/* A single private struct is shared between main and info banks */
- /* Only free it on the call for main bank (#0) */
- if ((0 == bank->bank_number) && (NULL != bank->driver_priv))
+ /* Only free it on the call for main bank */
+ if (is_main && (NULL != bank->driver_priv))
free(bank->driver_priv);
+
/* Forget about the private struct on both main and info banks */
bank->driver_priv = NULL;
}
@@ -1052,14 +1058,14 @@ static const struct command_registration msp432_exec_command_handlers[] = {
.handler = msp432_mass_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase entire flash memory on device.",
- .usage = "['main' | 'all']",
+ .usage = "bank_id ['main' | 'all']",
},
{
.name = "bsl",
.handler = msp432_bsl_command,
.mode = COMMAND_EXEC,
.help = "Allow BSL to be erased or written by flash commands.",
- .usage = "['unlock' | 'lock']",
+ .usage = "bank_id ['unlock' | 'lock']",
},
COMMAND_REGISTRATION_DONE
};
@@ -1085,6 +1091,7 @@ const struct flash_driver msp432_flash = {
.probe = msp432_probe,
.auto_probe = msp432_auto_probe,
.erase_check = default_flash_blank_check,
+ .protect_check = msp432_protect_check,
.info = msp432_info,
.free_driver_priv = msp432_flash_free_driver_priv,
};
diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h
index ffefa8f43..663393b79 100644
--- a/src/flash/nor/msp432.h
+++ b/src/flash/nor/msp432.h
@@ -34,14 +34,17 @@
#define MSP432E411Y 7 /* MSP432E401Y device */
#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */
+/* Common MSP432 flash parameters */
+#define FLASH_BASE 0x00000000
+
/* MSP432P4 flash parameters */
-#define P4_FLASH_MAIN_BASE 0x00000000
+#define P4_FLASH_MAIN_BASE FLASH_BASE
#define P4_FLASH_INFO_BASE 0x00200000
#define P4_SECTOR_LENGTH 0x1000
#define P4_ALGO_ENTRY_ADDR 0x01000110
/* MSP432E4 flash paramters */
-#define E4_FLASH_BASE 0x00000000
+#define E4_FLASH_BASE FLASH_BASE
#define E4_FLASH_SIZE 0x100000
#define E4_SECTOR_LENGTH 0x4000
#define E4_ALGO_ENTRY_ADDR 0x20000110
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 4041bfbe4..fa67e2bf3 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -28,6 +28,10 @@
#include
#include
+/* Both those values are constant across the current spectrum ofr nRF5 devices */
+#define WATCHDOG_REFRESH_REGISTER 0x40010600
+#define WATCHDOG_REFRESH_VALUE 0x6e524635
+
enum {
NRF5_FLASH_BASE = 0x00000000,
};
@@ -39,13 +43,15 @@ enum nrf5_ficr_registers {
NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010),
NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014),
- NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028),
- NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C),
- NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034),
- NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038),
- NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
- NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
- NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
+
+ NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028),
+ NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C),
+ NRF51_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034),
+ NRF51_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038),
+ NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
+ NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
+ NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
+
NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C),
NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060),
NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064),
@@ -60,36 +66,42 @@ enum nrf5_ficr_registers {
NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0),
NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4),
NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8),
- NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC),
- NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0),
- NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4),
- NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8),
- NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC),
- NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0),
- NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC),
- NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0),
- NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4),
- NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8),
- NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC),
+
+ NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC),
+ NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0),
+ NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4),
+ NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8),
+ NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC),
+ NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0),
+ NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC),
+ NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0),
+ NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4),
+ NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8),
+ NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC),
+
+ /* Following registers are available on nRF52 and on nRF51 since rev 3 */
+ NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100),
+ NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104),
+ NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108),
+ NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C),
+ NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110),
};
enum nrf5_uicr_registers {
NRF5_UICR_BASE = 0x10001000, /* User Information
* Configuration Regsters */
- NRF5_UICR_SIZE = 0x100,
-
#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
- NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000),
- NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004),
- NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008),
- NRF5_UICR_FWID = NRF5_UICR_REG(0x010),
+ NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000),
+ NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004),
+ NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008),
+ NRF51_UICR_FWID = NRF5_UICR_REG(0x010),
};
enum nrf5_nvmc_registers {
NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory
- * Controller Regsters */
+ * Controller Registers */
#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset)
@@ -98,6 +110,8 @@ enum nrf5_nvmc_registers {
NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508),
NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C),
NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514),
+
+ NRF5_BPROT_BASE = 0x40000000,
};
enum nrf5_nvmc_config_bits {
@@ -107,17 +121,19 @@ enum nrf5_nvmc_config_bits {
};
-struct nrf5_info {
- uint32_t code_page_size;
- uint32_t refcount;
+struct nrf52_ficr_info {
+ uint32_t part;
+ uint32_t variant;
+ uint32_t package;
+ uint32_t ram;
+ uint32_t flash;
+};
- struct {
- bool probed;
- int (*write) (struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count);
- } bank[2];
- struct target *target;
+enum nrf5_features {
+ NRF5_FEATURE_SERIES_51 = 1 << 0,
+ NRF5_FEATURE_SERIES_52 = 1 << 1,
+ NRF5_FEATURE_BPROT = 1 << 2,
+ NRF5_FEATURE_ACL_PROT = 1 << 3,
};
struct nrf5_device_spec {
@@ -126,22 +142,58 @@ struct nrf5_device_spec {
const char *variant;
const char *build_code;
unsigned int flash_size_kb;
+ enum nrf5_features features;
};
-#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \
+struct nrf5_info {
+ uint32_t refcount;
+
+ struct nrf5_bank {
+ struct nrf5_info *chip;
+ bool probed;
+ } bank[2];
+ struct target *target;
+
+ /* chip identification stored in nrf5_probe() for use in nrf5_info() */
+ bool ficr_info_valid;
+ struct nrf52_ficr_info ficr_info;
+ const struct nrf5_device_spec *spec;
+ uint32_t hwid;
+ enum nrf5_features features;
+ unsigned int flash_size_kb;
+ unsigned int ram_size_kb;
+};
+
+#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \
{ \
.hwid = (id), \
.part = pt, \
.variant = var, \
.build_code = bcode, \
.flash_size_kb = (fsize), \
+.features = NRF5_FEATURE_SERIES_51, \
}
-/* The known devices table below is derived from the "nRF51 Series
- * Compatibility Matrix" document, which can be found by searching for
- * ATTN-51 on the Nordic Semi website:
+#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \
+{ \
+.hwid = (id), \
+.part = pt, \
+.variant = var, \
+.build_code = bcode, \
+.flash_size_kb = (fsize), \
+.features = features, \
+}
+
+/* The known devices table below is derived from the "nRF5x series
+ * compatibility matrix" documents, which can be found in the "DocLib" of
+ * nordic:
*
- * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview
*
* Up to date with Matrix v2.0, plus some additional HWIDs.
*
@@ -151,79 +203,99 @@ struct nrf5_device_spec {
*/
static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF51822 Devices (IC rev 1). */
- NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256),
- NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128),
- NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128),
- NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
- NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
+ NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256),
+ NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128),
+ NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128),
+ NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
+ NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
/* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
with built-in jlink seem to use engineering samples not listed
in the nRF51 Series Compatibility Matrix V1.0. */
- NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
+ NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
/* nRF51822 Devices (IC rev 2). */
- NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
- NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
- NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256),
- NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256),
- NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256),
- NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128),
- NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256),
- NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256),
- NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256),
+ NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
+ NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
+ NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256),
+ NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256),
+ NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256),
+ NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128),
+ NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256),
+ NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256),
+ NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256),
/* nRF51822 Devices (IC rev 3). */
- NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
- NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
- NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
- NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
- NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
- NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
- NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
- NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
- NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
+ NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
+ NRF51_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
+ NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
+ NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
+ NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
+ NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
+ NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
/* nRF51422 Devices (IC rev 1). */
- NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
- NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256),
- NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256),
+ NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
+ NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256),
+ NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256),
/* nRF51422 Devices (IC rev 2). */
- NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256),
- NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256),
- NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128),
- NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256),
+ NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256),
+ NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256),
+ NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128),
+ NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256),
/* nRF51422 Devices (IC rev 3). */
- NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256),
- NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128),
- NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256),
- NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256),
- NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128),
- NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
- NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256),
+ NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128),
+ NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256),
+ NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256),
+ NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128),
+ NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
+ NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
+ /* The driver fully autodects nRF52 series devices by FICR INFO,
+ * no need for nRF52xxx HWIDs in this table */
+#if 0
/* nRF52810 Devices */
- NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192),
- NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192),
+ NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
+ NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
/* nRF52832 Devices */
- NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
- NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
- NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
+ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
+ NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
+ NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
/* nRF52840 Devices */
- NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
+ NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT),
+#endif
};
+struct nrf5_device_package {
+ uint32_t package;
+ const char *code;
+};
+
+/* Newer devices have FICR INFO.PACKAGE.
+ * This table converts its value to two character code */
+static const struct nrf5_device_package nrf5_packages_table[] = {
+ { 0x2000, "QF" },
+ { 0x2001, "CH" },
+ { 0x2002, "CI" },
+ { 0x2005, "CK" },
+};
+
+const struct flash_driver nrf5_flash, nrf51_flash;
+
static int nrf5_bank_is_probed(struct flash_bank *bank)
{
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
- assert(chip != NULL);
+ assert(nbank != NULL);
- return chip->bank[bank->bank_number].probed;
+ return nbank->probed;
}
static int nrf5_probe(struct flash_bank *bank);
@@ -234,7 +306,8 @@ static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_i
return ERROR_TARGET_NOT_HALTED;
}
- *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ *chip = nbank->chip;
int probed = nrf5_bank_is_probed(bank);
if (probed < 0)
@@ -367,6 +440,33 @@ error:
return ERROR_FAIL;
}
+static int nrf5_protect_check_bprot(struct flash_bank *bank)
+{
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+
+ assert(chip != NULL);
+
+ static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 };
+ uint32_t bprot_reg = 0;
+ int res;
+
+ for (int i = 0; i < bank->num_sectors; i++) {
+ unsigned int bit = i % 32;
+ if (bit == 0) {
+ unsigned int n_reg = i / 32;
+ if (n_reg >= ARRAY_SIZE(nrf5_bprot_offsets))
+ break;
+
+ res = target_read_u32(chip->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg);
+ if (res != ERROR_OK)
+ return res;
+ }
+ bank->sectors[i].is_protected = (bprot_reg & (1 << bit)) ? 1 : 0;
+ }
+ return ERROR_OK;
+}
+
static int nrf5_protect_check(struct flash_bank *bank)
{
int res;
@@ -376,11 +476,20 @@ static int nrf5_protect_check(struct flash_bank *bank)
if (bank->base == NRF5_UICR_BASE)
return ERROR_OK;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
assert(chip != NULL);
- res = target_read_u32(chip->target, NRF5_FICR_CLENR0,
+ if (chip->features & NRF5_FEATURE_BPROT)
+ return nrf5_protect_check_bprot(bank);
+
+ if (!(chip->features & NRF5_FEATURE_SERIES_51)) {
+ LOG_WARNING("Flash protection of this nRF device is not supported");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
+ res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[FICR]");
@@ -388,7 +497,7 @@ static int nrf5_protect_check(struct flash_bank *bank)
}
if (clenr0 == 0xFFFFFFFF) {
- res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
+ res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
@@ -417,12 +526,17 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
if (res != ERROR_OK)
return res;
+ if (!(chip->features & NRF5_FEATURE_SERIES_51)) {
+ LOG_ERROR("Flash protection setting of this nRF device is not supported");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
if (first != 0) {
LOG_ERROR("Code region 0 must start at the begining of the bank");
return ERROR_FAIL;
}
- res = target_read_u32(chip->target, NRF5_FICR_PPFC,
+ res = target_read_u32(chip->target, NRF51_FICR_PPFC,
&ppfc);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read PPFC register");
@@ -434,7 +548,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_FAIL;
}
- res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
+ res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
@@ -442,7 +556,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
}
if (clenr0 == 0xFFFFFFFF) {
- res = target_write_u32(chip->target, NRF5_UICR_CLENR0,
+ res = target_write_u32(chip->target, NRF51_UICR_CLENR0,
clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't write code region 0 size[UICR]");
@@ -458,93 +572,266 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_OK;
}
+static bool nrf5_info_variant_to_str(uint32_t variant, char *bf)
+{
+ uint8_t b[4];
+
+ h_u32_to_be(b, variant);
+ if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) {
+ memcpy(bf, b, 4);
+ bf[4] = 0;
+ return true;
+ }
+
+ strcpy(bf, "xxxx");
+ return false;
+}
+
+static const char *nrf5_decode_info_package(uint32_t package)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) {
+ if (nrf5_packages_table[i].package == package)
+ return nrf5_packages_table[i].code;
+ }
+ return "xx";
+}
+
+static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+ int res;
+
+ if (chip->spec) {
+ res = snprintf(buf, buf_size,
+ "nRF%s-%s(build code: %s)",
+ chip->spec->part, chip->spec->variant, chip->spec->build_code);
+
+ } else if (chip->ficr_info_valid) {
+ char variant[5];
+ nrf5_info_variant_to_str(chip->ficr_info.variant, variant);
+ res = snprintf(buf, buf_size,
+ "nRF%" PRIx32 "-%s%.2s(build code: %s)",
+ chip->ficr_info.part,
+ nrf5_decode_info_package(chip->ficr_info.package),
+ variant, &variant[2]);
+
+ } else {
+ res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")",
+ chip->hwid);
+ }
+ if (res <= 0)
+ return ERROR_FAIL;
+
+ snprintf(buf + res, buf_size - res, " %ukB Flash, %ukB RAM",
+ chip->flash_size_kb, chip->ram_size_kb);
+ return ERROR_OK;
+}
+
+static int nrf5_read_ficr_info(struct nrf5_info *chip)
+{
+ int res;
+ struct target *target = chip->target;
+
+ chip->ficr_info_valid = false;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part);
+ if (res != ERROR_OK) {
+ LOG_DEBUG("Couldn't read FICR INFO.PART register");
+ return res;
+ }
+
+ uint32_t series = chip->ficr_info.part & 0xfffff000;
+ switch (series) {
+ case 0x51000:
+ chip->features = NRF5_FEATURE_SERIES_51;
+ break;
+
+ case 0x52000:
+ chip->features = NRF5_FEATURE_SERIES_52;
+
+ switch (chip->ficr_info.part) {
+ case 0x52810:
+ case 0x52832:
+ chip->features |= NRF5_FEATURE_BPROT;
+ break;
+
+ case 0x52840:
+ chip->features |= NRF5_FEATURE_ACL_PROT;
+ break;
+ }
+ break;
+
+ default:
+ LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08"
+ PRIx32, chip->ficr_info.part);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ /* Now we know the device has FICR INFO filled by something relevant:
+ * Although it is not documented, the tested nRF51 rev 3 devices
+ * have FICR INFO.PART, RAM and FLASH of the same format as nRF52.
+ * VARIANT and PACKAGE coding is unknown for a nRF51 device.
+ * nRF52 devices have FICR INFO documented and always filled. */
+
+ res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant);
+ if (res != ERROR_OK)
+ return res;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package);
+ if (res != ERROR_OK)
+ return res;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram);
+ if (res != ERROR_OK)
+ return res;
+
+ res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash);
+ if (res != ERROR_OK)
+ return res;
+
+ chip->ficr_info_valid = true;
+ return ERROR_OK;
+}
+
+static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size)
+{
+ int res;
+
+ *ram_size = 0;
+
+ uint32_t numramblock;
+ res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock);
+ if (res != ERROR_OK) {
+ LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register");
+ return res;
+ }
+
+ if (numramblock < 1 || numramblock > 4) {
+ LOG_DEBUG("FICR NUMRAMBLOCK strange value %" PRIx32, numramblock);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ for (unsigned int i = 0; i < numramblock; i++) {
+ uint32_t sizeramblock;
+ res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock);
+ if (res != ERROR_OK) {
+ LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register");
+ return res;
+ }
+ if (sizeramblock < 1024 || sizeramblock > 65536)
+ LOG_DEBUG("FICR SIZERAMBLOCK strange value %" PRIx32, sizeramblock);
+ else
+ *ram_size += sizeramblock;
+ }
+ return res;
+}
+
static int nrf5_probe(struct flash_bank *bank)
{
- uint32_t hwid;
int res;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+ struct target *target = chip->target;
- res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid);
+ res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read CONFIGID register");
return res;
}
- hwid &= 0xFFFF; /* HWID is stored in the lower two
+ chip->hwid &= 0xFFFF; /* HWID is stored in the lower two
* bytes of the CONFIGID register */
- const struct nrf5_device_spec *spec = NULL;
+ /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
+ chip->features = NRF5_FEATURE_SERIES_51;
+
+ /* Don't bail out on error for the case that some old engineering
+ * sample has FICR INFO registers unreadable. We can proceed anyway. */
+ (void)nrf5_read_ficr_info(chip);
+
+ chip->spec = NULL;
for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) {
- if (hwid == nrf5_known_devices_table[i].hwid) {
- spec = &nrf5_known_devices_table[i];
+ if (chip->hwid == nrf5_known_devices_table[i].hwid) {
+ chip->spec = &nrf5_known_devices_table[i];
+ chip->features = chip->spec->features;
break;
}
}
- if (!chip->bank[0].probed && !chip->bank[1].probed) {
- if (spec)
- LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash",
- spec->part, spec->variant, spec->build_code,
- spec->flash_size_kb);
- else
- LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid);
+ if (chip->spec && chip->ficr_info_valid) {
+ /* check if HWID table gives the same part as FICR INFO */
+ if (chip->ficr_info.part != strtoul(chip->spec->part, NULL, 16))
+ LOG_WARNING("HWID 0x%04" PRIx32 " mismatch: FICR INFO.PART %"
+ PRIx32, chip->hwid, chip->ficr_info.part);
}
- if (bank->base == NRF5_FLASH_BASE) {
- /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
- res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
- &chip->code_page_size);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read code page size");
- return res;
- }
+ if (chip->ficr_info_valid) {
+ chip->ram_size_kb = chip->ficr_info.ram;
+ } else {
+ uint32_t ram_size;
+ nrf5_get_ram_size(target, &ram_size);
+ chip->ram_size_kb = ram_size / 1024;
+ }
- /* Note the register name is misleading,
- * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
- uint32_t num_sectors;
- res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read code memory size");
- return res;
+ /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
+ uint32_t flash_page_size;
+ res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
+ &flash_page_size);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read code page size");
+ return res;
+ }
+
+ /* Note the register name is misleading,
+ * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
+ uint32_t num_sectors;
+ res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read code memory size");
+ return res;
+ }
+
+ chip->flash_size_kb = num_sectors * flash_page_size / 1024;
+
+ if (!chip->bank[0].probed && !chip->bank[1].probed) {
+ char buf[80];
+ nrf5_info(bank, buf, sizeof(buf));
+ if (!chip->spec && !chip->ficr_info_valid) {
+ LOG_INFO("Unknown device: %s", buf);
+ } else {
+ LOG_INFO("%s", buf);
}
+ }
+
+ free(bank->sectors);
+
+ if (bank->base == NRF5_FLASH_BASE) {
+ /* Sanity check */
+ if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb)
+ LOG_WARNING("Chip's reported Flash capacity does not match expected one");
+ if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash)
+ LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH");
bank->num_sectors = num_sectors;
- bank->size = num_sectors * chip->code_page_size;
+ bank->size = num_sectors * flash_page_size;
- if (spec && bank->size / 1024 != spec->flash_size_kb)
- LOG_WARNING("Chip's reported Flash capacity does not match expected one");
-
- bank->sectors = calloc(bank->num_sectors,
- sizeof((bank->sectors)[0]));
+ bank->sectors = alloc_block_array(0, flash_page_size, num_sectors);
if (!bank->sectors)
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- /* Fill out the sector information: all NRF5 sectors are the same size and
- * there is always a fixed number of them. */
- for (int i = 0; i < bank->num_sectors; i++) {
- bank->sectors[i].size = chip->code_page_size;
- bank->sectors[i].offset = i * chip->code_page_size;
-
- /* mark as unknown */
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = -1;
- }
+ return ERROR_FAIL;
nrf5_protect_check(bank);
chip->bank[0].probed = true;
+
} else {
- bank->size = NRF5_UICR_SIZE;
bank->num_sectors = 1;
- bank->sectors = calloc(bank->num_sectors,
- sizeof((bank->sectors)[0]));
+ bank->size = flash_page_size;
+
+ bank->sectors = alloc_block_array(0, flash_page_size, num_sectors);
if (!bank->sectors)
- return ERROR_FLASH_BANK_NOT_PROBED;
+ return ERROR_FAIL;
- bank->sectors[0].size = bank->size;
- bank->sectors[0].offset = 0;
-
- bank->sectors[0].is_erased = 0;
bank->sectors[0].is_protected = 0;
chip->bank[1].probed = true;
@@ -580,29 +867,27 @@ static int nrf5_erase_page(struct flash_bank *bank,
int res;
LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
- if (sector->is_protected) {
- LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
- return ERROR_FAIL;
- }
if (bank->base == NRF5_UICR_BASE) {
- uint32_t ppfc;
- res = target_read_u32(chip->target, NRF5_FICR_PPFC,
+ if (chip->features & NRF5_FEATURE_SERIES_51) {
+ uint32_t ppfc;
+ res = target_read_u32(chip->target, NRF51_FICR_PPFC,
&ppfc);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read PPFC register");
- return res;
- }
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read PPFC register");
+ return res;
+ }
- if ((ppfc & 0xFF) == 0xFF) {
- /* We can't erase the UICR. Double-check to
- see if it's already erased before complaining. */
- default_flash_blank_check(bank);
- if (sector->is_erased == 1)
- return ERROR_OK;
+ if ((ppfc & 0xFF) == 0xFF) {
+ /* We can't erase the UICR. Double-check to
+ see if it's already erased before complaining. */
+ default_flash_blank_check(bank);
+ if (sector->is_erased == 1)
+ return ERROR_OK;
- LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
- return ERROR_FAIL;
+ LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
+ return ERROR_FAIL;
+ }
}
res = nrf5_nvmc_generic_erase(chip,
@@ -619,44 +904,22 @@ static int nrf5_erase_page(struct flash_bank *bank,
return res;
}
-static const uint8_t nrf5_flash_write_code[] = {
- /* See contrib/loaders/flash/cortex-m0.S */
-/* : */
- 0x0d, 0x68, /* ldr r5, [r1, #0] */
- 0x00, 0x2d, /* cmp r5, #0 */
- 0x0b, 0xd0, /* beq.n 1e */
- 0x4c, 0x68, /* ldr r4, [r1, #4] */
- 0xac, 0x42, /* cmp r4, r5 */
- 0xf9, 0xd0, /* beq.n 0 */
- 0x20, 0xcc, /* ldmia r4!, {r5} */
- 0x20, 0xc3, /* stmia r3!, {r5} */
- 0x94, 0x42, /* cmp r4, r2 */
- 0x01, 0xd3, /* bcc.n 18 */
- 0x0c, 0x46, /* mov r4, r1 */
- 0x08, 0x34, /* adds r4, #8 */
-/* : */
- 0x4c, 0x60, /* str r4, [r1, #4] */
- 0x04, 0x38, /* subs r0, #4 */
- 0xf0, 0xd1, /* bne.n 0 */
-/* : */
- 0x00, 0xbe /* bkpt 0x0000 */
-};
-
-
/* Start a low level flash write for the specified region */
-static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
+static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes)
{
struct target *target = chip->target;
uint32_t buffer_size = 8192;
struct working_area *write_algorithm;
struct working_area *source;
- uint32_t address = NRF5_FLASH_BASE + offset;
- struct reg_param reg_params[4];
+ struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
+ static const uint8_t nrf5_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/nrf5/nrf5.inc"
+ };
- LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
+ LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes);
assert(bytes % 4 == 0);
/* allocate working area with flash programming code */
@@ -665,7 +928,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
LOG_WARNING("no working area available, falling back to slow memory writes");
for (; bytes > 0; bytes -= 4) {
- retval = target_write_memory(chip->target, offset, 4, 1, buffer);
+ retval = target_write_memory(target, address, 4, 1, buffer);
if (retval != ERROR_OK)
return retval;
@@ -673,17 +936,13 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
if (retval != ERROR_OK)
return retval;
- offset += 4;
+ address += 4;
buffer += 4;
}
return ERROR_OK;
}
- LOG_WARNING("using fast async flash loader. This is currently supported");
- LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
- LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it");
-
retval = target_write_buffer(target, write_algorithm->address,
sizeof(nrf5_flash_write_code),
nrf5_flash_write_code);
@@ -710,15 +969,19 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */
init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */
+ init_reg_param(®_params[4], "r6", 32, PARAM_OUT); /* watchdog refresh value */
+ init_reg_param(®_params[5], "r7", 32, PARAM_OUT); /* watchdog refresh register address */
buf_set_u32(reg_params[0].value, 0, 32, bytes);
buf_set_u32(reg_params[1].value, 0, 32, source->address);
buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[3].value, 0, 32, address);
+ buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE);
+ buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER);
retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
0, NULL,
- 4, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
@@ -730,26 +993,29 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui
destroy_reg_param(®_params[1]);
destroy_reg_param(®_params[2]);
destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+ destroy_reg_param(®_params[5]);
return retval;
}
-/* Check and erase flash sectors in specified range then start a low level page write.
- start/end must be sector aligned.
-*/
-static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
+static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
{
- int res = ERROR_FAIL;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_info *chip;
- assert(start % chip->code_page_size == 0);
- assert(end % chip->code_page_size == 0);
+ int res = nrf5_get_probed_chip_if_halted(bank, &chip);
+ if (res != ERROR_OK)
+ return res;
+
+ assert(offset % 4 == 0);
+ assert(count % 4 == 0);
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
- res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
+ res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count);
if (res != ERROR_OK)
goto error;
@@ -777,113 +1043,10 @@ static int nrf5_erase(struct flash_bank *bank, int first, int last)
return res;
}
-static int nrf5_code_flash_write(struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-
- int res;
- /* Need to perform reads to fill any gaps we need to preserve in the first page,
- before the start of buffer, or in the last page, after the end of buffer */
- uint32_t first_page = offset/chip->code_page_size;
- uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
-
- uint32_t first_page_offset = first_page * chip->code_page_size;
- uint32_t last_page_offset = last_page * chip->code_page_size;
-
- LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
- offset, offset+count, first_page_offset, last_page_offset);
-
- uint32_t page_cnt = last_page - first_page;
- uint8_t buffer_to_flash[page_cnt*chip->code_page_size];
-
- /* Fill in any space between start of first page and start of buffer */
- uint32_t pre = offset - first_page_offset;
- if (pre > 0) {
- res = target_read_memory(bank->target,
- first_page_offset,
- 1,
- pre,
- buffer_to_flash);
- if (res != ERROR_OK)
- return res;
- }
-
- /* Fill in main contents of buffer */
- memcpy(buffer_to_flash+pre, buffer, count);
-
- /* Fill in any space between end of buffer and end of last page */
- uint32_t post = last_page_offset - (offset+count);
- if (post > 0) {
- /* Retrieve the full row contents from Flash */
- res = target_read_memory(bank->target,
- offset + count,
- 1,
- post,
- buffer_to_flash+pre+count);
- if (res != ERROR_OK)
- return res;
- }
-
- return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
-}
-
-static int nrf5_uicr_flash_write(struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count)
-{
- int res;
- uint8_t uicr[NRF5_UICR_SIZE];
- struct flash_sector *sector = &bank->sectors[0];
-
- if ((offset + count) > NRF5_UICR_SIZE)
- return ERROR_FAIL;
-
- res = target_read_memory(bank->target,
- NRF5_UICR_BASE,
- 1,
- NRF5_UICR_SIZE,
- uicr);
-
- if (res != ERROR_OK)
- return res;
-
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK)
- return res;
-
- res = nrf5_nvmc_write_enable(chip);
- if (res != ERROR_OK)
- return res;
-
- memcpy(&uicr[offset], buffer, count);
-
- res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE);
- if (res != ERROR_OK) {
- nrf5_nvmc_read_only(chip);
- return res;
- }
-
- return nrf5_nvmc_read_only(chip);
-}
-
-
-static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
-{
- int res;
- struct nrf5_info *chip;
-
- res = nrf5_get_probed_chip_if_halted(bank, &chip);
- if (res != ERROR_OK)
- return res;
-
- return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
-}
-
static void nrf5_free_driver_priv(struct flash_bank *bank)
{
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
if (chip == NULL)
return;
@@ -894,22 +1057,43 @@ static void nrf5_free_driver_priv(struct flash_bank *bank)
}
}
+static struct nrf5_info *nrf5_get_chip(struct target *target)
+{
+ struct flash_bank *bank_iter;
+
+ /* iterate over nrf5 banks of same target */
+ for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) {
+ if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash)
+ continue;
+
+ if (bank_iter->target != target)
+ continue;
+
+ struct nrf5_bank *nbank = bank_iter->driver_priv;
+ if (!nbank)
+ continue;
+
+ if (nbank->chip)
+ return nbank->chip;
+ }
+ return NULL;
+}
+
FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
{
- static struct nrf5_info *chip;
+ struct nrf5_info *chip;
+ struct nrf5_bank *nbank = NULL;
switch (bank->base) {
case NRF5_FLASH_BASE:
- bank->bank_number = 0;
- break;
case NRF5_UICR_BASE:
- bank->bank_number = 1;
break;
default:
LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
return ERROR_FAIL;
}
+ chip = nrf5_get_chip(bank->target);
if (!chip) {
/* Create a new chip */
chip = calloc(1, sizeof(*chip));
@@ -921,16 +1105,19 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
switch (bank->base) {
case NRF5_FLASH_BASE:
- chip->bank[bank->bank_number].write = nrf5_code_flash_write;
+ nbank = &chip->bank[0];
break;
case NRF5_UICR_BASE:
- chip->bank[bank->bank_number].write = nrf5_uicr_flash_write;
+ nbank = &chip->bank[1];
break;
}
+ assert(nbank != NULL);
chip->refcount++;
- chip->bank[bank->bank_number].probed = false;
- bank->driver_priv = chip;
+ nbank->chip = chip;
+ nbank->probed = false;
+ bank->driver_priv = nbank;
+ bank->write_start_alignment = bank->write_end_alignment = 4;
return ERROR_OK;
}
@@ -953,19 +1140,20 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
if (res != ERROR_OK)
return res;
- uint32_t ppfc;
-
- res = target_read_u32(target, NRF5_FICR_PPFC,
+ if (chip->features & NRF5_FEATURE_SERIES_51) {
+ uint32_t ppfc;
+ res = target_read_u32(target, NRF51_FICR_PPFC,
&ppfc);
- if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read PPFC register");
- return res;
- }
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read PPFC register");
+ return res;
+ }
- if ((ppfc & 0xFF) == 0x00) {
- LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
- "mass erase command won't work.");
- return ERROR_FAIL;
+ if ((ppfc & 0xFF) == 0x00) {
+ LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
+ "mass erase command won't work.");
+ return ERROR_FAIL;
+ }
}
res = nrf5_erase_all(chip);
@@ -988,9 +1176,17 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
return ERROR_OK;
}
-static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
+COMMAND_HANDLER(nrf5_handle_info_command)
{
int res;
+ struct flash_bank *bank = NULL;
+ struct target *target = get_current_target(CMD_CTX);
+
+ res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank);
+ if (res != ERROR_OK)
+ return res;
+
+ assert(bank != NULL);
struct nrf5_info *chip;
@@ -1004,13 +1200,13 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
} ficr[] = {
{ .address = NRF5_FICR_CODEPAGESIZE },
{ .address = NRF5_FICR_CODESIZE },
- { .address = NRF5_FICR_CLENR0 },
- { .address = NRF5_FICR_PPFC },
- { .address = NRF5_FICR_NUMRAMBLOCK },
- { .address = NRF5_FICR_SIZERAMBLOCK0 },
- { .address = NRF5_FICR_SIZERAMBLOCK1 },
- { .address = NRF5_FICR_SIZERAMBLOCK2 },
- { .address = NRF5_FICR_SIZERAMBLOCK3 },
+ { .address = NRF51_FICR_CLENR0 },
+ { .address = NRF51_FICR_PPFC },
+ { .address = NRF51_FICR_NUMRAMBLOCK },
+ { .address = NRF51_FICR_SIZERAMBLOCK0 },
+ { .address = NRF51_FICR_SIZERAMBLOCK1 },
+ { .address = NRF51_FICR_SIZERAMBLOCK2 },
+ { .address = NRF51_FICR_SIZERAMBLOCK3 },
{ .address = NRF5_FICR_CONFIGID },
{ .address = NRF5_FICR_DEVICEID0 },
{ .address = NRF5_FICR_DEVICEID1 },
@@ -1025,22 +1221,22 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
{ .address = NRF5_FICR_DEVICEADDRTYPE },
{ .address = NRF5_FICR_DEVICEADDR0 },
{ .address = NRF5_FICR_DEVICEADDR1 },
- { .address = NRF5_FICR_OVERRIDEN },
- { .address = NRF5_FICR_NRF_1MBIT0 },
- { .address = NRF5_FICR_NRF_1MBIT1 },
- { .address = NRF5_FICR_NRF_1MBIT2 },
- { .address = NRF5_FICR_NRF_1MBIT3 },
- { .address = NRF5_FICR_NRF_1MBIT4 },
- { .address = NRF5_FICR_BLE_1MBIT0 },
- { .address = NRF5_FICR_BLE_1MBIT1 },
- { .address = NRF5_FICR_BLE_1MBIT2 },
- { .address = NRF5_FICR_BLE_1MBIT3 },
- { .address = NRF5_FICR_BLE_1MBIT4 },
+ { .address = NRF51_FICR_OVERRIDEN },
+ { .address = NRF51_FICR_NRF_1MBIT0 },
+ { .address = NRF51_FICR_NRF_1MBIT1 },
+ { .address = NRF51_FICR_NRF_1MBIT2 },
+ { .address = NRF51_FICR_NRF_1MBIT3 },
+ { .address = NRF51_FICR_NRF_1MBIT4 },
+ { .address = NRF51_FICR_BLE_1MBIT0 },
+ { .address = NRF51_FICR_BLE_1MBIT1 },
+ { .address = NRF51_FICR_BLE_1MBIT2 },
+ { .address = NRF51_FICR_BLE_1MBIT3 },
+ { .address = NRF51_FICR_BLE_1MBIT4 },
}, uicr[] = {
- { .address = NRF5_UICR_CLENR0, },
- { .address = NRF5_UICR_RBPCONF },
- { .address = NRF5_UICR_XTALFREQ },
- { .address = NRF5_UICR_FWID },
+ { .address = NRF51_UICR_CLENR0, },
+ { .address = NRF51_UICR_RBPCONF },
+ { .address = NRF51_UICR_XTALFREQ },
+ { .address = NRF51_UICR_FWID },
};
for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) {
@@ -1061,7 +1257,7 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
}
}
- snprintf(buf, buf_size,
+ command_print(CMD,
"\n[factory information control block]\n\n"
"code page size: %"PRIu32"B\n"
"code memory size: %"PRIu32"kB\n"
@@ -1120,6 +1316,13 @@ static const struct command_registration nrf5_exec_command_handlers[] = {
.help = "Erase all flash contents of the chip.",
.usage = "",
},
+ {
+ .name = "info",
+ .handler = nrf5_handle_info_command,
+ .mode = COMMAND_EXEC,
+ .help = "Show FICR and UICR info.",
+ .usage = "",
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c
index c62af04bf..a4852829e 100644
--- a/src/flash/nor/numicro.c
+++ b/src/flash/nor/numicro.c
@@ -1216,7 +1216,7 @@ static int numicro_init_isp(struct target *target)
return ERROR_OK;
}
-static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t* rdata)
+static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata)
{
uint32_t timeout, status;
int retval = ERROR_OK;
@@ -1548,7 +1548,6 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
{
struct target *target = bank->target;
uint32_t timeout, status;
- uint8_t *new_buffer = NULL;
int retval = ERROR_OK;
if (target->state != TARGET_HALTED) {
@@ -1566,20 +1565,8 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
return retval;
- if (count & 0x3) {
- uint32_t old_count = count;
- count = (old_count | 3) + 1;
- new_buffer = malloc(count);
- if (new_buffer == NULL) {
- LOG_ERROR("odd number of bytes to write and no memory "
- "for padding buffer");
- return ERROR_FAIL;
- }
- LOG_INFO("odd number of bytes to write (%d), extending to %d "
- "and padding with 0xff", old_count, count);
- memset(new_buffer, 0xff, count);
- buffer = memcpy(new_buffer, buffer, old_count);
- }
+ assert(offset % 4 == 0);
+ assert(count % 4 == 0);
uint32_t words_remaining = count / 4;
@@ -1597,13 +1584,10 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_DEBUG("write longword @ %08X", offset + i);
- uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
- memcpy(padding, buffer + i, MIN(4, count-i));
-
retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i);
if (retval != ERROR_OK)
return retval;
- retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, padding);
+ retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
@@ -1649,7 +1633,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_OK;
}
-static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type** cpu)
+static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu)
{
uint32_t part_id;
int retval = ERROR_OK;
@@ -1663,7 +1647,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_
LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id);
/* search part numbers */
- for (size_t i = 0; i < sizeof(NuMicroParts)/sizeof(NuMicroParts[0]); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) {
if (part_id == NuMicroParts[i].partid) {
*cpu = &NuMicroParts[i];
LOG_INFO("Device Name: %s", (*cpu)->partname);
@@ -1754,6 +1738,7 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command)
memset(bank_info, 0, sizeof(struct numicro_flash_bank));
bank->driver_priv = bank_info;
+ bank->write_start_alignment = bank->write_end_alignment = 4;
return ERROR_OK;
diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c
index 386075e2c..a8f8d3f08 100644
--- a/src/flash/nor/psoc6.c
+++ b/src/flash/nor/psoc6.c
@@ -108,7 +108,7 @@ static const struct row_region safe_sflash_regions[] = {
{0x16007C00, 0x400}, /* SFLASH: TOC2 */
};
-#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0]))
+#define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
static struct working_area *g_stack_area;
static struct armv7m_algorithm g_armv7m_info;
@@ -481,20 +481,15 @@ static const char *protection_to_str(uint8_t protection)
switch (protection) {
case PROTECTION_VIRGIN:
return "VIRGIN";
- break;
case PROTECTION_NORMAL:
return "NORMAL";
- break;
case PROTECTION_SECURE:
return "SECURE";
- break;
case PROTECTION_DEAD:
return "DEAD";
- break;
case PROTECTION_UNKNOWN:
default:
return "UNKNOWN";
- break;
}
}
diff --git a/src/flash/nor/renesas_rpchf.c b/src/flash/nor/renesas_rpchf.c
new file mode 100644
index 000000000..3f03f9275
--- /dev/null
+++ b/src/flash/nor/renesas_rpchf.c
@@ -0,0 +1,648 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Renesas RCar Gen3 RPC Hyperflash driver
+ * Based on U-Boot RPC Hyperflash driver
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016 Cogent Embedded, Inc.
+ * Copyright (C) 2017-2019 Marek Vasut
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "cfi.h"
+#include "non_cfi.h"
+#include
+#include
+#include
+
+#define RPC_CMNCR 0x0000 /* R/W */
+#define RPC_CMNCR_MD BIT(31)
+#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
+#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
+#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
+#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
+#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
+#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
+#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
+#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+ RPC_CMNCR_IO3FV(3))
+#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+
+#define RPC_SSLDR 0x0004 /* R/W */
+#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+
+#define RPC_DRCR 0x000C /* R/W */
+#define RPC_DRCR_SSLN BIT(24)
+#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+#define RPC_DRCR_RCF BIT(9)
+#define RPC_DRCR_RBE BIT(8)
+#define RPC_DRCR_SSLE BIT(0)
+
+#define RPC_DRCMR 0x0010 /* R/W */
+#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_DREAR 0x0014 /* R/W */
+#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
+#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
+
+#define RPC_DROPR 0x0018 /* R/W */
+#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
+#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
+
+#define RPC_DRENR 0x001C /* R/W */
+#define RPC_DRENR_CDB(o) (uint32_t)((((o) & 0x3) << 30))
+#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_DRENR_DME BIT(15)
+#define RPC_DRENR_CDE BIT(14)
+#define RPC_DRENR_OCDE BIT(12)
+#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
+
+#define RPC_SMCR 0x0020 /* R/W */
+#define RPC_SMCR_SSLKP BIT(8)
+#define RPC_SMCR_SPIRE BIT(2)
+#define RPC_SMCR_SPIWE BIT(1)
+#define RPC_SMCR_SPIE BIT(0)
+
+#define RPC_SMCMR 0x0024 /* R/W */
+#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_SMADR 0x0028 /* R/W */
+#define RPC_SMOPR 0x002C /* R/W */
+#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
+#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
+
+#define RPC_SMENR 0x0030 /* R/W */
+#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
+#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_SMENR_DME BIT(15)
+#define RPC_SMENR_CDE BIT(14)
+#define RPC_SMENR_OCDE BIT(12)
+#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
+#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
+
+#define RPC_SMRDR0 0x0038 /* R */
+#define RPC_SMRDR1 0x003C /* R */
+#define RPC_SMWDR0 0x0040 /* R/W */
+#define RPC_SMWDR1 0x0044 /* R/W */
+#define RPC_CMNSR 0x0048 /* R */
+#define RPC_CMNSR_SSLF BIT(1)
+#define RPC_CMNSR_TEND BIT(0)
+
+#define RPC_DRDMCR 0x0058 /* R/W */
+#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_DRDRENR 0x005C /* R/W */
+#define RPC_DRDRENR_HYPE (0x5 << 12)
+#define RPC_DRDRENR_ADDRE BIT(8)
+#define RPC_DRDRENR_OPDRE BIT(4)
+#define RPC_DRDRENR_DRDRE BIT(0)
+
+#define RPC_SMDMCR 0x0060 /* R/W */
+#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_SMDRENR 0x0064 /* R/W */
+#define RPC_SMDRENR_HYPE (0x5 << 12)
+#define RPC_SMDRENR_ADDRE BIT(8)
+#define RPC_SMDRENR_OPDRE BIT(4)
+#define RPC_SMDRENR_SPIDRE BIT(0)
+
+#define RPC_PHYCNT 0x007C /* R/W */
+#define RPC_PHYCNT_CAL BIT(31)
+#define PRC_PHYCNT_OCTA_AA BIT(22)
+#define PRC_PHYCNT_OCTA_SA BIT(23)
+#define PRC_PHYCNT_EXDS BIT(21)
+#define RPC_PHYCNT_OCT BIT(20)
+#define RPC_PHYCNT_WBUF2 BIT(4)
+#define RPC_PHYCNT_WBUF BIT(2)
+#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
+
+#define RPC_PHYINT 0x0088 /* R/W */
+#define RPC_PHYINT_RSTEN BIT(18)
+#define RPC_PHYINT_WPEN BIT(17)
+#define RPC_PHYINT_INTEN BIT(16)
+#define RPC_PHYINT_RST BIT(2)
+#define RPC_PHYINT_WP BIT(1)
+#define RPC_PHYINT_INT BIT(0)
+
+#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
+#define RPC_WBUF_SIZE 0x100
+
+static uint32_t rpc_base = 0xee200000;
+static uint32_t mem_base = 0x08000000;
+
+enum rpc_hf_size {
+ RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8),
+ RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC),
+ RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF),
+};
+
+static int rpc_hf_wait_tend(struct target *target)
+{
+ uint32_t reg = rpc_base + RPC_CMNSR;
+ uint32_t val;
+ unsigned long timeout = 1000;
+ long long endtime;
+ int ret;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ ret = target_read_u32(target, reg, &val);
+ if (ret != ERROR_OK)
+ return ERROR_FAIL;
+
+ if (val & RPC_CMNSR_TEND)
+ return ERROR_OK;
+
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static int clrsetbits_u32(struct target *target, uint32_t reg,
+ uint32_t clr, uint32_t set)
+{
+ uint32_t val;
+ int ret;
+
+ ret = target_read_u32(target, reg, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~clr;
+ val |= set;
+
+ return target_write_u32(target, reg, val);
+}
+
+static int rpc_hf_mode(struct target *target, bool manual)
+{
+ uint32_t val;
+ int ret;
+
+ ret = rpc_hf_wait_tend(target);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Mode TEND timeout");
+ return ret;
+ }
+
+ ret = clrsetbits_u32(target, rpc_base + RPC_PHYCNT,
+ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
+ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
+ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR,
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+ (manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1));
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (manual)
+ return ERROR_OK;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRCR,
+ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF |
+ RPC_DRCR_RBE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRCMR,
+ RPC_DRCMR_CMD(0xA0));
+ if (ret != ERROR_OK)
+ return ret;
+ ret = target_write_u32(target, rpc_base + RPC_DRENR,
+ RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) |
+ RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) |
+ RPC_DRENR_CDE | RPC_DRENR_OCDE |
+ RPC_DRENR_ADE(4));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRDMCR,
+ RPC_DRDMCR_DMCYC(0xE));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_DRDRENR,
+ RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE |
+ RPC_DRDRENR_DRDRE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Dummy read */
+ return target_read_u32(target, rpc_base + RPC_DRCR, &val);
+}
+
+static int rpc_hf_xfer(struct target *target, target_addr_t addr,
+ uint32_t wdata, uint32_t *rdata, enum rpc_hf_size size,
+ bool write, const uint8_t *wbuf, unsigned int wbuf_size)
+{
+ int ret;
+ uint32_t val;
+
+ if (wbuf_size != 0) {
+ ret = rpc_hf_wait_tend(target);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Xfer TEND timeout");
+ return ret;
+ }
+
+ /* Write calibration magic */
+ ret = target_write_u32(target, rpc_base + RPC_DRCR, 0x01FF0301);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_PHYCNT, 0x80030277);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_memory(target, rpc_base | RPC_WBUF, 4,
+ wbuf_size / 4, wbuf);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR,
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(1));
+ if (ret != ERROR_OK)
+ return ret;
+ } else {
+ ret = rpc_hf_mode(target, 1);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ /* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */
+ ret = target_write_u32(target, rpc_base + RPC_SMCMR,
+ write ? 0 : RPC_SMCMR_CMD(0x80));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMADR,
+ addr >> 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMOPR, 0x0);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMDRENR,
+ RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE |
+ RPC_SMDRENR_SPIDRE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
+ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
+ (wbuf_size ? RPC_SMENR_OPDB(2) : 0) |
+ RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size;
+
+ if (write) {
+ ret = target_write_u32(target, rpc_base + RPC_SMENR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (wbuf_size == 0) {
+ buf_bswap32((uint8_t *)&wdata, (uint8_t *)&wdata, 4);
+ ret = target_write_u32(target, rpc_base + RPC_SMWDR0,
+ wdata);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ ret = target_write_u32(target, rpc_base + RPC_SMCR,
+ RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
+ if (ret != ERROR_OK)
+ return ret;
+ } else {
+ val |= RPC_SMENR_DME;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMDMCR,
+ RPC_SMDMCR_DMCYC(0xE));
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMENR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, rpc_base + RPC_SMCR,
+ RPC_SMCR_SPIRE | RPC_SMCR_SPIE);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = rpc_hf_wait_tend(target);
+ if (ret != ERROR_OK)
+ return ret;
+
+ uint32_t val32;
+ ret = target_read_u32(target, rpc_base + RPC_SMRDR0, &val32);
+ if (ret != ERROR_OK)
+ return ret;
+ buf_bswap32((uint8_t *)&val32, (uint8_t *)&val32, 4);
+ *rdata = val32;
+ }
+
+ ret = rpc_hf_mode(target, 0);
+ if (ret != ERROR_OK)
+ LOG_ERROR("Xfer done TEND timeout");
+ return ret;
+}
+
+static int rpchf_target_write_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, const uint8_t *buffer)
+{
+ struct target *target = bank->target;
+ uint32_t wdata;
+
+ if (count != 2)
+ return ERROR_FAIL;
+
+ wdata = buffer[0] | (buffer[1] << 8);
+
+ return rpc_hf_xfer(target, addr, wdata, NULL, RPC_HF_SIZE_16BIT,
+ true, NULL, 0);
+}
+
+static int rpchf_target_read_memory(struct flash_bank *bank, target_addr_t addr,
+ uint32_t count, uint8_t *buffer)
+{
+ struct target *target = bank->target;
+ uint32_t i, rdata;
+ int ret;
+
+ for (i = 0; i < count; i++) {
+ ret = rpc_hf_xfer(target, addr + (2 * i), 0, &rdata,
+ RPC_HF_SIZE_16BIT, false, NULL, 0);
+ if (ret != ERROR_OK)
+ return ret;
+ buffer[(2 * i) + 0] = rdata & 0xff;
+ buffer[(2 * i) + 1] = (rdata >> 8) & 0xff;
+ }
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(rpchf_flash_bank_command)
+{
+ struct cfi_flash_bank *cfi_info;
+ int ret;
+
+ ret = cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV);
+ if (ret != ERROR_OK)
+ return ret;
+
+ cfi_info = bank->driver_priv;
+ cfi_info->read_mem = rpchf_target_read_memory;
+ cfi_info->write_mem = rpchf_target_write_memory;
+
+ return ERROR_OK;
+}
+
+static int rpchf_spansion_write_words(struct flash_bank *bank, const uint8_t *word,
+ uint32_t wordcount, uint32_t address)
+{
+ int retval;
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+ /* Calculate buffer size and boundary mask
+ * buffersize is (buffer size per chip) * (number of chips)
+ * bufferwsize is buffersize in words */
+ uint32_t buffersize = RPC_WBUF_SIZE;
+ uint32_t buffermask = buffersize - 1;
+ uint32_t bufferwsize = buffersize / 2;
+
+ /* Check for valid range */
+ if (address & buffermask) {
+ LOG_ERROR("Write address at base " TARGET_ADDR_FMT
+ ", address 0x%" PRIx32 " not aligned to 2^%d boundary",
+ bank->base, address, cfi_info->max_buf_write_size);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Check for valid size */
+ if (wordcount > bufferwsize) {
+ LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %"
+ PRId32, wordcount, buffersize);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Unlock */
+ retval = cfi_spansion_unlock_seq(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1));
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = rpc_hf_xfer(bank->target, address, 0, NULL, RPC_HF_SIZE_64BIT, true, word, wordcount * 2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) {
+ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT
+ ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address,
+ bufferwsize);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static int rpchf_write_words(struct flash_bank *bank, const uint8_t *word,
+ uint32_t wordcount, uint32_t address)
+{
+ return rpchf_spansion_write_words(bank, word, wordcount, address);
+}
+
+static int rpchf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ uint32_t address = bank->base + offset; /* address of first byte to be programmed */
+ uint32_t write_p;
+ int align; /* number of unaligned bytes */
+ uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being
+ *programmed */
+ int i;
+ int retval;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* start at the first byte of the first word (bus_width size) */
+ write_p = address & ~(bank->bus_width - 1);
+ align = address - write_p;
+ if (align != 0) {
+ LOG_INFO("Fixup %d unaligned head bytes", align);
+
+ /* read a complete word from flash */
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* replace only bytes that must be written */
+ for (i = align;
+ (i < bank->bus_width) && (count > 0);
+ i++, count--)
+ if (cfi_info->data_swap)
+ /* data bytes are swapped (reverse endianness) */
+ current_word[bank->bus_width - i] = *buffer++;
+ else
+ current_word[i] = *buffer++;
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ write_p += bank->bus_width;
+ }
+
+ /* Calculate buffer size and boundary mask
+ * buffersize is (buffer size per chip) * (number of chips)
+ * bufferwsize is buffersize in words */
+ uint32_t buffersize = RPC_WBUF_SIZE;
+ uint32_t buffermask = buffersize-1;
+ uint32_t bufferwsize = buffersize / bank->bus_width;
+
+ /* fall back to memory writes */
+ while (count >= (uint32_t)bank->bus_width) {
+ int fallback;
+ if ((write_p & 0xff) == 0) {
+ LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08"
+ PRIx32 " bytes remaining", write_p, count);
+ }
+ fallback = 1;
+ if ((bufferwsize > 0) && (count >= buffersize) &&
+ !(write_p & buffermask)) {
+ retval = rpchf_write_words(bank, buffer, bufferwsize, write_p);
+ if (retval == ERROR_OK) {
+ buffer += buffersize;
+ write_p += buffersize;
+ count -= buffersize;
+ fallback = 0;
+ } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED)
+ return retval;
+ }
+ /* try the slow way? */
+ if (fallback) {
+ for (i = 0; i < bank->bus_width; i++)
+ current_word[i] = *buffer++;
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+
+ write_p += bank->bus_width;
+ count -= bank->bus_width;
+ }
+ }
+
+ /* return to read array mode, so we can read from flash again for padding */
+ retval = cfi_reset(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* handle unaligned tail bytes */
+ if (count > 0) {
+ LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
+
+ /* read a complete word from flash */
+ retval = cfi_target_read_memory(bank, write_p, 1, current_word);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* replace only bytes that must be written */
+ for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
+ if (cfi_info->data_swap)
+ /* data bytes are swapped (reverse endianness) */
+ current_word[bank->bus_width - i] = *buffer++;
+ else
+ current_word[i] = *buffer++;
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* return to read array mode */
+ return cfi_reset(bank);
+}
+
+static int rpchf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ LOG_DEBUG("reading buffer of %" PRIi32 " byte at 0x%8.8" PRIx32,
+ count, offset);
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ return target_read_memory(target, offset | mem_base,
+ 4, count / 4, buffer);
+}
+
+const struct flash_driver renesas_rpchf_flash = {
+ .name = "rpchf",
+ .flash_bank_command = rpchf_flash_bank_command,
+ .erase = cfi_erase,
+ .protect = cfi_protect,
+ .write = rpchf_write,
+ .read = rpchf_read,
+ .probe = cfi_probe,
+ .auto_probe = cfi_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = cfi_protect_check,
+ .info = cfi_get_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c
new file mode 100644
index 000000000..862e43aae
--- /dev/null
+++ b/src/flash/nor/sh_qspi.c
@@ -0,0 +1,912 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SH QSPI (Quad SPI) driver
+ * Copyright (C) 2019 Marek Vasut
+ *
+ * Based on U-Boot SH QSPI driver
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Nobuhiro Iwamatsu
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "spi.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* SH QSPI register bit masks _ */
+#define SPCR_MSTR 0x08
+#define SPCR_SPE 0x40
+#define SPSR_SPRFF 0x80
+#define SPSR_SPTEF 0x20
+#define SPPCR_IO3FV 0x04
+#define SPPCR_IO2FV 0x02
+#define SPPCR_IO1FV 0x01
+#define SPBDCR_RXBC0 BIT(0)
+#define SPCMD_SCKDEN BIT(15)
+#define SPCMD_SLNDEN BIT(14)
+#define SPCMD_SPNDEN BIT(13)
+#define SPCMD_SSLKP BIT(7)
+#define SPCMD_BRDV0 BIT(2)
+#define SPCMD_INIT1 (SPCMD_SCKDEN | SPCMD_SLNDEN | \
+ SPCMD_SPNDEN | SPCMD_SSLKP | \
+ SPCMD_BRDV0)
+#define SPCMD_INIT2 (SPCMD_SPNDEN | SPCMD_SSLKP | \
+ SPCMD_BRDV0)
+#define SPBFCR_TXRST BIT(7)
+#define SPBFCR_RXRST BIT(6)
+#define SPBFCR_TXTRG 0x30
+#define SPBFCR_RXTRG 0x07
+
+/* SH QSPI register set */
+#define SH_QSPI_SPCR 0x00
+#define SH_QSPI_SSLP 0x01
+#define SH_QSPI_SPPCR 0x02
+#define SH_QSPI_SPSR 0x03
+#define SH_QSPI_SPDR 0x04
+#define SH_QSPI_SPSCR 0x08
+#define SH_QSPI_SPSSR 0x09
+#define SH_QSPI_SPBR 0x0a
+#define SH_QSPI_SPDCR 0x0b
+#define SH_QSPI_SPCKD 0x0c
+#define SH_QSPI_SSLND 0x0d
+#define SH_QSPI_SPND 0x0e
+#define SH_QSPI_DUMMY0 0x0f
+#define SH_QSPI_SPCMD0 0x10
+#define SH_QSPI_SPCMD1 0x12
+#define SH_QSPI_SPCMD2 0x14
+#define SH_QSPI_SPCMD3 0x16
+#define SH_QSPI_SPBFCR 0x18
+#define SH_QSPI_DUMMY1 0x19
+#define SH_QSPI_SPBDCR 0x1a
+#define SH_QSPI_SPBMUL0 0x1c
+#define SH_QSPI_SPBMUL1 0x20
+#define SH_QSPI_SPBMUL2 0x24
+#define SH_QSPI_SPBMUL3 0x28
+
+struct sh_qspi_flash_bank {
+ const struct flash_device *dev;
+ uint32_t io_base;
+ int probed;
+ struct working_area *io_algorithm;
+ struct working_area *source;
+ unsigned int buffer_size;
+};
+
+struct sh_qspi_target {
+ char *name;
+ uint32_t tap_idcode;
+ uint32_t io_base;
+};
+
+static const struct sh_qspi_target target_devices[] = {
+ /* name, tap_idcode, io_base */
+ { "SH QSPI", 0x4ba00477, 0xe6b10000 },
+ { NULL, 0, 0 }
+};
+
+static int sh_qspi_init(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t val;
+ int ret;
+
+ /* QSPI initialize */
+ /* Set master mode only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set SSL signal level */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set MOSI signal value when transfer is in idle state */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR,
+ SPPCR_IO3FV | SPPCR_IO2FV);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Disable Dummy Data Transmission */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set clock delay value */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set SSL negation delay value */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set next-access delay value */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set equence command */
+ ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
+ SPCMD_INIT2);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Reset transfer and receive Buffer */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPBFCR_TXRST | SPBFCR_RXRST;
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Clear transfer and receive Buffer control bit */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set equence control method. Use equence0 only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Enable SPI function */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPCR_SPE;
+
+ return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+}
+
+static int sh_qspi_cs_activate(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t val;
+ int ret;
+
+ /* Set master mode only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set command */
+ ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
+ SPCMD_INIT1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Reset transfer and receive Buffer */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPBFCR_TXRST | SPBFCR_RXRST;
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Clear transfer and receive Buffer control bit */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Set equence control method. Use equence0 only */
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Enable SPI function */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val |= SPCR_SPE;
+
+ return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+}
+
+static int sh_qspi_cs_deactivate(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t val;
+ int ret;
+
+ /* Disable SPI Function */
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~SPCR_SPE;
+
+ return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+}
+
+static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg,
+ uint32_t mask, bool set,
+ unsigned long timeout)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ long long endtime;
+ uint8_t val;
+ int ret;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ ret = target_read_u8(target, info->io_base + reg, &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (!set)
+ val = ~val;
+
+ if ((val & mask) == mask)
+ return ERROR_OK;
+
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static int sh_qspi_xfer_common(struct flash_bank *bank,
+ const uint8_t *dout, unsigned int outlen,
+ uint8_t *din, unsigned int inlen,
+ bool xfer_start, bool xfer_end)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ uint8_t tdata, rdata;
+ uint8_t val;
+ unsigned int nbyte = outlen + inlen;
+ int ret = 0;
+
+ if (xfer_start) {
+ ret = sh_qspi_cs_activate(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0,
+ nbyte);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR,
+ &val);
+ if (ret != ERROR_OK)
+ return ret;
+
+ val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG);
+
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR,
+ val);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ while (nbyte > 0) {
+ ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF,
+ true, 1000);
+ if (ret != ERROR_OK)
+ return ret;
+
+ tdata = outlen ? *dout++ : 0;
+ ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR,
+ tdata);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF,
+ true, 1000);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR,
+ &rdata);
+ if (ret != ERROR_OK)
+ return ret;
+ if (!outlen && inlen) {
+ *din++ = rdata;
+ inlen--;
+ }
+
+ if (outlen)
+ outlen--;
+
+ nbyte--;
+ }
+
+ if (xfer_end)
+ return sh_qspi_cs_deactivate(bank);
+ else
+ return ERROR_OK;
+}
+
+/* Send "write enable" command to SPI flash chip. */
+static int sh_qspi_write_enable(struct flash_bank *bank)
+{
+ uint8_t dout = SPIFLASH_WRITE_ENABLE;
+
+ return sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1);
+}
+
+/* Read the status register of the external SPI flash chip. */
+static int read_status_reg(struct flash_bank *bank, uint32_t *status)
+{
+ uint8_t dout = SPIFLASH_READ_STATUS;
+ uint8_t din;
+ int ret;
+
+ ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ *status = din & 0xff;
+
+ return ERROR_OK;
+}
+
+/* check for WIP (write in progress) bit in status register */
+/* timeout in ms */
+static int wait_till_ready(struct flash_bank *bank, int timeout)
+{
+ long long endtime;
+ uint32_t status;
+ int ret;
+
+ endtime = timeval_ms() + timeout;
+ do {
+ /* read flash status register */
+ ret = read_status_reg(bank, &status);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if ((status & SPIFLASH_BSY_BIT) == 0)
+ return ERROR_OK;
+ alive_sleep(1);
+ } while (timeval_ms() < endtime);
+
+ LOG_ERROR("timeout");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static int sh_qspi_erase_sector(struct flash_bank *bank, int sector)
+{
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ bool addr4b = info->dev->size_in_bytes > (1UL << 24);
+ uint32_t address = (sector * info->dev->sectorsize) <<
+ (addr4b ? 0 : 8);
+ uint8_t dout[5] = {
+ info->dev->erase_cmd,
+ (address >> 24) & 0xff, (address >> 16) & 0xff,
+ (address >> 8) & 0xff, (address >> 0) & 0xff
+ };
+ unsigned int doutlen = addr4b ? 5 : 4;
+ int ret;
+
+ /* Write Enable */
+ ret = sh_qspi_write_enable(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Erase */
+ ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* Poll status register */
+ return wait_till_ready(bank, 3000);
+}
+
+static int sh_qspi_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ int retval = ERROR_OK;
+ int sector;
+
+ LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
+ LOG_ERROR("Flash sector invalid");
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ if (!info->probed) {
+ LOG_ERROR("Flash bank not probed");
+ return ERROR_FLASH_BANK_NOT_PROBED;
+ }
+
+ if (info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
+ for (sector = first; sector <= last; sector++) {
+ if (bank->sectors[sector].is_protected) {
+ LOG_ERROR("Flash sector %d protected", sector);
+ return ERROR_FAIL;
+ }
+ }
+
+ for (sector = first; sector <= last; sector++) {
+ retval = sh_qspi_erase_sector(bank, sector);
+ if (retval != ERROR_OK)
+ break;
+ keep_alive();
+ }
+
+ return retval;
+}
+
+static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ struct reg_param reg_params[4];
+ struct arm_algorithm arm_algo;
+ uint32_t io_base = (uint32_t)(info->io_base);
+ uint32_t src_base = (uint32_t)(info->source->address);
+ uint32_t chunk;
+ bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
+ int ret = ERROR_OK;
+ int sector;
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size) {
+ LOG_WARNING("Write pasts end of flash. Extra data discarded.");
+ count = bank->size - offset;
+ }
+
+ if (offset & 0xff) {
+ LOG_ERROR("sh_qspi_write_page: unaligned write address: %08x",
+ offset);
+ return ERROR_FAIL;
+ }
+
+ /* Check sector protection */
+ for (sector = 0; sector < bank->num_sectors; sector++) {
+ /* Start offset in or before this sector? */
+ /* End offset in or behind this sector? */
+ struct flash_sector *bs = &bank->sectors[sector];
+
+ if ((offset < (bs->offset + bs->size)) &&
+ ((offset + count - 1) >= bs->offset) &&
+ bs->is_protected) {
+ LOG_ERROR("Flash sector %d protected", sector);
+ return ERROR_FAIL;
+ }
+ }
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size) {
+ LOG_WARNING("Reads past end of flash. Extra data discarded.");
+ count = bank->size - offset;
+ }
+
+ arm_algo.common_magic = ARM_COMMON_MAGIC;
+ arm_algo.core_mode = ARM_MODE_SVC;
+ arm_algo.core_state = ARM_STATE_ARM;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
+
+ while (count > 0) {
+ chunk = (count > info->buffer_size) ?
+ info->buffer_size : count;
+
+ target_write_buffer(target, info->source->address,
+ chunk, buffer);
+
+ buf_set_u32(reg_params[0].value, 0, 32, io_base);
+ buf_set_u32(reg_params[1].value, 0, 32, src_base);
+ buf_set_u32(reg_params[2].value, 0, 32,
+ (1 << 31) | (addr4b << 30) |
+ (info->dev->pprog_cmd << 20) | chunk);
+ buf_set_u32(reg_params[3].value, 0, 32, offset);
+
+ ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ info->io_algorithm->address,
+ 0, 10000, &arm_algo);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("error executing SH QSPI flash IO algorithm");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+
+ buffer += chunk;
+ offset += chunk;
+ count -= chunk;
+ }
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+
+ return ret;
+}
+
+static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ struct reg_param reg_params[4];
+ struct arm_algorithm arm_algo;
+ uint32_t io_base = (uint32_t)(info->io_base);
+ uint32_t src_base = (uint32_t)(info->source->address);
+ uint32_t chunk;
+ bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
+ int ret = ERROR_OK;
+
+ LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ __func__, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size) {
+ LOG_WARNING("Reads past end of flash. Extra data discarded.");
+ count = bank->size - offset;
+ }
+
+ arm_algo.common_magic = ARM_COMMON_MAGIC;
+ arm_algo.core_mode = ARM_MODE_SVC;
+ arm_algo.core_state = ARM_STATE_ARM;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
+
+ while (count > 0) {
+ chunk = (count > info->buffer_size) ?
+ info->buffer_size : count;
+
+ buf_set_u32(reg_params[0].value, 0, 32, io_base);
+ buf_set_u32(reg_params[1].value, 0, 32, src_base);
+ buf_set_u32(reg_params[2].value, 0, 32,
+ (addr4b << 30) | (info->dev->read_cmd << 20) |
+ chunk);
+ buf_set_u32(reg_params[3].value, 0, 32, offset);
+
+ ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ info->io_algorithm->address,
+ 0, 10000, &arm_algo);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("error executing SH QSPI flash IO algorithm");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+
+ target_read_buffer(target, info->source->address,
+ chunk, buffer);
+
+ buffer += chunk;
+ offset += chunk;
+ count -= chunk;
+ }
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+
+ return ret;
+}
+
+/* Return ID of flash device */
+static int read_flash_id(struct flash_bank *bank, uint32_t *id)
+{
+ struct target *target = bank->target;
+ uint8_t dout = SPIFLASH_READ_ID;
+ uint8_t din[3] = { 0, 0, 0 };
+ int ret;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ *id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16);
+
+ if (*id == 0xffffff) {
+ LOG_ERROR("No SPI flash found");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int sh_qspi_protect(struct flash_bank *bank, int set,
+ int first, int last)
+{
+ int sector;
+
+ for (sector = first; sector <= last; sector++)
+ bank->sectors[sector].is_protected = set;
+
+ return ERROR_OK;
+}
+
+static int sh_qspi_upload_helper(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+ /* see contrib/loaders/flash/sh_qspi.s for src */
+ static const uint8_t sh_qspi_io_code[] = {
+#include "../../../contrib/loaders/flash/sh_qspi/sh_qspi.inc"
+ };
+ int ret;
+
+ if (info->source)
+ target_free_working_area(target, info->source);
+ if (info->io_algorithm)
+ target_free_working_area(target, info->io_algorithm);
+
+ /* flash write code */
+ if (target_alloc_working_area(target, sizeof(sh_qspi_io_code),
+ &info->io_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ target_write_buffer(target, info->io_algorithm->address,
+ sizeof(sh_qspi_io_code), sh_qspi_io_code);
+
+ /*
+ * Try to allocate as big work area buffer as possible, start
+ * with 32 kiB and count down. If there is less than 256 Bytes
+ * of work area available, abort.
+ */
+ info->buffer_size = 32768;
+ while (true) {
+ ret = target_alloc_working_area_try(target, info->buffer_size,
+ &info->source);
+ if (ret == ERROR_OK)
+ return ret;
+
+ info->buffer_size /= 2;
+ if (info->buffer_size <= 256) {
+ target_free_working_area(target, info->io_algorithm);
+
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int sh_qspi_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+ struct flash_sector *sectors;
+ uint32_t id = 0; /* silence uninitialized warning */
+ uint32_t sectorsize;
+ const struct sh_qspi_target *target_device;
+ int ret;
+
+ if (info->probed)
+ free(bank->sectors);
+
+ info->probed = 0;
+
+ for (target_device = target_devices; target_device->name;
+ ++target_device)
+ if (target_device->tap_idcode == target->tap->idcode)
+ break;
+ if (!target_device->name) {
+ LOG_ERROR("Device ID 0x%" PRIx32 " is not known",
+ target->tap->idcode);
+ return ERROR_FAIL;
+ }
+
+ info->io_base = target_device->io_base;
+
+ LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT,
+ target_device->name, bank->base);
+
+ ret = sh_qspi_upload_helper(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = sh_qspi_init(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = read_flash_id(bank, &id);
+ if (ret != ERROR_OK)
+ return ret;
+
+ info->dev = NULL;
+ for (const struct flash_device *p = flash_devices; p->name; p++)
+ if (p->device_id == id) {
+ info->dev = p;
+ break;
+ }
+
+ if (!info->dev) {
+ LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
+ info->dev->name, info->dev->device_id);
+
+ /* Set correct size value */
+ bank->size = info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = info->dev->sectorsize ?
+ info->dev->sectorsize :
+ info->dev->size_in_bytes;
+
+ /* create and fill sectors array */
+ bank->num_sectors = info->dev->size_in_bytes / sectorsize;
+ sectors = calloc(1, sizeof(*sectors) * bank->num_sectors);
+ if (!sectors) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ for (int sector = 0; sector < bank->num_sectors; sector++) {
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
+ sectors[sector].is_erased = 0;
+ sectors[sector].is_protected = 0;
+ }
+
+ bank->sectors = sectors;
+ info->probed = 1;
+ return ERROR_OK;
+}
+
+static int sh_qspi_auto_probe(struct flash_bank *bank)
+{
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+ if (info->probed)
+ return ERROR_OK;
+
+ return sh_qspi_probe(bank);
+}
+
+static int sh_qspi_flash_blank_check(struct flash_bank *bank)
+{
+ /* Not implemented */
+ return ERROR_OK;
+}
+
+static int sh_qspi_protect_check(struct flash_bank *bank)
+{
+ /* Not implemented */
+ return ERROR_OK;
+}
+
+static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+ if (!info->probed) {
+ snprintf(buf, buf_size,
+ "\nSH QSPI flash bank not probed yet\n");
+ return ERROR_OK;
+ }
+
+ snprintf(buf, buf_size, "\nSH QSPI flash information:\n"
+ " Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+ info->dev->name, info->dev->device_id);
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command)
+{
+ struct sh_qspi_flash_bank *info;
+
+ LOG_DEBUG("%s", __func__);
+
+ if (CMD_ARGC < 6 || CMD_ARGC > 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) {
+ LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ info = calloc(1, sizeof(struct sh_qspi_flash_bank));
+ if (!info) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ bank->driver_priv = info;
+
+ return ERROR_OK;
+}
+
+const struct flash_driver sh_qspi_flash = {
+ .name = "sh_qspi",
+ .flash_bank_command = sh_qspi_flash_bank_command,
+ .erase = sh_qspi_erase,
+ .protect = sh_qspi_protect,
+ .write = sh_qspi_write,
+ .read = sh_qspi_read,
+ .probe = sh_qspi_probe,
+ .auto_probe = sh_qspi_auto_probe,
+ .erase_check = sh_qspi_flash_blank_check,
+ .protect_check = sh_qspi_protect_check,
+ .info = sh_qspi_get_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c
index 7ccf56b6e..4e39705fd 100644
--- a/src/flash/nor/sim3x.c
+++ b/src/flash/nor/sim3x.c
@@ -471,7 +471,7 @@ static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf,
return ret;
}
-static int sim3x_flash_write(struct flash_bank *bank, const uint8_t * buffer, uint32_t offset, uint32_t count)
+static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int ret;
struct target *target;
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index cf10e3747..990b48aeb 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -116,7 +116,7 @@ struct stm32x_options {
struct stm32x_flash_bank {
struct stm32x_options option_bytes;
int ppage_size;
- int probed;
+ bool probed;
bool has_dual_banks;
/* used to access dual flash bank stm32xl */
@@ -145,7 +145,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
bank->driver_priv = stm32x_info;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->has_dual_banks = false;
stm32x_info->can_load_options = false;
stm32x_info->register_base = FLASH_REG_BASE_B0;
@@ -229,34 +229,20 @@ static int stm32x_read_options(struct flash_bank *bank)
uint32_t option_bytes;
int retval;
- /* read user and read protection option bytes */
- retval = target_read_u32(target, STM32_OB_RDP, &option_bytes);
+ /* read user and read protection option bytes, user data option bytes */
+ retval = target_read_u32(target, STM32_FLASH_OBR_B0, &option_bytes);
if (retval != ERROR_OK)
return retval;
- stm32x_info->option_bytes.rdp = option_bytes & 0xFF;
- stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF;
-
- /* read user data option bytes */
- retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes);
- if (retval != ERROR_OK)
- return retval;
-
- stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
+ stm32x_info->option_bytes.rdp = (option_bytes & (1 << OPT_READOUT)) ? 0 : stm32x_info->default_rdp;
+ stm32x_info->option_bytes.user = (option_bytes >> stm32x_info->option_offset >> 2) & 0xff;
+ stm32x_info->option_bytes.data = (option_bytes >> stm32x_info->user_data_offset) & 0xffff;
/* read write protection option bytes */
- retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes);
+ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &stm32x_info->option_bytes.protection);
if (retval != ERROR_OK)
return retval;
- stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
-
- retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes);
- if (retval != ERROR_OK)
- return retval;
-
- stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16;
-
return ERROR_OK;
}
@@ -382,7 +368,6 @@ static int stm32x_protect_check(struct flash_bank *bank)
static int stm32x_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
- int i;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -400,7 +385,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
if (retval != ERROR_OK)
return retval;
- for (i = first; i <= last; i++) {
+ for (int i = first; i <= last; i++) {
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER);
if (retval != ERROR_OK)
return retval;
@@ -711,7 +696,7 @@ static int stm32x_probe(struct flash_bank *bank)
int page_size;
uint32_t base_address = 0x08000000;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->register_base = FLASH_REG_BASE_B0;
stm32x_info->user_data_offset = 10;
stm32x_info->option_offset = 0;
@@ -728,31 +713,79 @@ static int stm32x_probe(struct flash_bank *bank)
/* set page size, protection granularity and max flash size depending on family */
switch (device_id & 0xfff) {
- case 0x410: /* medium density */
+ case 0x440: /* stm32f05x */
+ page_size = 1024;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 64;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x444: /* stm32f03x */
+ case 0x445: /* stm32f04x */
+ page_size = 1024;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 32;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x448: /* stm32f07x */
+ page_size = 2048;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 128;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x442: /* stm32f09x */
+ page_size = 2048;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 256;
+ stm32x_info->user_data_offset = 16;
+ stm32x_info->option_offset = 6;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
+ break;
+ case 0x410: /* stm32f1x medium-density */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 128;
break;
- case 0x412: /* low density */
+ case 0x412: /* stm32f1x low-density */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 32;
break;
- case 0x414: /* high density */
+ case 0x414: /* stm32f1x high-density */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 512;
break;
- case 0x418: /* connectivity line density */
+ case 0x418: /* stm32f1x connectivity */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 256;
break;
- case 0x420: /* value line density */
+ case 0x430: /* stm32f1 XL-density (dual flash banks) */
+ page_size = 2048;
+ stm32x_info->ppage_size = 2;
+ max_flash_size_in_kb = 1024;
+ stm32x_info->has_dual_banks = true;
+ break;
+ case 0x420: /* stm32f100xx low- and medium-density value line */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 128;
break;
+ case 0x428: /* stm32f100xx high-density value line */
+ page_size = 2048;
+ stm32x_info->ppage_size = 4;
+ max_flash_size_in_kb = 512;
+ break;
case 0x422: /* stm32f302/3xb/c */
page_size = 2048;
stm32x_info->ppage_size = 2;
@@ -771,17 +804,6 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->default_rdp = 0xAA;
stm32x_info->can_load_options = true;
break;
- case 0x428: /* value line High density */
- page_size = 2048;
- stm32x_info->ppage_size = 4;
- max_flash_size_in_kb = 128;
- break;
- case 0x430: /* xl line density (dual flash banks) */
- page_size = 2048;
- stm32x_info->ppage_size = 2;
- max_flash_size_in_kb = 1024;
- stm32x_info->has_dual_banks = true;
- break;
case 0x432: /* stm32f37x */
page_size = 2048;
stm32x_info->ppage_size = 2;
@@ -801,27 +823,6 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->default_rdp = 0xAA;
stm32x_info->can_load_options = true;
break;
- case 0x440: /* stm32f05x */
- case 0x444: /* stm32f03x */
- case 0x445: /* stm32f04x */
- page_size = 1024;
- stm32x_info->ppage_size = 4;
- max_flash_size_in_kb = 64;
- stm32x_info->user_data_offset = 16;
- stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0xAA;
- stm32x_info->can_load_options = true;
- break;
- case 0x448: /* stm32f07x */
- case 0x442: /* stm32f09x */
- page_size = 2048;
- stm32x_info->ppage_size = 4;
- max_flash_size_in_kb = 256;
- stm32x_info->user_data_offset = 16;
- stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0xAA;
- stm32x_info->can_load_options = true;
- break;
default:
LOG_WARNING("Cannot identify target as a STM32 family.");
return ERROR_FAIL;
@@ -900,7 +901,7 @@ static int stm32x_probe(struct flash_bank *bank)
if (num_prot_blocks == 32)
bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size;
- stm32x_info->probed = 1;
+ stm32x_info->probed = true;
return ERROR_OK;
}
@@ -1368,8 +1369,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt);
CMD_ARGC--;
CMD_ARGV++;
- }
- else if (stm32x_info->has_dual_banks) {
+ } else if (stm32x_info->has_dual_banks) {
if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
optionbyte |= (1 << 3);
else if (strcmp("BOOT1", CMD_ARGV[0]) == 0)
@@ -1488,8 +1488,6 @@ static int stm32x_mass_erase(struct flash_bank *bank)
COMMAND_HANDLER(stm32x_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1501,7 +1499,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
retval = stm32x_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32x mass erase complete");
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index b49e76e32..c1283bb3f 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -634,7 +634,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
*/
for (i = first; i <= last; i++) {
- int snb;
+ unsigned int snb;
if (stm32x_info->has_large_mem && i >= 12)
snb = (i - 12) | 0x10;
else
@@ -894,31 +894,68 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
}
-static int setup_sector(struct flash_bank *bank, int start, int num, int size)
+static void setup_sector(struct flash_bank *bank, int i, int size)
{
+ assert(i < bank->num_sectors);
+ bank->sectors[i].offset = bank->size;
+ bank->sectors[i].size = size;
+ bank->size += bank->sectors[i].size;
+ LOG_DEBUG("sector %d: %dkBytes", i, size >> 10);
+}
- for (int i = start; i < (start + num) ; i++) {
- assert(i < bank->num_sectors);
- bank->sectors[i].offset = bank->size;
- bank->sectors[i].size = size;
- bank->size += bank->sectors[i].size;
- LOG_DEBUG("sector %d: %d kBytes", i, size >> 10);
+static uint16_t sector_size_in_kb(int i, uint16_t max_sector_size_in_kb)
+{
+ assert(i >= 0);
+ if (i < 4)
+ return max_sector_size_in_kb / 8;
+ if (i == 4)
+ return max_sector_size_in_kb / 2;
+ return max_sector_size_in_kb;
+}
+
+static int calculate_number_of_sectors(struct flash_bank *bank,
+ uint16_t flash_size_in_kb,
+ uint16_t max_sector_size_in_kb)
+{
+ struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+ uint16_t remaining_flash_size_in_kb = flash_size_in_kb;
+ int nr_sectors;
+
+ /* Dual Bank Flash has two identically-arranged banks of sectors. */
+ if (stm32x_info->has_large_mem)
+ remaining_flash_size_in_kb /= 2;
+
+ for (nr_sectors = 0; remaining_flash_size_in_kb > 0; nr_sectors++) {
+ uint16_t size_in_kb = sector_size_in_kb(nr_sectors, max_sector_size_in_kb);
+ if (size_in_kb > remaining_flash_size_in_kb) {
+ LOG_INFO("%s Bank %" PRIu16 " kiB final sector clipped to %" PRIu16 " kiB",
+ stm32x_info->has_large_mem ? "Dual" : "Single",
+ flash_size_in_kb, remaining_flash_size_in_kb);
+ remaining_flash_size_in_kb = 0;
+ } else {
+ remaining_flash_size_in_kb -= size_in_kb;
+ }
}
- return start + num;
+ return stm32x_info->has_large_mem ? nr_sectors*2 : nr_sectors;
}
static void setup_bank(struct flash_bank *bank, int start,
uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb)
{
- int remain;
-
- start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024);
- start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024);
-
- /* remaining sectors all of size max_sector_size_in_kb */
- remain = (flash_size_in_kb / max_sector_size_in_kb) - 1;
- start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024);
+ uint16_t remaining_flash_size_in_kb = flash_size_in_kb;
+ int sector_index = 0;
+ while (remaining_flash_size_in_kb > 0) {
+ uint16_t size_in_kb = sector_size_in_kb(sector_index, max_sector_size_in_kb);
+ if (size_in_kb > remaining_flash_size_in_kb) {
+ /* Clip last sector. Already warned in
+ * calculate_number_of_sectors. */
+ size_in_kb = remaining_flash_size_in_kb;
+ }
+ setup_sector(bank, start + sector_index, size_in_kb * 1024);
+ remaining_flash_size_in_kb -= size_in_kb;
+ sector_index++;
+ }
}
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
@@ -1150,12 +1187,12 @@ static int stm32x_probe(struct flash_bank *bank)
}
/* calculate numbers of pages */
- int num_pages = flash_size_in_kb / max_sector_size_in_kb
- + (stm32x_info->has_large_mem ? 8 : 4);
+ int num_pages = calculate_number_of_sectors(
+ bank, flash_size_in_kb, max_sector_size_in_kb);
bank->base = base_address;
bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+ bank->sectors = calloc(num_pages, sizeof(struct flash_sector));
for (i = 0; i < num_pages; i++) {
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c
index fd6bf9a09..7b6fdb39c 100644
--- a/src/flash/nor/stm32h7x.c
+++ b/src/flash/nor/stm32h7x.c
@@ -57,8 +57,6 @@
#define FLASH_FW (1 << 6)
#define FLASH_START (1 << 7)
-#define FLASH_SNB(a) ((a) << 8)
-
/* FLASH_SR register bits */
#define FLASH_BSY (1 << 0) /* Operation in progress */
#define FLASH_QW (1 << 2) /* Operation queue in progress */
@@ -79,6 +77,15 @@
#define OPT_LOCK (1 << 0)
#define OPT_START (1 << 1)
+/* FLASH_OPTSR register bits */
+#define OPT_BSY (1 << 0)
+#define OPT_RDP_POS 8
+#define OPT_RDP_MASK (0xff << OPT_RDP_POS)
+#define OPT_OPTCHANGEERR (1 << 30)
+
+/* FLASH_OPTCCR register bits */
+#define OPT_CLR_OPTCHANGEERR (1 << 30)
+
/* register unlock keys */
#define KEY1 0x45670123
#define KEY2 0xCDEF89AB
@@ -92,68 +99,103 @@
#define FLASH_BANK1_ADDRESS 0x08100000
#define FLASH_REG_BASE_B0 0x52002000
#define FLASH_REG_BASE_B1 0x52002100
-#define FLASH_SIZE_ADDRESS 0x1FF1E880
-#define FLASH_BLOCK_SIZE 32
struct stm32h7x_rev {
uint16_t rev;
const char *str;
};
-struct stm32x_options {
- uint8_t RDP;
- uint32_t protection; /* bank1 WRP */
- uint32_t protection2; /* bank2 WRP */
- uint8_t user_options;
- uint8_t user2_options;
- uint8_t user3_options;
-};
+/* stm32h7x_part_info permits the store each device information and specificities.
+ * the default unit is byte unless the suffix '_kb' is used. */
struct stm32h7x_part_info {
uint16_t id;
const char *device_str;
const struct stm32h7x_rev *revs;
size_t num_revs;
- unsigned int page_size;
+ unsigned int page_size_kb;
+ unsigned int block_size; /* flash write word size in bytes */
uint16_t max_flash_size_kb;
- uint8_t has_dual_bank;
- uint16_t first_bank_size_kb; /* Used when has_dual_bank is true */
- uint32_t flash_base; /* Flash controller registers location */
- uint32_t fsize_base; /* Location of FSIZE register */
+ bool has_dual_bank;
+ uint16_t max_bank_size_kb; /* Used when has_dual_bank is true */
+ uint32_t fsize_addr; /* Location of FSIZE register */
+ uint32_t wps_group_size; /* write protection group sectors' count */
+ uint32_t wps_mask;
+ /* function to compute flash_cr register values */
+ uint32_t (*compute_flash_cr)(uint32_t cmd, int snb);
};
struct stm32h7x_flash_bank {
- int probed;
+ bool probed;
uint32_t idcode;
uint32_t user_bank_size;
- uint32_t flash_base; /* Address of flash reg controller */
- struct stm32x_options option_bytes;
+ uint32_t flash_regs_base; /* Address of flash reg controller */
const struct stm32h7x_part_info *part_info;
};
-static const struct stm32h7x_rev stm32_450_revs[] = {
- { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" },
+enum stm32h7x_opt_rdp {
+ OPT_RDP_L0 = 0xaa,
+ OPT_RDP_L1 = 0x00,
+ OPT_RDP_L2 = 0xcc
};
+static const struct stm32h7x_rev stm32_450_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" },
+};
+
+static const struct stm32h7x_rev stm32_480_revs[] = {
+ { 0x1000, "A"},
+};
+
+static uint32_t stm32x_compute_flash_cr_450(uint32_t cmd, int snb)
+{
+ return cmd | (snb << 8);
+}
+
+static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb)
+{
+ /* save FW and START bits, to be right shifted by 2 bits later */
+ const uint32_t tmp = cmd & (FLASH_FW | FLASH_START);
+
+ /* mask parallelism (ignored), FW and START bits */
+ cmd &= ~(FLASH_PSIZE_64 | FLASH_FW | FLASH_START);
+
+ return cmd | (tmp >> 2) | (snb << 6);
+}
+
static const struct stm32h7x_part_info stm32h7x_parts[] = {
{
.id = 0x450,
.revs = stm32_450_revs,
.num_revs = ARRAY_SIZE(stm32_450_revs),
.device_str = "STM32H74x/75x",
- .page_size = 128, /* 128 KB */
+ .page_size_kb = 128,
+ .block_size = 32,
.max_flash_size_kb = 2048,
- .first_bank_size_kb = 1024,
- .has_dual_bank = 1,
- .flash_base = FLASH_REG_BASE_B0,
- .fsize_base = FLASH_SIZE_ADDRESS,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = true,
+ .fsize_addr = 0x1FF1E880,
+ .wps_group_size = 1,
+ .wps_mask = 0xFF,
+ .compute_flash_cr = stm32x_compute_flash_cr_450,
+ },
+ {
+ .id = 0x480,
+ .revs = stm32_480_revs,
+ .num_revs = ARRAY_SIZE(stm32_480_revs),
+ .device_str = "STM32H7Ax/7Bx",
+ .page_size_kb = 8,
+ .block_size = 16,
+ .max_flash_size_kb = 2048,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = true,
+ .fsize_addr = 0x08FFF80C,
+ .wps_group_size = 4,
+ .wps_mask = 0xFFFFFFFF,
+ .compute_flash_cr = stm32x_compute_flash_cr_480,
},
};
-static int stm32x_unlock_reg(struct flash_bank *bank);
-static int stm32x_lock_reg(struct flash_bank *bank);
-static int stm32x_probe(struct flash_bank *bank);
-
/* flash bank stm32x 0 0 */
FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
@@ -166,51 +208,68 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank));
bank->driver_priv = stm32x_info;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->user_bank_size = bank->size;
return ERROR_OK;
}
-static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
{
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
- return reg + stm32x_info->flash_base;
+ return reg_offset + stm32x_info->flash_regs_base;
+}
+
+static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
+{
+ uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset);
+ int retval = target_read_u32(bank->target, reg_addr, value);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("error while reading from address 0x%" PRIx32, reg_addr);
+
+ return retval;
+}
+
+static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset);
+ int retval = target_write_u32(bank->target, reg_addr, value);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("error while writing to address 0x%" PRIx32, reg_addr);
+
+ return retval;
}
static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status)
{
- struct target *target = bank->target;
- return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status);
+ return stm32x_read_flash_reg(bank, FLASH_SR, status);
}
static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
{
- struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
uint32_t status;
int retval;
/* wait for flash operations completion */
for (;;) {
retval = stm32x_get_flash_status(bank, &status);
- if (retval != ERROR_OK) {
- LOG_INFO("wait_flash_op_queue, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base);
+ if (retval != ERROR_OK)
return retval;
- }
if ((status & FLASH_QW) == 0)
break;
if (timeout-- <= 0) {
- LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status);
+ LOG_ERROR("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status);
return ERROR_FAIL;
}
alive_sleep(1);
}
if (status & FLASH_WRPERR) {
- LOG_INFO("wait_flash_op_queue, WRPERR : error : remote address 0x%x", stm32x_info->flash_base);
+ LOG_ERROR("wait_flash_op_queue, WRPERR detected");
retval = ERROR_FAIL;
}
@@ -219,7 +278,7 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
if (retval == ERROR_OK)
retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original retval */
- target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status);
+ stm32x_write_flash_reg(bank, FLASH_CCR, status);
}
return retval;
}
@@ -227,12 +286,11 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
static int stm32x_unlock_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- struct target *target = bank->target;
/* first check if not already unlocked
* otherwise writing on FLASH_KEYR will fail
*/
- int retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl);
+ int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -240,15 +298,15 @@ static int stm32x_unlock_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock flash registers for bank */
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1);
+ retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY2);
+ retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl);
+ retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -262,9 +320,8 @@ static int stm32x_unlock_reg(struct flash_bank *bank)
static int stm32x_unlock_option_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- struct target *target = bank->target;
- int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl);
+ int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -272,15 +329,15 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock option registers */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl);
+ retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -292,159 +349,108 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
}
-static int stm32x_lock_reg(struct flash_bank *bank)
+static inline int stm32x_lock_reg(struct flash_bank *bank)
{
- struct target *target = bank->target;
-
- /* Lock bank reg */
- int retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_LOCK);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK);
}
-static int stm32x_read_options(struct flash_bank *bank)
+static inline int stm32x_lock_option_reg(struct flash_bank *bank)
{
- uint32_t optiondata;
- struct stm32h7x_flash_bank *stm32x_info = NULL;
- struct target *target = bank->target;
-
- stm32x_info = bank->driver_priv;
-
- /* read current option bytes */
- int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_CUR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
-
- /* decode option data */
- stm32x_info->option_bytes.user_options = optiondata & 0xfc;
- stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff;
- stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff;
- stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0xa3;
-
- if (stm32x_info->option_bytes.RDP != 0xAA)
- LOG_INFO("Device Security Bit Set");
-
- /* read current WPSN option bytes */
- retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_CUR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32x_info->option_bytes.protection = optiondata & 0xff;
-
- /* read current WPSN2 option bytes */
- retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_CUR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32x_info->option_bytes.protection2 = optiondata & 0xff;
-
- return ERROR_OK;
+ return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK);
}
-static int stm32x_write_options(struct flash_bank *bank)
+static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
{
- struct stm32h7x_flash_bank *stm32x_info = NULL;
- struct target *target = bank->target;
- uint32_t optiondata;
+ int retval, retval2;
- stm32x_info = bank->driver_priv;
-
- int retval = stm32x_unlock_option_reg(bank);
+ /* unlock option bytes for modification */
+ retval = stm32x_unlock_option_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
- /* rebuild option data */
- optiondata = stm32x_info->option_bytes.user_options;
- optiondata |= (stm32x_info->option_bytes.RDP << 8);
- optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16;
- optiondata |= (stm32x_info->option_bytes.user3_options & 0xa3) << 24;
-
- /* program options */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_PRG, optiondata);
+ /* write option bytes */
+ retval = stm32x_write_flash_reg(bank, reg_offset, value);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
- optiondata = stm32x_info->option_bytes.protection & 0xff;
- /* Program protection WPSNPRG */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_PRG, optiondata);
- if (retval != ERROR_OK)
- return retval;
-
- optiondata = stm32x_info->option_bytes.protection2 & 0xff;
- /* Program protection WPSNPRG2 */
- retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_PRG, optiondata);
- if (retval != ERROR_OK)
- return retval;
-
- optiondata = 0x40000000;
/* Remove OPT error flag before programming */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
/* start programming cycle */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START);
+ retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START);
if (retval != ERROR_OK)
- return retval;
+ goto flash_options_lock;
/* wait for completion */
int timeout = FLASH_ERASE_TIMEOUT;
+ uint32_t status;
for (;;) {
- uint32_t status;
- retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status);
+ retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status);
if (retval != ERROR_OK) {
- LOG_INFO("stm32x_write_options: wait_flash_op_queue : error");
- return retval;
+ LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR");
+ goto flash_options_lock;
}
- if ((status & FLASH_QW) == 0)
+ if ((status & OPT_BSY) == 0)
break;
if (timeout-- <= 0) {
- LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status);
- return ERROR_FAIL;
+ LOG_ERROR("waiting for OBL launch, time out expired, OPTSR: 0x%" PRIx32 "", status);
+ retval = ERROR_FAIL;
+ goto flash_options_lock;
}
alive_sleep(1);
}
- /* relock option registers */
- retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK);
+ /* check for failure */
+ if (status & OPT_OPTCHANGEERR) {
+ LOG_ERROR("error changing option bytes (OPTCHANGEERR=1)");
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ }
+
+flash_options_lock:
+ retval2 = stm32x_lock_option_reg(bank);
+ if (retval2 != ERROR_OK)
+ LOG_ERROR("error during the lock of flash options");
+
+ return (retval == ERROR_OK) ? retval2 : retval;
+}
+
+static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask)
+{
+ uint32_t data;
+
+ int retval = stm32x_read_flash_reg(bank, reg_offset, &data);
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ data = (data & ~mask) | (value & mask);
+
+ return stm32x_write_option(bank, reg_offset, data);
}
static int stm32x_protect_check(struct flash_bank *bank)
{
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ uint32_t protection;
/* read 'write protection' settings */
- int retval = stm32x_read_options(bank);
+ int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection);
if (retval != ERROR_OK) {
- LOG_DEBUG("unable to read option bytes");
+ LOG_DEBUG("unable to read WPSN_CUR register");
return retval;
}
- for (int i = 0; i < bank->num_sectors; i++) {
- if (stm32x_info->flash_base == FLASH_REG_BASE_B0) {
- if (stm32x_info->option_bytes.protection & (1 << i))
- bank->sectors[i].is_protected = 0;
- else
- bank->sectors[i].is_protected = 1;
- } else {
- if (stm32x_info->option_bytes.protection2 & (1 << i))
- bank->sectors[i].is_protected = 0;
- else
- bank->sectors[i].is_protected = 1;
- }
- }
+ for (int i = 0; i < bank->num_prot_blocks; i++)
+ bank->prot_blocks[i].is_protected = protection & (1 << i) ? 0 : 1;
+
return ERROR_OK;
}
static int stm32x_erase(struct flash_bank *bank, int first, int last)
{
- struct target *target = bank->target;
- int retval;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ int retval, retval2;
assert(first < bank->num_sectors);
assert(last < bank->num_sectors);
@@ -454,7 +460,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
retval = stm32x_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
/*
Sector Erase
@@ -468,92 +474,84 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
*/
for (int i = first; i <= last; i++) {
LOG_DEBUG("erase sector %d", i);
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR),
- FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i));
if (retval != ERROR_OK) {
LOG_ERROR("Error erase sector %d", i);
- return retval;
+ goto flash_lock;
}
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR),
- FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i));
if (retval != ERROR_OK) {
LOG_ERROR("Error erase sector %d", i);
- return retval;
+ goto flash_lock;
}
retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK) {
LOG_ERROR("erase time-out or operation error sector %d", i);
- return retval;
+ goto flash_lock;
}
bank->sectors[i].is_erased = 1;
}
- retval = stm32x_lock_reg(bank);
- if (retval != ERROR_OK) {
+flash_lock:
+ retval2 = stm32x_lock_reg(bank);
+ if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
- return retval;
- }
- return ERROR_OK;
+ return (retval == ERROR_OK) ? retval2 : retval;
}
static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ uint32_t protection;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- /* read protection settings */
- int retval = stm32x_read_options(bank);
+
+ /* read 'write protection' settings */
+ int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection);
if (retval != ERROR_OK) {
- LOG_DEBUG("unable to read option bytes");
+ LOG_DEBUG("unable to read WPSN_CUR register");
return retval;
}
for (int i = first; i <= last; i++) {
- if (stm32x_info->flash_base == FLASH_REG_BASE_B0) {
- if (set)
- stm32x_info->option_bytes.protection &= ~(1 << i);
- else
- stm32x_info->option_bytes.protection |= (1 << i);
- } else {
- if (set)
- stm32x_info->option_bytes.protection2 &= ~(1 << i);
- else
- stm32x_info->option_bytes.protection2 |= (1 << i);
- }
+ if (set)
+ protection &= ~(1 << i);
+ else
+ protection |= (1 << i);
}
- LOG_INFO("stm32x_protect, option_bytes written WRP1 0x%x , WRP2 0x%x",
- (stm32x_info->option_bytes.protection & 0xff), (stm32x_info->option_bytes.protection2 & 0xff));
+ /* apply WRPSN mask */
+ protection &= 0xff;
- retval = stm32x_write_options(bank);
- if (retval != ERROR_OK)
- return retval;
+ LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection);
- return ERROR_OK;
+ /* apply new option value */
+ return stm32x_write_option(bank, FLASH_WPSN_PRG, protection);
}
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
/*
- * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get
+ * If the size of the data part of the buffer is not a multiple of .block_size, we get
* "corrupted fifo read" pointer in target_run_flash_async_algorithm()
*/
- uint32_t data_size = 512 * FLASH_BLOCK_SIZE; /* 16384 */
+ uint32_t data_size = 512 * stm32x_info->part_info->block_size;
uint32_t buffer_size = 8 + data_size;
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
- struct reg_param reg_params[5];
+ struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
int retval = ERROR_OK;
static const uint8_t stm32x_flash_write_code[] = {
@@ -588,7 +586,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
}
}
- LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size);
+ LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%" PRIx32, buffer_size);
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
@@ -596,27 +594,29 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */
- init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (word-256 bits) */
- init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash reg base */
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count of words (word size = .block_size (bytes) */
+ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* word size in bytes */
+ init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash reg base */
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[2].value, 0, 32, address);
buf_set_u32(reg_params[3].value, 0, 32, count);
- buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->flash_base);
+ buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->part_info->block_size);
+ buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base);
retval = target_run_flash_async_algorithm(target,
buffer,
count,
- FLASH_BLOCK_SIZE,
+ stm32x_info->part_info->block_size,
0, NULL,
- 5, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
if (retval == ERROR_FLASH_OPERATION_FAILED) {
- LOG_INFO("error executing stm32h7x flash write algorithm");
+ LOG_ERROR("error executing stm32h7x flash write algorithm");
uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32);
@@ -626,7 +626,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
if ((flash_sr & FLASH_ERROR) != 0) {
LOG_ERROR("flash write failed, FLASH_SR = %08" PRIx32, flash_sr);
/* Clear error + EOP flags but report errors */
- target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), flash_sr);
+ stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr);
retval = ERROR_FAIL;
}
}
@@ -639,6 +639,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
destroy_reg_param(®_params[2]);
destroy_reg_param(®_params[3]);
destroy_reg_param(®_params[4]);
+ destroy_reg_param(®_params[5]);
return retval;
}
@@ -646,6 +647,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
uint32_t address = bank->base + offset;
int retval, retval2;
@@ -654,19 +656,19 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_TARGET_NOT_HALTED;
}
- if (offset % FLASH_BLOCK_SIZE) {
- LOG_WARNING("offset 0x%" PRIx32 " breaks required 32-byte alignment", offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
+ /* should be enforced via bank->write_start_alignment */
+ assert(!(offset % stm32x_info->part_info->block_size));
+
+ /* should be enforced via bank->write_end_alignment */
+ assert(!(count % stm32x_info->part_info->block_size));
retval = stm32x_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
- uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE;
- uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE;
+ uint32_t blocks_remaining = count / stm32x_info->part_info->block_size;
- /* multiple words (32-bytes) to be programmed in block */
+ /* multiple words (n * .block_size) to be programmed in block */
if (blocks_remaining) {
retval = stm32x_write_block(bank, buffer, offset, blocks_remaining);
if (retval != ERROR_OK) {
@@ -676,8 +678,8 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
}
} else {
- buffer += blocks_remaining * FLASH_BLOCK_SIZE;
- address += blocks_remaining * FLASH_BLOCK_SIZE;
+ buffer += blocks_remaining * stm32x_info->part_info->block_size;
+ address += blocks_remaining * stm32x_info->part_info->block_size;
blocks_remaining = 0;
}
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
@@ -694,11 +696,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
4. Wait for flash operations completion
*/
while (blocks_remaining > 0) {
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0));
if (retval != ERROR_OK)
goto flash_lock;
- retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer);
+ retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer);
if (retval != ERROR_OK)
goto flash_lock;
@@ -706,49 +709,17 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
goto flash_lock;
- buffer += FLASH_BLOCK_SIZE;
- address += FLASH_BLOCK_SIZE;
+ buffer += stm32x_info->part_info->block_size;
+ address += stm32x_info->part_info->block_size;
blocks_remaining--;
}
- if (bytes_remaining) {
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64);
- if (retval != ERROR_OK)
- goto flash_lock;
-
- retval = target_write_buffer(target, address, bytes_remaining, buffer);
- if (retval != ERROR_OK)
- goto flash_lock;
-
- /* Force Write buffer of FLASH_BLOCK_SIZE = 32 bytes */
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64 | FLASH_FW);
- if (retval != ERROR_OK)
- goto flash_lock;
-
- retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT);
- if (retval != ERROR_OK)
- goto flash_lock;
- }
-
flash_lock:
retval2 = stm32x_lock_reg(bank);
if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
- if (retval == ERROR_OK)
- retval = retval2;
-
- return retval;
-}
-
-static void setup_sector(struct flash_bank *bank, int start, int num, int size)
-{
- for (int i = start; i < (start + num) ; i++) {
- assert(i < bank->num_sectors);
- bank->sectors[i].offset = bank->size;
- bank->sectors[i].size = size;
- bank->size += bank->sectors[i].size;
- }
+ return (retval == ERROR_OK) ? retval2 : retval;
}
static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id)
@@ -764,13 +735,10 @@ static int stm32x_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
- int i;
uint16_t flash_size_in_kb;
uint32_t device_id;
- uint32_t base_address = FLASH_BANK0_ADDRESS;
- uint32_t second_bank_base;
- stm32x_info->probed = 0;
+ stm32x_info->probed = false;
stm32x_info->part_info = NULL;
int retval = stm32x_read_id_code(bank, &stm32x_info->idcode);
@@ -792,44 +760,77 @@ static int stm32x_probe(struct flash_bank *bank)
LOG_INFO("Device: %s", stm32x_info->part_info->device_str);
}
- /* update the address of controller from data base */
- stm32x_info->flash_base = stm32x_info->part_info->flash_base;
+ /* update the address of controller */
+ if (bank->base == FLASH_BANK0_ADDRESS)
+ stm32x_info->flash_regs_base = FLASH_REG_BASE_B0;
+ else if (bank->base == FLASH_BANK1_ADDRESS)
+ stm32x_info->flash_regs_base = FLASH_REG_BASE_B1;
+ else {
+ LOG_WARNING("Flash register base not defined for bank %d", bank->bank_number);
+ return ERROR_FAIL;
+ }
+ LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base);
/* get flash size from target */
- retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb);
+ retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb);
if (retval != ERROR_OK) {
/* read error when device has invalid value, set max flash size */
flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb;
} else
LOG_INFO("flash size probed value %d", flash_size_in_kb);
- /* Lower flash size devices are single bank */
- if (stm32x_info->part_info->has_dual_bank && (flash_size_in_kb > stm32x_info->part_info->first_bank_size_kb)) {
- /* Use the configured base address to determine if this is the first or second flash bank.
- * Verify that the base address is reasonably correct and determine the flash bank size
+
+
+
+ /* setup bank size */
+ const uint32_t bank1_base = FLASH_BANK0_ADDRESS;
+ const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024;
+ bool has_dual_bank = stm32x_info->part_info->has_dual_bank;
+
+ switch (device_id) {
+ case 0x450:
+ case 0x480:
+ /* For STM32H74x/75x and STM32H7Ax/Bx
+ * - STM32H7xxxI devices contains dual bank, 1 Mbyte each
+ * - STM32H7xxxG devices contains dual bank, 512 Kbyte each
+ * - STM32H7xxxB devices contains single bank, 128 Kbyte
+ * - the second bank starts always from 0x08100000
*/
- second_bank_base = base_address + stm32x_info->part_info->first_bank_size_kb * 1024;
- if (bank->base == second_bank_base) {
- /* This is the second bank */
- base_address = second_bank_base;
- flash_size_in_kb = flash_size_in_kb - stm32x_info->part_info->first_bank_size_kb;
- /* bank1 also uses a register offset */
- stm32x_info->flash_base = FLASH_REG_BASE_B1;
- } else if (bank->base == base_address) {
- /* This is the first bank */
- flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb;
- } else {
- LOG_WARNING("STM32H flash bank base address config is incorrect. "
- TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
- bank->base, base_address, second_bank_base);
+ if (flash_size_in_kb == 128)
+ has_dual_bank = false;
+ else
+ /* flash size is 2M or 1M */
+ flash_size_in_kb /= 2;
+ break;
+ default:
+ LOG_ERROR("unsupported device");
+ return ERROR_FAIL;
+ }
+
+ if (has_dual_bank) {
+ LOG_INFO("STM32H7 flash has dual banks");
+ if (bank->base != bank1_base && bank->base != bank2_base) {
+ LOG_ERROR("STM32H7 flash bank base address config is incorrect. "
+ TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
+ bank->base, bank1_base, bank2_base);
return ERROR_FAIL;
}
- LOG_INFO("STM32H flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32,
- bank->bank_number, flash_size_in_kb, base_address);
} else {
- LOG_INFO("STM32H flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address);
+ LOG_INFO("STM32H7 flash has a single bank");
+ if (bank->base == bank2_base) {
+ LOG_ERROR("this device has a single bank only");
+ return ERROR_FAIL;
+ } else if (bank->base != bank1_base) {
+ LOG_ERROR("STM32H7 flash bank base address config is incorrect. "
+ TARGET_ADDR_FMT " but should be 0x%" PRIx32,
+ bank->base, bank1_base);
+ return ERROR_FAIL;
+ }
}
+ LOG_INFO("Bank (%d) size is %d kb, base address is 0x%" PRIx32,
+ bank->bank_number, flash_size_in_kb, (uint32_t) bank->base);
+
/* if the user sets the size manually then ignore the probed value
* this allows us to work around devices that have an invalid flash size register value */
if (stm32x_info->user_bank_size) {
@@ -842,33 +843,41 @@ static int stm32x_probe(struct flash_bank *bank)
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
+ bank->size = flash_size_in_kb * 1024;
+ bank->write_start_alignment = stm32x_info->part_info->block_size;
+ bank->write_end_alignment = stm32x_info->part_info->block_size;
- /* calculate numbers of pages */
- int num_pages = flash_size_in_kb / stm32x_info->part_info->page_size;
+ /* setup sectors */
+ bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb;
+ assert(bank->num_sectors > 0);
- /* check that calculation result makes sense */
- assert(num_pages > 0);
-
- if (bank->sectors) {
+ if (bank->sectors)
free(bank->sectors);
- bank->sectors = NULL;
- }
- bank->base = base_address;
- bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+ bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024,
+ bank->num_sectors);
+
if (bank->sectors == NULL) {
LOG_ERROR("failed to allocate bank sectors");
return ERROR_FAIL;
}
- bank->size = 0;
- /* fixed memory */
- setup_sector(bank, 0, num_pages, stm32x_info->part_info->page_size * 1024);
+ /* setup protection blocks */
+ const uint32_t wpsn = stm32x_info->part_info->wps_group_size;
+ assert(bank->num_sectors % wpsn == 0);
- for (i = 0; i < num_pages; i++) {
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 0;
+ bank->num_prot_blocks = bank->num_sectors / wpsn;
+ assert(bank->num_prot_blocks > 0);
+
+ if (bank->prot_blocks)
+ free(bank->prot_blocks);
+
+ bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024,
+ bank->num_prot_blocks);
+
+ if (bank->prot_blocks == NULL) {
+ LOG_ERROR("failed to allocate bank prot_block");
+ return ERROR_FAIL;
}
stm32x_info->probed = 1;
@@ -922,11 +931,52 @@ static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
+static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp)
+{
+ struct target *target = bank->target;
+ uint32_t optsr, cur_rdp;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr);
+
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("unable to read FLASH_OPTSR_PRG register");
+ return retval;
+ }
+
+ /* get current RDP, and check if there is a change */
+ cur_rdp = (optsr & OPT_RDP_MASK) >> OPT_RDP_POS;
+ if (new_rdp == cur_rdp) {
+ LOG_INFO("the requested RDP value is already programmed");
+ return ERROR_OK;
+ }
+
+ switch (new_rdp) {
+ case OPT_RDP_L0:
+ LOG_WARNING("unlocking the entire flash device");
+ break;
+ case OPT_RDP_L1:
+ LOG_WARNING("locking the entire flash device");
+ break;
+ case OPT_RDP_L2:
+ LOG_WARNING("locking the entire flash device, irreversible");
+ break;
+ }
+
+ /* apply new RDP */
+ optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS);
+
+ /* apply new option value */
+ return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr);
+}
+
COMMAND_HANDLER(stm32x_handle_lock_command)
{
- struct target *target = NULL;
- struct stm32h7x_flash_bank *stm32x_info = NULL;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -935,44 +985,18 @@ COMMAND_HANDLER(stm32x_handle_lock_command)
if (ERROR_OK != retval)
return retval;
- stm32x_info = bank->driver_priv;
- target = bank->target;
+ retval = stm32x_set_rdp(bank, OPT_RDP_L1);
- /* if we have a dual flash bank device then
- * we need to perform option byte lock on bank0 only */
- if (stm32x_info->flash_base != FLASH_REG_BASE_B0) {
- LOG_ERROR("Option Byte Lock Operation must use bank0");
- return ERROR_FLASH_OPERATION_FAILED;
- }
+ if (retval != ERROR_OK)
+ command_print(CMD, "%s failed to lock device", bank->driver->name);
+ else
+ command_print(CMD, "%s locked", bank->driver->name);
- if (target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stm32x_read_options(bank) != ERROR_OK) {
- command_print(CMD, "%s failed to read options",
- bank->driver->name);
- return ERROR_OK;
- }
- /* set readout protection */
- stm32x_info->option_bytes.RDP = 0;
-
- if (stm32x_write_options(bank) != ERROR_OK) {
- command_print(CMD, "%s failed to lock device",
- bank->driver->name);
- return ERROR_OK;
- }
- command_print(CMD, "%s locked", bank->driver->name);
-
- return ERROR_OK;
+ return retval;
}
COMMAND_HANDLER(stm32x_handle_unlock_command)
{
- struct target *target = NULL;
- struct stm32h7x_flash_bank *stm32x_info = NULL;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -981,43 +1005,21 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
if (ERROR_OK != retval)
return retval;
- stm32x_info = bank->driver_priv;
- target = bank->target;
+ retval = stm32x_set_rdp(bank, OPT_RDP_L0);
- /* if we have a dual flash bank device then
- * we need to perform option byte unlock on bank0 only */
- if (stm32x_info->flash_base != FLASH_REG_BASE_B0) {
- LOG_ERROR("Option Byte Unlock Operation must use bank0");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if (target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stm32x_read_options(bank) != ERROR_OK) {
- command_print(CMD, "%s failed to read options", bank->driver->name);
- return ERROR_OK;
- }
-
- /* clear readout protection option byte
- * this will also force a device unlock if set */
- stm32x_info->option_bytes.RDP = 0xAA;
-
- if (stm32x_write_options(bank) != ERROR_OK) {
+ if (retval != ERROR_OK)
command_print(CMD, "%s failed to unlock device", bank->driver->name);
- return ERROR_OK;
- }
- command_print(CMD, "%s unlocked.\n", bank->driver->name);
+ else
+ command_print(CMD, "%s unlocked", bank->driver->name);
- return ERROR_OK;
+ return retval;
}
static int stm32x_mass_erase(struct flash_bank *bank)
{
- int retval;
+ int retval, retval2;
struct target *target = bank->target;
+ struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -1026,34 +1028,33 @@ static int stm32x_mass_erase(struct flash_bank *bank)
retval = stm32x_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
/* mass erase flash memory bank */
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER | FLASH_PSIZE_64);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0));
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
- retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR),
- FLASH_BER | FLASH_PSIZE_64 | FLASH_START);
+ retval = stm32x_write_flash_reg(bank, FLASH_CR,
+ stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0));
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
retval = stm32x_wait_flash_op_queue(bank, 30000);
if (retval != ERROR_OK)
- return retval;
+ goto flash_lock;
- retval = stm32x_lock_reg(bank);
- if (retval != ERROR_OK) {
+flash_lock:
+ retval2 = stm32x_lock_reg(bank);
+ if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
- return retval;
- }
- return ERROR_OK;
+
+ return (retval == ERROR_OK) ? retval2 : retval;
}
COMMAND_HANDLER(stm32x_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1) {
command_print(CMD, "stm32h7x mass_erase ");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1067,7 +1068,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
retval = stm32x_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32h7x mass erase complete");
@@ -1078,6 +1079,53 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
return retval;
}
+COMMAND_HANDLER(stm32x_handle_option_read_command)
+{
+ if (CMD_ARGC < 2) {
+ command_print(CMD, "stm32h7x option_read ");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_offset, value;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+ retval = stm32x_read_flash_reg(bank, reg_offset, &value);
+ if (ERROR_OK != retval)
+ return retval;
+
+ command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "",
+ stm32x_get_flash_reg(bank, reg_offset), value);
+
+ return retval;
+}
+
+COMMAND_HANDLER(stm32x_handle_option_write_command)
+{
+ if (CMD_ARGC < 3) {
+ command_print(CMD, "stm32h7x option_write [mask]");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_offset, value, mask = 0xffffffff;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
+ if (CMD_ARGC > 3)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask);
+
+ return stm32x_modify_option(bank, reg_offset, value, mask);
+}
+
static const struct command_registration stm32x_exec_command_handlers[] = {
{
.name = "lock",
@@ -1100,6 +1148,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.usage = "bank_id",
.help = "Erase entire flash device.",
},
+ {
+ .name = "option_read",
+ .handler = stm32x_handle_option_read_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id reg_offset",
+ .help = "Read and display device option bytes.",
+ },
+ {
+ .name = "option_write",
+ .handler = stm32x_handle_option_write_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id reg_offset value [mask]",
+ .help = "Write device option bit fields with provided value.",
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index f680542c7..94fcd3226 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -1,7 +1,10 @@
/***************************************************************************
* Copyright (C) 2015 by Uwe Bonnes *
* bon@elektron.ikp.physik.tu-darmstadt.de *
- *
+ * *
+ * Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics *
+ * tarek.bouchkati@gmail.com *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
@@ -24,6 +27,8 @@
#include
#include
#include
+#include "bits.h"
+#include "stm32l4x.h"
/* STM32L4xxx series for reference.
*
@@ -47,91 +52,294 @@
* RM0394 devices have a single bank only.
*
* RM0432 devices have single and dual bank operating modes.
- * The FLASH size is 1Mbyte or 2Mbyte.
+ * - for STM32L4R/Sxx the FLASH size is 2Mbyte or 1Mbyte.
+ * - for STM32L4P/Q5x the FLASH size is 1Mbyte or 512Kbyte.
* Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode).
*
* Bank mode is controlled by two different bits in option bytes register.
- * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
- * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ * - for STM32L4R/Sxx
+ * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
+ * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ * - for STM32L4P5/Q5x
+ * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
+ * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode.
*
*/
+/* STM32WBxxx series for reference.
+ *
+ * RM0434 (STM32WB55)
+ * http://www.st.com/resource/en/reference_manual/dm00318631.pdf
+ *
+ * RM0471 (STM32WB50)
+ * http://www.st.com/resource/en/reference_manual/dm00622834.pdf
+ */
+
+/* STM32WLxxx series for reference.
+ *
+ * RM0461 (STM32WLEx)
+ * http://www.st.com/resource/en/reference_manual/dm00530369.pdf
+ */
+
+/*
+ * STM32G0xxx series for reference.
+ *
+ * RM0444 (STM32G0x1)
+ * http://www.st.com/resource/en/reference_manual/dm00371828.pdf
+ *
+ * RM0454 (STM32G0x0)
+ * http://www.st.com/resource/en/reference_manual/dm00463896.pdf
+ */
+
+/*
+ * STM32G4xxx series for reference.
+ *
+ * RM0440 (STM32G43x/44x/47x/48x)
+ * http://www.st.com/resource/en/reference_manual/dm00355726.pdf
+ *
+ * Cat. 2 devices have single bank only, page size is 2kByte.
+ *
+ * Cat. 3 devices have single and dual bank operating modes,
+ * Page size is 2kByte (dual mode) or 4kByte (single mode).
+ *
+ * Bank mode is controlled by bit 22 (DBANK) in option bytes register.
+ * Both banks are treated as a single OpenOCD bank.
+ */
+
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
#define FLASH_ERASE_TIMEOUT 250
-#define STM32_FLASH_BASE 0x40022000
-#define STM32_FLASH_ACR 0x40022000
-#define STM32_FLASH_KEYR 0x40022008
-#define STM32_FLASH_OPTKEYR 0x4002200c
-#define STM32_FLASH_SR 0x40022010
-#define STM32_FLASH_CR 0x40022014
-#define STM32_FLASH_OPTR 0x40022020
-#define STM32_FLASH_WRP1AR 0x4002202c
-#define STM32_FLASH_WRP1BR 0x40022030
-#define STM32_FLASH_WRP2AR 0x4002204c
-#define STM32_FLASH_WRP2BR 0x40022050
-
-/* FLASH_CR register bits */
-
-#define FLASH_PG (1 << 0)
-#define FLASH_PER (1 << 1)
-#define FLASH_MER1 (1 << 2)
-#define FLASH_PAGE_SHIFT 3
-#define FLASH_CR_BKER (1 << 11)
-#define FLASH_MER2 (1 << 15)
-#define FLASH_STRT (1 << 16)
-#define FLASH_OPTSTRT (1 << 17)
-#define FLASH_EOPIE (1 << 24)
-#define FLASH_ERRIE (1 << 25)
-#define FLASH_OBLLAUNCH (1 << 27)
-#define FLASH_OPTLOCK (1 << 30)
-#define FLASH_LOCK (1 << 31)
-
-/* FLASH_SR register bits */
-
-#define FLASH_BSY (1 << 16)
-/* Fast programming not used => related errors not used*/
-#define FLASH_PGSERR (1 << 7) /* Programming sequence error */
-#define FLASH_SIZERR (1 << 6) /* Size error */
-#define FLASH_PGAERR (1 << 5) /* Programming alignment error */
-#define FLASH_WRPERR (1 << 4) /* Write protection error */
-#define FLASH_PROGERR (1 << 3) /* Programming error */
-#define FLASH_OPERR (1 << 1) /* Operation error */
-#define FLASH_EOP (1 << 0) /* End of operation */
-
-#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGSERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR)
-
-/* STM32_FLASH_OBR bit definitions (reading) */
-
-#define OPT_DBANK_LE_1M (1 << 21) /* dual bank for devices up to 1M flash */
-#define OPT_DBANK_GE_2M (1 << 22) /* dual bank for devices with 2M flash */
-
-/* register unlock keys */
-
-#define KEY1 0x45670123
-#define KEY2 0xCDEF89AB
-
-/* option register unlock key */
-#define OPTKEY1 0x08192A3B
-#define OPTKEY2 0x4C5D6E7F
-
-#define RDP_LEVEL_0 0xAA
-#define RDP_LEVEL_1 0xBB
-#define RDP_LEVEL_2 0xCC
-
-
-/* other registers */
-#define DBGMCU_IDCODE 0xE0042000
-#define FLASH_SIZE_REG 0x1FFF75E0
-
-struct stm32l4_flash_bank {
- uint16_t bank2_start;
- int probed;
+struct stm32l4_rev {
+ const uint16_t rev;
+ const char *str;
};
-/* flash bank stm32l4x 0 0
- */
+struct stm32l4_part_info {
+ uint16_t id;
+ const char *device_str;
+ const struct stm32l4_rev *revs;
+ const size_t num_revs;
+ const uint16_t max_flash_size_kb;
+ const bool has_dual_bank;
+ const uint32_t flash_regs_base;
+ const uint32_t fsize_addr;
+};
+
+struct stm32l4_flash_bank {
+ bool probed;
+ uint32_t idcode;
+ int bank1_sectors;
+ bool dual_bank_mode;
+ int hole_sectors;
+ uint32_t user_bank_size;
+ uint32_t wrpxxr_mask;
+ const struct stm32l4_part_info *part_info;
+};
+
+/* human readable list of families this drivers supports */
+static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0";
+
+static const struct stm32l4_rev stm32_415_revs[] = {
+ { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
+};
+
+static const struct stm32l4_rev stm32_435_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
+};
+
+static const struct stm32l4_rev stm32_460_revs[] = {
+ { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_461_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_462_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
+};
+
+static const struct stm32l4_rev stm32_464_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
+};
+
+static const struct stm32l4_rev stm32_466_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_468_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
+};
+
+static const struct stm32l4_rev stm32_469_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
+};
+
+static const struct stm32l4_rev stm32_470_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" },
+};
+
+static const struct stm32l4_rev stm32_471_revs[] = {
+ { 0x1001, "Z" },
+};
+
+static const struct stm32l4_rev stm32_495_revs[] = {
+ { 0x2001, "2.1" },
+};
+
+static const struct stm32l4_rev stm32_496_revs[] = {
+ { 0x1000, "A" },
+};
+
+static const struct stm32l4_rev stm32_497_revs[] = {
+ { 0x1000, "1.0" },
+};
+
+static const struct stm32l4_part_info stm32l4_parts[] = {
+ {
+ .id = 0x415,
+ .revs = stm32_415_revs,
+ .num_revs = ARRAY_SIZE(stm32_415_revs),
+ .device_str = "STM32L47/L48xx",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x435,
+ .revs = stm32_435_revs,
+ .num_revs = ARRAY_SIZE(stm32_435_revs),
+ .device_str = "STM32L43/L44xx",
+ .max_flash_size_kb = 256,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x460,
+ .revs = stm32_460_revs,
+ .num_revs = ARRAY_SIZE(stm32_460_revs),
+ .device_str = "STM32G07/G08xx",
+ .max_flash_size_kb = 128,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x461,
+ .revs = stm32_461_revs,
+ .num_revs = ARRAY_SIZE(stm32_461_revs),
+ .device_str = "STM32L49/L4Axx",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x462,
+ .revs = stm32_462_revs,
+ .num_revs = ARRAY_SIZE(stm32_462_revs),
+ .device_str = "STM32L45/L46xx",
+ .max_flash_size_kb = 512,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x464,
+ .revs = stm32_464_revs,
+ .num_revs = ARRAY_SIZE(stm32_464_revs),
+ .device_str = "STM32L41/L42xx",
+ .max_flash_size_kb = 128,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x466,
+ .revs = stm32_466_revs,
+ .num_revs = ARRAY_SIZE(stm32_466_revs),
+ .device_str = "STM32G03/G04xx",
+ .max_flash_size_kb = 64,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x468,
+ .revs = stm32_468_revs,
+ .num_revs = ARRAY_SIZE(stm32_468_revs),
+ .device_str = "STM32G43/G44xx",
+ .max_flash_size_kb = 128,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x469,
+ .revs = stm32_469_revs,
+ .num_revs = ARRAY_SIZE(stm32_469_revs),
+ .device_str = "STM32G47/G48xx",
+ .max_flash_size_kb = 512,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x470,
+ .revs = stm32_470_revs,
+ .num_revs = ARRAY_SIZE(stm32_470_revs),
+ .device_str = "STM32L4R/L4Sxx",
+ .max_flash_size_kb = 2048,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x471,
+ .revs = stm32_471_revs,
+ .num_revs = ARRAY_SIZE(stm32_471_revs),
+ .device_str = "STM32L4P5/L4Q5x",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x495,
+ .revs = stm32_495_revs,
+ .num_revs = ARRAY_SIZE(stm32_495_revs),
+ .device_str = "STM32WB5x",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x58004000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x496,
+ .revs = stm32_496_revs,
+ .num_revs = ARRAY_SIZE(stm32_496_revs),
+ .device_str = "STM32WB3x",
+ .max_flash_size_kb = 512,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x58004000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+ {
+ .id = 0x497,
+ .revs = stm32_497_revs,
+ .num_revs = ARRAY_SIZE(stm32_497_revs),
+ .device_str = "STM32WLEx",
+ .max_flash_size_kb = 256,
+ .has_dual_bank = false,
+ .flash_regs_base = 0x58004000,
+ .fsize_addr = 0x1FFF75E0,
+ },
+};
+
+/* flash bank stm32l4x 0 0 */
FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
{
struct stm32l4_flash_bank *stm32l4_info;
@@ -144,32 +352,40 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
return ERROR_FAIL; /* Checkme: What better error to use?*/
bank->driver_priv = stm32l4_info;
- stm32l4_info->probed = 0;
+ /* The flash write must be aligned to a double word (8-bytes) boundary.
+ * Ask the flash infrastructure to ensure required alignment */
+ bank->write_start_alignment = bank->write_end_alignment = 8;
+
+ stm32l4_info->probed = false;
+ stm32l4_info->user_bank_size = bank->size;
return ERROR_OK;
}
-static inline int stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
{
- return reg;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ return stm32l4_info->part_info->flash_regs_base + reg_offset;
}
-static inline int stm32l4_get_flash_status(struct flash_bank *bank, uint32_t *status)
+static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
{
- struct target *target = bank->target;
- return target_read_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR), status);
+ return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value);
+}
+
+static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value);
}
static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
{
- struct target *target = bank->target;
uint32_t status;
int retval = ERROR_OK;
/* wait for busy to clear */
for (;;) {
- retval = stm32l4_get_flash_status(bank, &status);
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%" PRIx32 "", status);
@@ -195,20 +411,20 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* If this operation fails, we ignore it and report the original
* retval
*/
- target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR),
- status & FLASH_ERROR);
+ stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR);
}
+
return retval;
}
-static int stm32l4_unlock_reg(struct target *target)
+static int stm32l4_unlock_reg(struct flash_bank *bank)
{
uint32_t ctrl;
/* first check if not already unlocked
* otherwise writing on STM32_FLASH_KEYR will fail
*/
- int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -216,15 +432,15 @@ static int stm32l4_unlock_reg(struct target *target)
return ERROR_OK;
/* unlock flash registers */
- retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -236,11 +452,11 @@ static int stm32l4_unlock_reg(struct target *target)
return ERROR_OK;
}
-static int stm32l4_unlock_option_reg(struct target *target)
+static int stm32l4_unlock_option_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -248,15 +464,15 @@ static int stm32l4_unlock_option_reg(struct target *target)
return ERROR_OK;
/* unlock option registers */
- retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2);
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, STM32_FLASH_CR, &ctrl);
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -268,66 +484,72 @@ static int stm32l4_unlock_option_reg(struct target *target)
return ERROR_OK;
}
-static int stm32l4_read_option(struct flash_bank *bank, uint32_t address, uint32_t* value)
+static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
+ uint32_t value, uint32_t mask)
{
- struct target *target = bank->target;
- return target_read_u32(target, address, value);
-}
-
-static int stm32l4_write_option(struct flash_bank *bank, uint32_t address, uint32_t value, uint32_t mask)
-{
- struct target *target = bank->target;
uint32_t optiondata;
+ int retval, retval2;
- int retval = target_read_u32(target, address, &optiondata);
+ retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata);
if (retval != ERROR_OK)
return retval;
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
- retval = stm32l4_unlock_option_reg(target);
+ retval = stm32l4_unlock_option_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
optiondata = (optiondata & ~mask) | (value & mask);
- retval = target_write_u32(target, address, optiondata);
+ retval = stm32l4_write_flash_reg(bank, reg_offset, optiondata);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
- retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OPTSTRT);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK);
+
if (retval != ERROR_OK)
return retval;
- return retval;
+ return retval2;
}
static int stm32l4_protect_check(struct flash_bank *bank)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
- uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
- stm32l4_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar);
- stm32l4_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br);
- stm32l4_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar);
- stm32l4_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br);
- const uint8_t wrp1a_start = wrp1ar & 0xFF;
- const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF;
- const uint8_t wrp1b_start = wrp1br & 0xFF;
- const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF;
- const uint8_t wrp2a_start = wrp2ar & 0xFF;
- const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF;
- const uint8_t wrp2b_start = wrp2br & 0xFF;
- const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF;
+ uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar);
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br);
+ if (stm32l4_info->part_info->has_dual_bank) {
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar);
+ stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br);
+ } else {
+ /* prevent unintialized errors */
+ wrp2ar = 0;
+ wrp2br = 0;
+ }
+
+ const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask;
+ const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask;
for (int i = 0; i < bank->num_sectors; i++) {
- if (i < stm32l4_info->bank2_start) {
+ if (i < stm32l4_info->bank1_sectors) {
if (((i >= wrp1a_start) &&
(i <= wrp1a_end)) ||
((i >= wrp1b_start) &&
@@ -336,8 +558,9 @@ static int stm32l4_protect_check(struct flash_bank *bank)
else
bank->sectors[i].is_protected = 0;
} else {
+ assert(stm32l4_info->part_info->has_dual_bank == true);
uint8_t snb;
- snb = i - stm32l4_info->bank2_start;
+ snb = i - stm32l4_info->bank1_sectors;
if (((snb >= wrp2a_start) &&
(snb <= wrp2a_end)) ||
((snb >= wrp2b_start) &&
@@ -352,62 +575,60 @@ static int stm32l4_protect_check(struct flash_bank *bank)
static int stm32l4_erase(struct flash_bank *bank, int first, int last)
{
- struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
int i;
+ int retval, retval2;
- assert(first < bank->num_sectors);
- assert(last < bank->num_sectors);
+ assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- int retval;
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
/*
Sector Erase
To erase a sector, follow the procedure below:
1. Check that no Flash memory operation is ongoing by
- checking the BSY bit in the FLASH_SR register
+ checking the BSY bit in the FLASH_SR register
2. Set the PER bit and select the page and bank
you wish to erase in the FLASH_CR register
3. Set the STRT bit in the FLASH_CR register
4. Wait for the BSY bit to be cleared
*/
- struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
for (i = first; i <= last; i++) {
uint32_t erase_flags;
erase_flags = FLASH_PER | FLASH_STRT;
- if (i >= stm32l4_info->bank2_start) {
+ if (i >= stm32l4_info->bank1_sectors) {
uint8_t snb;
- snb = i - stm32l4_info->bank2_start;
+ snb = i - stm32l4_info->bank1_sectors;
erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
} else
erase_flags |= i << FLASH_PAGE_SHIFT;
- retval = target_write_u32(target,
- stm32l4_get_flash_reg(bank, STM32_FLASH_CR), erase_flags);
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags);
if (retval != ERROR_OK)
- return retval;
+ break;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK)
- return retval;
+ break;
bank->sectors[i].is_erased = 1;
}
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ return retval2;
}
static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last)
@@ -423,9 +644,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
int ret = ERROR_OK;
/* Bank 2 */
uint32_t reg_value = 0xFF; /* Default to bank un-protected */
- if (last >= stm32l4_info->bank2_start) {
+ if (last >= stm32l4_info->bank1_sectors) {
if (set == 1) {
- uint8_t begin = first > stm32l4_info->bank2_start ? first : 0x00;
+ uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00;
reg_value = ((last & 0xFF) << 16) | begin;
}
@@ -433,9 +654,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
}
/* Bank 1 */
reg_value = 0xFF; /* Default to bank un-protected */
- if (first < stm32l4_info->bank2_start) {
+ if (first < stm32l4_info->bank1_sectors) {
if (set == 1) {
- uint8_t end = last >= stm32l4_info->bank2_start ? 0xFF : last;
+ uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last;
reg_value = (end << 16) | (first & 0xFF);
}
@@ -445,16 +666,16 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
return ret;
}
-/* Count is in halfwords */
+/* Count is in double-words */
static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+ uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- uint32_t buffer_size = 16384;
+ uint32_t buffer_size;
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
- struct reg_param reg_params[5];
+ struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
@@ -476,18 +697,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
return retval;
}
- /* memory buffer */
- while (target_alloc_working_area_try(target, buffer_size, &source) !=
- ERROR_OK) {
- buffer_size /= 2;
- if (buffer_size <= 256) {
- /* we already allocated the writing code, but failed to get a
- * buffer, free the algorithm */
- target_free_working_area(target, write_algorithm);
+ /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */
+ buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1);
+ if (buffer_size < 256) {
+ LOG_WARNING("large enough working area not available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ } else if (buffer_size > 16384) {
+ /* probably won't benefit from more than 16k ... */
+ buffer_size = 16384;
+ }
- LOG_WARNING("large enough working area not available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ LOG_ERROR("allocating working area failed");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
@@ -497,17 +719,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */
init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (double word-64bit) */
- init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */
+ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */
+ init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[2].value, 0, 32, address);
- buf_set_u32(reg_params[3].value, 0, 32, count / 4);
- buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE);
+ buf_set_u32(reg_params[3].value, 0, 32, count);
+ buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR));
+ buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR));
- retval = target_run_flash_async_algorithm(target, buffer, count, 2,
+ retval = target_run_flash_async_algorithm(target, buffer, count, 8,
0, NULL,
- 5, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
@@ -523,7 +747,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
if (error != 0) {
LOG_ERROR("flash write failed = %08" PRIx32, error);
/* Clear but report errors */
- target_write_u32(target, STM32_FLASH_SR, error);
+ stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error);
retval = ERROR_FAIL;
}
}
@@ -536,195 +760,311 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
destroy_reg_param(®_params[2]);
destroy_reg_param(®_params[3]);
destroy_reg_param(®_params[4]);
+ destroy_reg_param(®_params[5]);
return retval;
}
static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+ uint32_t offset, uint32_t count)
{
- struct target *target = bank->target;
- int retval;
+ int retval = ERROR_OK, retval2;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (offset & 0x7) {
- LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment",
- offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ /* The flash write must be aligned to a double word (8-bytes) boundary.
+ * The flash infrastructure ensures it, do just a security check */
+ assert(offset % 8 == 0);
+ assert(count % 8 == 0);
+
+ /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether
+ * data to be written does not go into a gap:
+ * suppose buffer is fully contained in bank from sector 0 to sector
+ * num->sectors - 1 and sectors are ordered according to offset
+ */
+ struct flash_sector *head = &bank->sectors[0];
+ struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1];
+
+ while ((head < tail) && (offset >= (head + 1)->offset)) {
+ /* buffer does not intersect head nor gap behind head */
+ head++;
}
- if (count & 0x7) {
- LOG_WARNING("Padding %d bytes to keep 8-byte write size",
- count & 7);
- count = (count + 7) & ~7;
- /* This pads the write chunk with random bytes by overrunning the
- * write buffer. Padding with the erased pattern 0xff is purely
- * cosmetical, as 8-byte flash words are ECC secured and the first
- * write will program the ECC bits. A second write would need
- * to reprogramm these ECC bits.
- * But this can only be done after erase!
- */
+ while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) {
+ /* buffer does not intersect tail nor gap before tail */
+ --tail;
+ }
+
+ LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32,
+ offset, offset + count - 1, head->offset, tail->offset + tail->size - 1);
+
+ /* Now check that there is no gap from head to tail, this should work
+ * even for multiple or non-symmetric gaps
+ */
+ while (head < tail) {
+ if (head->offset + head->size != (head + 1)->offset) {
+ LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT,
+ bank->base + head->offset + head->size,
+ bank->base + (head + 1)->offset - 1);
+ retval = ERROR_FLASH_DST_OUT_OF_BANK;
+ }
+ head++;
}
- retval = stm32l4_unlock_reg(target);
if (retval != ERROR_OK)
return retval;
- /* Only full double words (8-byte) can be programmed*/
- retval = stm32l4_write_block(bank, buffer, offset, count / 2);
- if (retval != ERROR_OK) {
- LOG_WARNING("block write failed");
- return retval;
- }
+ retval = stm32l4_unlock_reg(bank);
+ if (retval != ERROR_OK)
+ goto err_lock;
- LOG_WARNING("block write succeeded");
- return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+ retval = stm32l4_write_block(bank, buffer, offset, count / 8);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("block write failed");
+ return retval;
+ }
+ return retval2;
+}
+
+static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
+{
+ int retval;
+
+ /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */
+ retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id);
+ if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) {
+ retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id);
+ if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) {
+ LOG_ERROR("can't get device id");
+ return (retval == ERROR_OK) ? ERROR_FAIL : retval;
+ }
+ }
+
+ return retval;
}
static int stm32l4_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
- int i;
- uint16_t flash_size_in_kb = 0xffff;
- uint16_t max_flash_size_in_kb;
+ const struct stm32l4_part_info *part_info;
+ uint16_t flash_size_kb = 0xffff;
uint32_t device_id;
uint32_t options;
- uint32_t base_address = 0x08000000;
- stm32l4_info->probed = 0;
+ stm32l4_info->probed = false;
- /* read stm32 device id register */
- int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id);
+ /* read stm32 device id registers */
+ int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode);
if (retval != ERROR_OK)
return retval;
- LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
- /* set max flash size depending on family */
- switch (device_id & 0xfff) {
- case 0x470:
- max_flash_size_in_kb = 2048;
- break;
- case 0x461:
- case 0x415:
- max_flash_size_in_kb = 1024;
- break;
- case 0x462:
- max_flash_size_in_kb = 512;
- break;
- case 0x435:
- max_flash_size_in_kb = 256;
- break;
- default:
- LOG_WARNING("Cannot identify target as an STM32L4 family device.");
+ device_id = stm32l4_info->idcode & 0xFFF;
+
+ for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) {
+ if (device_id == stm32l4_parts[n].id)
+ stm32l4_info->part_info = &stm32l4_parts[n];
+ }
+
+ if (!stm32l4_info->part_info) {
+ LOG_WARNING("Cannot identify target as an %s family device.", device_families);
return ERROR_FAIL;
}
- /* get flash size from target. */
- retval = target_read_u16(target, FLASH_SIZE_REG, &flash_size_in_kb);
-
- /* failed reading flash size or flash size invalid (early silicon),
- * default to max target family */
- if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
- LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash",
- max_flash_size_in_kb);
- flash_size_in_kb = max_flash_size_in_kb;
- }
-
- LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
-
- /* did we assign a flash size? */
- assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
-
- /* get options for DUAL BANK. */
- retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
+ part_info = stm32l4_info->part_info;
+ char device_info[1024];
+ retval = bank->driver->info(bank, device_info, sizeof(device_info));
if (retval != ERROR_OK)
return retval;
- int num_pages = 0;
- int page_size = 0;
+ LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info);
- switch (device_id & 0xfff) {
- case 0x470:
- /* L4R/S have 1M or 2M FLASH and dual/single bank mode.
- * Page size is 4K or 8K.*/
- if (flash_size_in_kb == 2048) {
- stm32l4_info->bank2_start = 256;
- if (options & OPT_DBANK_GE_2M) {
- page_size = 4096;
- num_pages = 512;
- } else {
- page_size = 8192;
- num_pages = 256;
- }
- break;
- }
- if (flash_size_in_kb == 1024) {
- stm32l4_info->bank2_start = 128;
- if (options & OPT_DBANK_LE_1M) {
- page_size = 4096;
- num_pages = 256;
- } else {
- page_size = 8192;
- num_pages = 128;
- }
- break;
- }
- /* Invalid FLASH size for this device. */
- LOG_WARNING("Invalid flash size for STM32L4+ family device.");
- return ERROR_FAIL;
- case 0x461:
- case 0x415:
- /* These are dual-bank devices, we need to check the OPT_DBANK_LE_1M bit here */
- page_size = 2048;
- num_pages = flash_size_in_kb / 2;
- /* check that calculation result makes sense */
- assert(num_pages > 0);
- if ((flash_size_in_kb == 1024) || !(options & OPT_DBANK_LE_1M))
- stm32l4_info->bank2_start = 256;
- else
- stm32l4_info->bank2_start = num_pages / 2;
- break;
- case 0x462:
- case 0x435:
- default:
- /* These are single-bank devices */
- page_size = 2048;
- num_pages = flash_size_in_kb / 2;
- /* check that calculation result makes sense */
- assert(num_pages > 0);
- stm32l4_info->bank2_start = UINT16_MAX;
- break;
+ /* get flash size from target. */
+ retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb);
+
+ /* failed reading flash size or flash size invalid (early silicon),
+ * default to max target family */
+ if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0
+ || flash_size_kb > part_info->max_flash_size_kb) {
+ LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash",
+ part_info->max_flash_size_kb);
+ flash_size_kb = part_info->max_flash_size_kb;
}
- /* Release sector table if allocated. */
+ /* if the user sets the size manually then ignore the probed value
+ * this allows us to work around devices that have a invalid flash size register value */
+ if (stm32l4_info->user_bank_size) {
+ LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE");
+ flash_size_kb = stm32l4_info->user_bank_size / 1024;
+ }
+
+ LOG_INFO("flash size = %dkbytes", flash_size_kb);
+
+ /* did we assign a flash size? */
+ assert((flash_size_kb != 0xffff) && flash_size_kb);
+
+ /* read flash option register */
+ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stm32l4_info->bank1_sectors = 0;
+ stm32l4_info->hole_sectors = 0;
+
+ int num_pages = 0;
+ int page_size_kb = 0;
+
+ stm32l4_info->dual_bank_mode = false;
+
+ switch (device_id) {
+ case 0x415: /* STM32L47/L48xx */
+ case 0x461: /* STM32L49/L4Axx */
+ /* if flash size is max (1M) the device is always dual bank
+ * 0x415: has variants with 512K
+ * 0x461: has variants with 512 and 256
+ * for these variants:
+ * if DUAL_BANK = 0 -> single bank
+ * else -> dual bank without gap
+ * note: the page size is invariant
+ */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+
+ /* check DUAL_BANK bit[21] if the flash is less than 1M */
+ if (flash_size_kb == 1024 || (options & BIT(21))) {
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case 0x435: /* STM32L43/L44xx */
+ case 0x460: /* STM32G07/G08xx */
+ case 0x462: /* STM32L45/L46xx */
+ case 0x464: /* STM32L41/L42xx */
+ case 0x466: /* STM32G03/G04xx */
+ case 0x468: /* STM32G43/G44xx */
+ case 0x497: /* STM32WLEx */
+ /* single bank flash */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
+ case 0x469: /* STM32G47/G48xx */
+ /* STM32G47/8 can be single/dual bank:
+ * if DUAL_BANK = 0 -> single bank
+ * else -> dual bank WITH gap
+ */
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ if (options & BIT(22)) {
+ stm32l4_info->dual_bank_mode = true;
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+
+ /* for devices with trimmed flash, there is a gap between both banks */
+ stm32l4_info->hole_sectors =
+ (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb);
+ }
+ break;
+ case 0x470: /* STM32L4R/L4Sxx */
+ case 0x471: /* STM32L4P5/L4Q5x */
+ /* STM32L4R/S can be single/dual bank:
+ * if size = 2M check DBANK bit(22)
+ * if size = 1M check DB1M bit(21)
+ * STM32L4P/Q can be single/dual bank
+ * if size = 1M check DBANK bit(22)
+ * if size = 512K check DB512K bit(21)
+ */
+ page_size_kb = 8;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
+ if ((use_dbank_bit && (options & BIT(22))) ||
+ (!use_dbank_bit && (options & BIT(21)))) {
+ stm32l4_info->dual_bank_mode = true;
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case 0x495: /* STM32WB5x */
+ case 0x496: /* STM32WB3x */
+ /* single bank flash */
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
+ default:
+ LOG_ERROR("unsupported device");
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single");
+
+ const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb;
+
+ if (gap_size_kb != 0) {
+ LOG_INFO("gap detected from 0x%08" PRIx32 " to 0x%08" PRIx32,
+ STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors
+ * page_size_kb * 1024,
+ STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors
+ * page_size_kb + gap_size_kb) * 1024 - 1);
+ }
+
+ /* number of significant bits in WRPxxR differs per device,
+ * always right adjusted, on some devices non-implemented
+ * bits read as '0', on others as '1' ...
+ * notably G4 Cat. 2 implement only 6 bits, contradicting the RM
+ */
+
+ /* use *max_flash_size* instead of actual size as the trimmed versions
+ * certainly use the same number of bits
+ * max_flash_size is always power of two, so max_pages too
+ */
+ uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb;
+ assert((max_pages & (max_pages - 1)) == 0);
+
+ /* in dual bank mode number of pages is doubled, but extra bit is bank selection */
+ stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1);
+ assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0);
+ LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask);
+
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
- /* Set bank configuration and construct sector table. */
- bank->base = base_address;
- bank->size = num_pages * page_size;
+ bank->size = (flash_size_kb + gap_size_kb) * 1024;
+ bank->base = STM32_FLASH_BANK_BASE;
bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
- if (!bank->sectors)
- return ERROR_FAIL; /* Checkme: What better error to use?*/
+ bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+ if (bank->sectors == NULL) {
+ LOG_ERROR("failed to allocate bank sectors");
+ return ERROR_FAIL;
+ }
- for (i = 0; i < num_pages; i++) {
- bank->sectors[i].offset = i * page_size;
- bank->sectors[i].size = page_size;
+ for (int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * page_size_kb * 1024;
+ /* in dual bank configuration, if there is a gap between banks
+ * we fix up the sector offset to consider this gap */
+ if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors)
+ bank->sectors[i].offset += gap_size_kb * 1024;
+ bank->sectors[i].size = page_size_kb * 1024;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
- stm32l4_info->probed = 1;
-
+ stm32l4_info->probed = true;
return ERROR_OK;
}
@@ -733,107 +1073,89 @@ static int stm32l4_auto_probe(struct flash_bank *bank)
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
if (stm32l4_info->probed)
return ERROR_OK;
+
return stm32l4_probe(bank);
}
static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
{
- struct target *target = bank->target;
- uint32_t dbgmcu_idcode;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ const struct stm32l4_part_info *part_info = stm32l4_info->part_info;
- /* read stm32 device id register */
- int retval = target_read_u32(target, DBGMCU_IDCODE, &dbgmcu_idcode);
- if (retval != ERROR_OK)
- return retval;
+ if (part_info) {
+ const char *rev_str = NULL;
+ uint16_t rev_id = stm32l4_info->idcode >> 16;
+ for (unsigned int i = 0; i < part_info->num_revs; i++) {
+ if (rev_id == part_info->revs[i].rev) {
+ rev_str = part_info->revs[i].str;
- uint16_t device_id = dbgmcu_idcode & 0xfff;
- uint8_t rev_id = dbgmcu_idcode >> 28;
- uint8_t rev_minor = 0;
- int i;
+ if (rev_str != NULL) {
+ snprintf(buf, buf_size, "%s - Rev: %s%s",
+ part_info->device_str, rev_str, stm32l4_info->probed ?
+ (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : "");
+ return ERROR_OK;
+ }
+ }
+ }
- for (i = 16; i < 28; i++) {
- if (dbgmcu_idcode & (1 << i))
- rev_minor++;
- else
- break;
- }
-
- const char *device_str;
-
- switch (device_id) {
- case 0x470:
- device_str = "STM32L4R/4Sxx";
- break;
-
- case 0x461:
- device_str = "STM32L496/4A6";
- break;
-
- case 0x415:
- device_str = "STM32L475/476/486";
- break;
-
- case 0x462:
- device_str = "STM32L45x/46x";
- break;
-
- case 0x435:
- device_str = "STM32L43x/44x";
- break;
-
- default:
- snprintf(buf, buf_size, "Cannot identify target as a STM32L4\n");
+ snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s",
+ part_info->device_str, rev_id, stm32l4_info->probed ?
+ (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : "");
+ return ERROR_OK;
+ } else {
+ snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families);
return ERROR_FAIL;
}
- snprintf(buf, buf_size, "%s - Rev: %1d.%02d",
- device_str, rev_id, rev_minor);
-
return ERROR_OK;
}
-static int stm32l4_mass_erase(struct flash_bank *bank, uint32_t action)
+static int stm32l4_mass_erase(struct flash_bank *bank)
{
- int retval;
+ int retval, retval2;
struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ uint32_t action = FLASH_MER1;
+
+ if (stm32l4_info->part_info->has_dual_bank)
+ action |= FLASH_MER2;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
/* mass erase flash memory */
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), action);
+ retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT / 10);
if (retval != ERROR_OK)
- return retval;
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR),
- action | FLASH_STRT);
+ goto err_lock;
+
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action);
+ if (retval != ERROR_OK)
+ goto err_lock;
+
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT);
+ if (retval != ERROR_OK)
+ goto err_lock;
+
+ retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
if (retval != ERROR_OK)
return retval;
- retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
- if (retval != ERROR_OK)
- return retval;
-
- retval = target_write_u32(
- target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return retval2;
}
COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
{
- int i;
- uint32_t action;
-
if (CMD_ARGC < 1) {
command_print(CMD, "stm32l4x mass_erase ");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -844,11 +1166,10 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
if (ERROR_OK != retval)
return retval;
- action = FLASH_MER1 | FLASH_MER2;
- retval = stm32l4_mass_erase(bank, action);
+ retval = stm32l4_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32l4x mass erase complete");
@@ -871,12 +1192,13 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command)
if (ERROR_OK != retval)
return retval;
- uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t reg_offset, reg_addr;
uint32_t value = 0;
- reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+ reg_offset = strtoul(CMD_ARGV[1], NULL, 16);
+ reg_addr = stm32l4_get_flash_reg(bank, reg_offset);
- retval = stm32l4_read_option(bank, reg_addr, &value);
+ retval = stm32l4_read_flash_reg(bank, reg_offset, &value);
if (ERROR_OK != retval)
return retval;
@@ -897,11 +1219,11 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
if (ERROR_OK != retval)
return retval;
- uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t reg_offset;
uint32_t value = 0;
uint32_t mask = 0xFFFFFFFF;
- reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+ reg_offset = strtoul(CMD_ARGV[1], NULL, 16);
value = strtoul(CMD_ARGV[2], NULL, 16);
if (CMD_ARGC > 3)
mask = strtoul(CMD_ARGV[3], NULL, 16);
@@ -910,13 +1232,13 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
"INFO: a reset or power cycle is required "
"for the new settings to take effect.", bank->driver->name);
- retval = stm32l4_write_option(bank, reg_addr, value, mask);
+ retval = stm32l4_write_option(bank, reg_offset, value, mask);
return retval;
}
COMMAND_HANDLER(stm32l4_handle_option_load_command)
{
- if (CMD_ARGC < 1)
+ if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
@@ -924,20 +1246,27 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command)
if (ERROR_OK != retval)
return retval;
- struct target *target = bank->target;
-
- retval = stm32l4_unlock_reg(target);
+ retval = stm32l4_unlock_reg(bank);
if (ERROR_OK != retval)
return retval;
- retval = stm32l4_unlock_option_reg(target);
+ retval = stm32l4_unlock_option_reg(bank);
if (ERROR_OK != retval)
return retval;
- /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */
- retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH);
+ /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload,
+ * but the RMs explicitly do *NOT* list this as power-on reset cause, and:
+ * "Note: If the read protection is set while the debugger is still
+ * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset."
+ */
+ retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH);
+
+ command_print(CMD, "stm32l4x option load completed. Power-on reset might be required");
+
+ /* Need to re-probe after change */
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ stm32l4_info->probed = false;
- command_print(CMD, "stm32l4x option load (POR) completed.");
return retval;
}
diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h
new file mode 100644
index 000000000..abd8010fc
--- /dev/null
+++ b/src/flash/nor/stm32l4x.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Uwe Bonnes *
+ * bon@elektron.ikp.physik.tu-darmstadt.de *
+ *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_STM32L4X
+#define OPENOCD_FLASH_NOR_STM32L4X
+
+/* Flash registers offsets */
+#define STM32_FLASH_ACR 0x00
+#define STM32_FLASH_KEYR 0x08
+#define STM32_FLASH_OPTKEYR 0x0c
+#define STM32_FLASH_SR 0x10
+#define STM32_FLASH_CR 0x14
+#define STM32_FLASH_OPTR 0x20
+#define STM32_FLASH_WRP1AR 0x2c
+#define STM32_FLASH_WRP1BR 0x30
+#define STM32_FLASH_WRP2AR 0x4c
+#define STM32_FLASH_WRP2BR 0x50
+
+/* FLASH_CR register bits */
+#define FLASH_PG (1 << 0)
+#define FLASH_PER (1 << 1)
+#define FLASH_MER1 (1 << 2)
+#define FLASH_PAGE_SHIFT 3
+#define FLASH_CR_BKER (1 << 11)
+#define FLASH_MER2 (1 << 15)
+#define FLASH_STRT (1 << 16)
+#define FLASH_OPTSTRT (1 << 17)
+#define FLASH_EOPIE (1 << 24)
+#define FLASH_ERRIE (1 << 25)
+#define FLASH_OBL_LAUNCH (1 << 27)
+#define FLASH_OPTLOCK (1 << 30)
+#define FLASH_LOCK (1 << 31)
+
+/* FLASH_SR register bits */
+#define FLASH_BSY (1 << 16)
+
+/* Fast programming not used => related errors not used*/
+#define FLASH_PGSERR (1 << 7) /* Programming sequence error */
+#define FLASH_SIZERR (1 << 6) /* Size error */
+#define FLASH_PGAERR (1 << 5) /* Programming alignment error */
+#define FLASH_WRPERR (1 << 4) /* Write protection error */
+#define FLASH_PROGERR (1 << 3) /* Programming error */
+#define FLASH_OPERR (1 << 1) /* Operation error */
+#define FLASH_EOP (1 << 0) /* End of operation */
+#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \
+ FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR)
+
+/* register unlock keys */
+#define KEY1 0x45670123
+#define KEY2 0xCDEF89AB
+
+/* option register unlock key */
+#define OPTKEY1 0x08192A3B
+#define OPTKEY2 0x4C5D6E7F
+
+#define RDP_LEVEL_0 0xAA
+#define RDP_LEVEL_1 0xBB
+#define RDP_LEVEL_2 0xCC
+
+/* other registers */
+#define DBGMCU_IDCODE_G0 0x40015800
+#define DBGMCU_IDCODE_L4_G4 0xE0042000
+#define DBGMCU_IDCODE_L5 0xE0044000
+
+#define STM32_FLASH_BANK_BASE 0x08000000
+
+#endif
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index e6473f8c2..c3f9c7249 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -128,7 +128,7 @@ struct stm32lx_part_info {
};
struct stm32lx_flash_bank {
- int probed;
+ bool probed;
uint32_t idcode;
uint32_t user_bank_size;
uint32_t flash_base;
@@ -297,7 +297,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
bank->driver_priv = stm32lx_info;
- stm32lx_info->probed = 0;
+ stm32lx_info->probed = false;
stm32lx_info->user_bank_size = bank->size;
/* the stm32l erased value is 0x00 */
@@ -308,8 +308,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -321,7 +319,7 @@ COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
retval = stm32lx_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
+ for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "stm32lx mass erase complete");
@@ -731,14 +729,13 @@ static int stm32lx_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- int i;
uint16_t flash_size_in_kb;
uint32_t device_id;
uint32_t base_address = FLASH_BANK0_ADDRESS;
uint32_t second_bank_base;
unsigned int n;
- stm32lx_info->probed = 0;
+ stm32lx_info->probed = false;
int retval = stm32lx_read_id_code(bank->target, &device_id);
if (retval != ERROR_OK)
@@ -756,7 +753,7 @@ static int stm32lx_probe(struct flash_bank *bank)
}
if (n == ARRAY_SIZE(stm32lx_parts)) {
- LOG_WARNING("Cannot identify target as a STM32L family.");
+ LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device.");
return ERROR_FAIL;
} else {
LOG_INFO("Device: %s", stm32lx_info->part_info.device_str);
@@ -852,14 +849,14 @@ static int stm32lx_probe(struct flash_bank *bank)
return ERROR_FAIL;
}
- for (i = 0; i < num_sectors; i++) {
+ for (int i = 0; i < num_sectors; i++) {
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
bank->sectors[i].size = FLASH_SECTOR_SIZE;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
- stm32lx_info->probed = 1;
+ stm32lx_info->probed = true;
return ERROR_OK;
}
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index bd313a0b5..fb2053b89 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -109,7 +109,7 @@ COMMAND_HANDLER(handle_flash_info_command)
return retval;
}
if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
- LOG_WARNING("Flash protection check is not implemented.");
+ LOG_INFO("Flash protection check is not implemented.");
command_print(CMD,
"#%d : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32
@@ -476,7 +476,7 @@ COMMAND_HANDLER(handle_flash_write_image_command)
COMMAND_HANDLER(handle_flash_fill_command)
{
target_addr_t address;
- uint32_t pattern;
+ uint64_t pattern;
uint32_t count;
struct target *target = get_current_target(CMD_CTX);
unsigned i;
@@ -487,7 +487,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern);
+ COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
struct flash_bank *bank;
@@ -496,6 +496,9 @@ COMMAND_HANDLER(handle_flash_fill_command)
return retval;
switch (CMD_NAME[4]) {
+ case 'd':
+ wordsize = 8;
+ break;
case 'w':
wordsize = 4;
break;
@@ -509,6 +512,11 @@ COMMAND_HANDLER(handle_flash_fill_command)
return ERROR_COMMAND_SYNTAX_ERROR;
}
+ if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) {
+ command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize);
+ return ERROR_FAIL;
+ }
+
if (count == 0)
return ERROR_OK;
@@ -541,6 +549,10 @@ COMMAND_HANDLER(handle_flash_fill_command)
uint8_t *ptr = buffer + padding_at_start;
switch (wordsize) {
+ case 8:
+ for (i = 0; i < count; i++, ptr += wordsize)
+ target_buffer_set_u64(target, ptr, pattern);
+ break;
case 4:
for (i = 0; i < count; i++, ptr += wordsize)
target_buffer_set_u32(target, ptr, pattern);
@@ -577,9 +589,12 @@ COMMAND_HANDLER(handle_flash_fill_command)
goto done;
for (i = 0, ptr = buffer; i < count; i++) {
- uint32_t readback = 0;
+ uint64_t readback = 0;
switch (wordsize) {
+ case 8:
+ readback = target_buffer_get_u64(target, ptr);
+ break;
case 4:
readback = target_buffer_get_u32(target, ptr);
break;
@@ -593,7 +608,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
if (readback != pattern) {
LOG_ERROR(
"Verification error address " TARGET_ADDR_FMT
- ", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32,
+ ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64,
address + i * wordsize, readback, pattern);
retval = ERROR_FAIL;
goto done;
@@ -613,6 +628,67 @@ done:
return retval;
}
+COMMAND_HANDLER(handle_flash_md_command)
+{
+ int retval;
+
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ target_addr_t address;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
+
+ uint32_t count = 1;
+ if (CMD_ARGC == 2)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count);
+
+ unsigned int wordsize;
+ switch (CMD_NAME[2]) {
+ case 'w':
+ wordsize = 4;
+ break;
+ case 'h':
+ wordsize = 2;
+ break;
+ case 'b':
+ wordsize = 1;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (count == 0)
+ return ERROR_OK;
+
+ struct target *target = get_current_target(CMD_CTX);
+ struct flash_bank *bank;
+ retval = get_flash_bank_by_addr(target, address, true, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t offset = address - bank->base;
+ uint32_t sizebytes = count * wordsize;
+ if (offset + sizebytes > bank->size) {
+ command_print(CMD, "Cannot cross flash bank borders");
+ return ERROR_FAIL;
+ }
+
+ uint8_t *buffer = calloc(count, wordsize);
+ if (buffer == NULL) {
+ command_print(CMD, "No memory for flash read buffer");
+ return ERROR_FAIL;
+ }
+
+ retval = flash_driver_read(bank, buffer, offset, sizebytes);
+ if (retval == ERROR_OK)
+ target_handle_md_output(CMD, target, address, wordsize, count, buffer);
+
+ free(buffer);
+
+ return retval;
+}
+
+
COMMAND_HANDLER(handle_flash_write_bank_command)
{
uint32_t offset;
@@ -952,7 +1028,7 @@ COMMAND_HANDLER(handle_flash_padded_value_command)
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value);
- command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", \
+ command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u",
p->default_padded_value, p->bank_number);
return retval;
@@ -1002,6 +1078,14 @@ static const struct command_registration flash_exec_command_handlers[] = {
"before erasing.",
},
+ {
+ .name = "filld",
+ .handler = handle_flash_fill_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address value n",
+ .help = "Fill n double-words with 64-bit value, starting at "
+ "word address. (No autoerase.)",
+ },
{
.name = "fillw",
.handler = handle_flash_fill_command,
@@ -1026,6 +1110,27 @@ static const struct command_registration flash_exec_command_handlers[] = {
.help = "Fill n bytes with 8-bit value, starting at "
"word address. (No autoerase.)",
},
+ {
+ .name = "mdb",
+ .handler = handle_flash_md_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address [count]",
+ .help = "Display bytes from flash.",
+ },
+ {
+ .name = "mdh",
+ .handler = handle_flash_md_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address [count]",
+ .help = "Display half-words from flash.",
+ },
+ {
+ .name = "mdw",
+ .handler = handle_flash_md_command,
+ .mode = COMMAND_EXEC,
+ .usage = "address [count]",
+ .help = "Display words from flash.",
+ },
{
.name = "write_bank",
.handler = handle_flash_write_bank_command,
diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c
index 90557b8f1..bc16acab5 100644
--- a/src/flash/nor/tms470.c
+++ b/src/flash/nor/tms470.c
@@ -709,6 +709,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector)
* Select one or more bits in FMBSEA or FMBSEB to disable Level 1
* protection for the particular sector to be erased/written.
*/
+ assert(sector >= 0);
if (sector < 16) {
target_read_u32(target, 0xFFE88008, &fmbsea);
target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector));
diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c
index a0c35c5e5..ba35c2c10 100644
--- a/src/flash/nor/xcf.c
+++ b/src/flash/nor/xcf.c
@@ -625,7 +625,6 @@ static int xcf_probe(struct flash_bank *bank)
default:
LOG_ERROR("Unknown flash device ID 0x%X", id);
return ERROR_FAIL;
- break;
}
bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl
index ff053ae1b..aafb939cd 100644
--- a/src/flash/startup.tcl
+++ b/src/flash/startup.tcl
@@ -17,9 +17,12 @@ proc program_error {description exit} {
proc program {filename args} {
set exit 0
+ set needsflash 1
foreach arg $args {
- if {[string equal $arg "verify"]} {
+ if {[string equal $arg "preverify"]} {
+ set preverify 1
+ } elseif {[string equal $arg "verify"]} {
set verify 1
} elseif {[string equal $arg "reset"]} {
set reset 1
@@ -30,6 +33,15 @@ proc program {filename args} {
}
}
+ # Set variables
+ set filename \{$filename\}
+ if {[info exists address]} {
+ set flash_args "$filename $address"
+ } else {
+ set flash_args "$filename"
+ }
+
+
# make sure init is called
if {[catch {init}] != 0} {
program_error "** OpenOCD init failed **" 1
@@ -40,40 +52,46 @@ proc program {filename args} {
program_error "** Unable to reset target **" $exit
}
+ # Check whether programming is needed
+ if {[info exists preverify]} {
+ echo "**pre-verifying**"
+ if {[catch {eval verify_image $flash_args}] == 0} {
+ echo "**Verified OK - No flashing**"
+ set needsflash 0
+ }
+ }
+
# start programming phase
- echo "** Programming Started **"
- set filename \{$filename\}
- if {[info exists address]} {
- set flash_args "$filename $address"
- } else {
- set flash_args "$filename"
+ if {$needsflash == 1} {
+ echo "** Programming Started **"
+
+ if {[catch {eval flash write_image erase $flash_args}] == 0} {
+ echo "** Programming Finished **"
+ if {[info exists verify]} {
+ # verify phase
+ echo "** Verify Started **"
+ if {[catch {eval verify_image $flash_args}] == 0} {
+ echo "** Verified OK **"
+ } else {
+ program_error "** Verify Failed **" $exit
+ }
+ }
+ } else {
+ program_error "** Programming Failed **" $exit
+ }
}
- if {[catch {eval flash write_image erase $flash_args}] == 0} {
- echo "** Programming Finished **"
- if {[info exists verify]} {
- # verify phase
- echo "** Verify Started **"
- if {[catch {eval verify_image $flash_args}] == 0} {
- echo "** Verified OK **"
- } else {
- program_error "** Verify Failed **" $exit
- }
+ if {[info exists reset]} {
+ # reset target if requested
+ if {$exit == 1} {
+ # also disable target polling, we are shutting down anyway
+ poll off
}
-
- if {[info exists reset]} {
- # reset target if requested
- if {$exit == 1} {
- # also disable target polling, we are shutting down anyway
- poll off
- }
- echo "** Resetting Target **"
- reset run
- }
- } else {
- program_error "** Programming Failed **" $exit
+ echo "** Resetting Target **"
+ reset run
}
+
if {$exit == 1} {
shutdown
}
@@ -81,25 +99,25 @@ proc program {filename args} {
}
add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional"
-add_usage_text program " \[address\] \[verify\] \[reset\] \[exit\]"
+add_usage_text program " \[address\] \[pre-verify\] \[verify\] \[reset\] \[exit\]"
-# stm32f0x uses the same flash driver as the stm32f1x
-# this alias enables the use of either name.
-proc stm32f0x args {
- eval stm32f1x $args
-}
+# stm32[f0x|f3x] uses the same flash driver as the stm32f1x
+proc stm32f0x args { eval stm32f1x $args }
+proc stm32f3x args { eval stm32f1x $args }
-# stm32f3x uses the same flash driver as the stm32f1x
-# this alias enables the use of either name.
-proc stm32f3x args {
- eval stm32f1x $args
-}
+# stm32[f4x|f7x] uses the same flash driver as the stm32f2x
+proc stm32f4x args { eval stm32f2x $args }
+proc stm32f7x args { eval stm32f2x $args }
-# stm32f4x uses the same flash driver as the stm32f2x
-# this alias enables the use of either name.
-proc stm32f4x args {
- eval stm32f2x $args
-}
+# stm32lx driver supports both STM32 L0 and L1 devices
+proc stm32l0x args { eval stm32lx $args }
+proc stm32l1x args { eval stm32lx $args }
+
+# stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x
+proc stm32g0x args { eval stm32l4x $args }
+proc stm32g4x args { eval stm32l4x $args }
+proc stm32wbx args { eval stm32l4x $args }
+proc stm32wlx args { eval stm32l4x $args }
# ease migration to updated flash driver
proc stm32x args {
diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h
index 7ac221e47..3f2481d9a 100644
--- a/src/helper/binarybuffer.h
+++ b/src/helper/binarybuffer.h
@@ -33,6 +33,7 @@
* using the bits in @c value. This routine fast-paths writes
* of little-endian, byte-aligned, 32-bit words.
* @param _buffer The buffer whose bits will be set.
+ * Do not use uninitialized buffer or clang static analyzer emits a warning.
* @param first The bit offset in @c _buffer to start writing (0-31).
* @param num The number of bits from @c value to copy (1-32).
* @param value Up to 32 bits that will be copied to _buffer.
@@ -62,6 +63,7 @@ static inline void buf_set_u32(uint8_t *_buffer,
* using the bits in @c value. This routine fast-paths writes
* of little-endian, byte-aligned, 64-bit words.
* @param _buffer The buffer whose bits will be set.
+ * Do not use uninitialized buffer or clang static analyzer emits a warning.
* @param first The bit offset in @c _buffer to start writing (0-63).
* @param num The number of bits from @c value to copy (1-64).
* @param value Up to 64 bits that will be copied to _buffer.
diff --git a/src/helper/command.c b/src/helper/command.c
index d969933e2..271e7b993 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -52,6 +52,10 @@ struct log_capture_state {
Jim_Obj *output;
};
+static int unregister_command(struct command_context *context,
+ struct command *parent, const char *name);
+static char *command_name(struct command *c, char delim);
+
static void tcl_output(void *privData, const char *file, unsigned line,
const char *function, const char *string)
{
@@ -126,13 +130,12 @@ extern struct command_context *global_cmd_ctx;
/* dump a single line to the log for the command.
* Do nothing in case we are not at debug level 3 */
-void script_debug(Jim_Interp *interp, const char *name,
- unsigned argc, Jim_Obj * const *argv)
+void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv)
{
if (debug_level < LOG_LVL_DEBUG)
return;
- char *dbg = alloc_printf("command - %s", name);
+ char *dbg = alloc_printf("command -");
for (unsigned i = 0; i < argc; i++) {
int len;
const char *w = Jim_GetString(argv[i], &len);
@@ -213,7 +216,7 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
struct command *c = interp->cmdPrivData;
assert(c);
- script_debug(interp, c->name, argc, argv);
+ script_debug(interp, argc, argv);
return script_command_run(interp, argc, argv, c);
}
@@ -243,11 +246,6 @@ struct command *command_find_in_context(struct command_context *cmd_ctx,
{
return command_find(cmd_ctx->commands, name);
}
-struct command *command_find_in_parent(struct command *parent,
- const char *name)
-{
- return command_find(parent->children, name);
-}
/**
* Add the command into the linked list, sorted by name.
@@ -333,7 +331,6 @@ static struct command *command_new(struct command_context *cmd_ctx,
c->parent = parent;
c->handler = cr->handler;
c->jim_handler = cr->jim_handler;
- c->jim_handler_data = cr->jim_handler_data;
c->mode = cr->mode;
command_add_child(command_list_for_parent(cmd_ctx, parent), c);
@@ -360,7 +357,7 @@ static int register_command_handler(struct command_context *cmd_ctx,
return retval;
}
-struct command *register_command(struct command_context *context,
+static struct command *register_command(struct command_context *context,
struct command *parent, const struct command_registration *cr)
{
if (!context || !cr->name)
@@ -382,14 +379,14 @@ struct command *register_command(struct command_context *context,
if (NULL == c)
return NULL;
- int retval = ERROR_OK;
+ int retval = JIM_OK;
if (NULL != cr->jim_handler && NULL == parent) {
retval = Jim_CreateCommand(context->interp, cr->name,
- cr->jim_handler, cr->jim_handler_data, NULL);
+ cr->jim_handler, NULL, NULL);
} else if (NULL != cr->handler || NULL != parent)
retval = register_command_handler(context, command_root(c));
- if (ERROR_OK != retval) {
+ if (retval != JIM_OK) {
unregister_command(context, parent, name);
c = NULL;
}
@@ -442,7 +439,7 @@ int unregister_all_commands(struct command_context *context,
return ERROR_OK;
}
-int unregister_command(struct command_context *context,
+static int unregister_command(struct command_context *context,
struct command *parent, const char *name)
{
if ((!context) || (!name))
@@ -550,7 +547,7 @@ static char *__command_name(struct command *c, char delim, unsigned extra)
return name;
}
-char *command_name(struct command *c, char delim)
+static char *command_name(struct command *c, char delim)
{
return __command_name(c, delim, 0);
}
@@ -1033,8 +1030,7 @@ static int run_usage(Jim_Interp *interp, int argc_valid, int argc, Jim_Obj * con
static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- const char *cmd_name = Jim_GetString(argv[0], NULL);
- script_debug(interp, cmd_name, argc, argv);
+ script_debug(interp, argc, argv);
struct command_context *cmd_ctx = current_command_context(interp);
struct command *c = cmd_ctx->commands;
@@ -1220,9 +1216,9 @@ static const struct command_registration command_subcommand_handlers[] = {
.mode = COMMAND_ANY,
.jim_handler = jim_command_mode,
.usage = "[command_name ...]",
- .help = "Returns the command modes allowed by a command:"
- "'any', 'config', or 'exec'. If no command is"
- "specified, returns the current command mode. "
+ .help = "Returns the command modes allowed by a command: "
+ "'any', 'config', or 'exec'. If no command is "
+ "specified, returns the current command mode. "
"Returns 'unknown' if an unknown command is given. "
"Command can be multiple tokens.",
},
@@ -1230,6 +1226,21 @@ static const struct command_registration command_subcommand_handlers[] = {
};
static const struct command_registration command_builtin_handlers[] = {
+ {
+ .name = "ocd_find",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_find,
+ .help = "find full path to file",
+ .usage = "file",
+ },
+ {
+ .name = "capture",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_capture,
+ .help = "Capture progress output and return as tcl return value. If the "
+ "progress output was empty, return tcl return value.",
+ .usage = "command",
+ },
{
.name = "echo",
.handler = jim_echo,
@@ -1340,9 +1351,6 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp
Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
Jim_NewStringObj(interp, HostOs, strlen(HostOs)));
- Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
- Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
-
register_commands(context, NULL, command_builtin_handlers);
Jim_SetAssocData(interp, "context", NULL, context);
diff --git a/src/helper/command.h b/src/helper/command.h
index 733ba42dd..886bde86b 100644
--- a/src/helper/command.h
+++ b/src/helper/command.h
@@ -195,19 +195,9 @@ struct command {
struct command *next;
};
-/**
- * @param c The command to be named.
- * @param delim The character to place between command names.
- * @returns A malloc'd string containing the full command name,
- * which may include one or more ancestor components. Multiple names
- * are separated by single spaces. The caller must free() the string
- * when done with it.
- */
-char *command_name(struct command *c, char delim);
-
/*
* Commands should be registered by filling in one or more of these
- * structures and passing them to register_command().
+ * structures and passing them to [un]register_commands().
*
* A conventioal format should be used for help strings, to provide both
* usage and basic information:
@@ -226,7 +216,6 @@ struct command_registration {
const char *name;
command_handler_t handler;
Jim_CmdProc *jim_handler;
- void *jim_handler_data;
enum command_mode mode;
const char *help;
/** a string listing the options and arguments, required or optional */
@@ -244,24 +233,6 @@ struct command_registration {
/** Use this as the last entry in an array of command_registration records. */
#define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL }
-/**
- * Register a command @c handler that can be called from scripts during
- * the execution @c mode specified.
- *
- * If @c parent is non-NULL, the new command will be registered as a
- * sub-command under it; otherwise, it will be available as a top-level
- * command.
- *
- * @param cmd_ctx The command_context in which to register the command.
- * @param parent Register this command as a child of this, or NULL to
- * register a top-level command.
- * @param rec A command_registration record that contains the desired
- * command parameters.
- * @returns The new command, if successful; otherwise, NULL.
- */
-struct command *register_command(struct command_context *cmd_ctx,
- struct command *parent, const struct command_registration *rec);
-
/**
* Register one or more commands in the specified context, as children
* of @c parent (or top-level commends, if NULL). In a registration's
@@ -280,16 +251,6 @@ struct command *register_command(struct command_context *cmd_ctx,
int register_commands(struct command_context *cmd_ctx, struct command *parent,
const struct command_registration *cmds);
-
-/**
- * Unregisters command @c name from the given context, @c cmd_ctx.
- * @param cmd_ctx The context of the registered command.
- * @param parent The parent of the given command, or NULL.
- * @param name The name of the command to unregister.
- * @returns ERROR_OK on success, or an error code.
- */
-int unregister_command(struct command_context *cmd_ctx,
- struct command *parent, const char *name);
/**
* Unregisters all commands from the specfied context.
* @param cmd_ctx The context that will be cleared of registered commands.
@@ -301,8 +262,6 @@ int unregister_all_commands(struct command_context *cmd_ctx,
struct command *command_find_in_context(struct command_context *cmd_ctx,
const char *name);
-struct command *command_find_in_parent(struct command *parent,
- const char *name);
/**
* Update the private command data field for a command and all descendents.
@@ -449,7 +408,6 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label);
#define COMMAND_PARSE_ENABLE(in, out) \
COMMAND_PARSE_BOOL(in, out, "enable", "disable")
-void script_debug(Jim_Interp *interp, const char *cmd,
- unsigned argc, Jim_Obj * const *argv);
+void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv);
#endif /* OPENOCD_HELPER_COMMAND_H */
diff --git a/src/helper/ioutil.c b/src/helper/ioutil.c
index d4f39e242..c103ce173 100644
--- a/src/helper/ioutil.c
+++ b/src/helper/ioutil.c
@@ -403,7 +403,7 @@ static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc,
{
if (strcmp("eth0", ifr->ifr_name) != 0)
continue;
- strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
close(SockFD);
return JIM_ERR;
diff --git a/src/helper/log.c b/src/helper/log.c
index d65430c50..31122554e 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -220,6 +220,15 @@ COMMAND_HANDLER(handle_debug_level_command)
COMMAND_HANDLER(handle_log_output_command)
{
+ if (CMD_ARGC == 0 || (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") == 0)) {
+ if (log_output != stderr && log_output != NULL) {
+ /* Close previous log file, if it was open and wasn't stderr. */
+ fclose(log_output);
+ }
+ log_output = stderr;
+ LOG_DEBUG("set log_output to default");
+ return ERROR_OK;
+ }
if (CMD_ARGC == 1) {
FILE *file = fopen(CMD_ARGV[0], "w");
if (file == NULL) {
@@ -231,9 +240,11 @@ COMMAND_HANDLER(handle_log_output_command)
fclose(log_output);
}
log_output = file;
+ LOG_DEBUG("set log_output to \"%s\"", CMD_ARGV[0]);
+ return ERROR_OK;
}
- return ERROR_OK;
+ return ERROR_COMMAND_SYNTAX_ERROR;
}
static const struct command_registration log_command_handlers[] = {
@@ -242,7 +253,7 @@ static const struct command_registration log_command_handlers[] = {
.handler = handle_log_output_command,
.mode = COMMAND_ANY,
.help = "redirect logging to a file (default: stderr)",
- .usage = "file_name",
+ .usage = "[file_name | \"default\"]",
},
{
.name = "debug_level",
@@ -390,25 +401,43 @@ char *alloc_printf(const char *format, ...)
* fast when invoked more often than every 500ms.
*
*/
-void keep_alive()
+#define KEEP_ALIVE_KICK_TIME_MS 500
+#define KEEP_ALIVE_TIMEOUT_MS 1000
+
+static void gdb_timeout_warning(int64_t delta_time)
+{
+ extern int gdb_actual_connections;
+
+ if (gdb_actual_connections)
+ LOG_WARNING("keep_alive() was not invoked in the "
+ "%d ms timelimit. GDB alive packet not "
+ "sent! (%" PRId64 " ms). Workaround: increase "
+ "\"set remotetimeout\" in GDB",
+ KEEP_ALIVE_TIMEOUT_MS,
+ delta_time);
+ else
+ LOG_DEBUG("keep_alive() was not invoked in the "
+ "%d ms timelimit (%" PRId64 " ms). This may cause "
+ "trouble with GDB connections.",
+ KEEP_ALIVE_TIMEOUT_MS,
+ delta_time);
+}
+
+void keep_alive(void)
{
current_time = timeval_ms();
- if (current_time-last_time > 1000) {
- extern int gdb_actual_connections;
- if (gdb_actual_connections)
- LOG_WARNING("keep_alive() was not invoked in the "
- "1000ms timelimit. GDB alive packet not "
- "sent! (%" PRId64 "). Workaround: increase "
- "\"set remotetimeout\" in GDB",
- current_time-last_time);
- else
- LOG_DEBUG("keep_alive() was not invoked in the "
- "1000ms timelimit (%" PRId64 "). This may cause "
- "trouble with GDB connections.",
- current_time-last_time);
+ int64_t delta_time = current_time - last_time;
+
+ if (delta_time > KEEP_ALIVE_TIMEOUT_MS) {
+ last_time = current_time;
+
+ gdb_timeout_warning(delta_time);
}
- if (current_time-last_time > 500) {
+
+ if (delta_time > KEEP_ALIVE_KICK_TIME_MS) {
+ last_time = current_time;
+
/* this will keep the GDB connection alive */
LOG_USER_N("%s", "");
@@ -419,16 +448,20 @@ void keep_alive()
*
* These functions should be invoked at a well defined spot in server.c
*/
-
- last_time = current_time;
}
}
/* reset keep alive timer without sending message */
-void kept_alive()
+void kept_alive(void)
{
current_time = timeval_ms();
+
+ int64_t delta_time = current_time - last_time;
+
last_time = current_time;
+
+ if (delta_time > KEEP_ALIVE_TIMEOUT_MS)
+ gdb_timeout_warning(delta_time);
}
/* if we sleep for extended periods of time, we must invoke keep_alive() intermittantly */
@@ -454,3 +487,28 @@ void busy_sleep(uint64_t ms)
*/
}
}
+
+/* Maximum size of socket error message retreived from operation system */
+#define MAX_SOCKET_ERR_MSG_LENGTH 256
+
+/* Provide log message for the last socket error.
+ Uses errno on *nix and WSAGetLastError() on Windows */
+void log_socket_error(const char *socket_desc)
+{
+ int error_code;
+#ifdef _WIN32
+ error_code = WSAGetLastError();
+ char error_message[MAX_SOCKET_ERR_MSG_LENGTH];
+ error_message[0] = '\0';
+ DWORD retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0,
+ error_message, MAX_SOCKET_ERR_MSG_LENGTH, NULL);
+ error_message[MAX_SOCKET_ERR_MSG_LENGTH - 1] = '\0';
+ const bool have_message = (retval != 0) && (error_message[0] != '\0');
+ LOG_ERROR("Error on socket '%s': WSAGetLastError==%d%s%s.", socket_desc, error_code,
+ (have_message ? ", message: " : ""),
+ (have_message ? error_message : ""));
+#else
+ error_code = errno;
+ LOG_ERROR("Error on socket '%s': errno==%d, message: %s.", socket_desc, error_code, strerror(error_code));
+#endif
+}
diff --git a/src/helper/log.h b/src/helper/log.h
index 43f67512c..c16543281 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -82,6 +82,8 @@ void kept_alive(void);
void alive_sleep(uint64_t ms);
void busy_sleep(uint64_t ms);
+void log_socket_error(const char *socket_desc);
+
typedef void (*log_callback_fn)(void *priv, const char *file, unsigned line,
const char *function, const char *string);
@@ -95,7 +97,8 @@ 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_printf(const char *fmt, ...);
+char *alloc_printf(const char *fmt, ...)
+ __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2)));
extern int debug_level;
diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl
index 691e3824f..71f489dd5 100644
--- a/src/helper/startup.tcl
+++ b/src/helper/startup.tcl
@@ -29,4 +29,3 @@ add_help_text script "filename of OpenOCD script (tcl) to run"
add_usage_text script ""
#########
-
diff --git a/src/helper/types.h b/src/helper/types.h
index 5e35c13b7..f3d5e04a3 100644
--- a/src/helper/types.h
+++ b/src/helper/types.h
@@ -126,17 +126,17 @@ static inline uint64_t le_to_h_u64(const uint8_t *buf)
(uint64_t)buf[7] << 56);
}
-static inline uint32_t le_to_h_u32(const uint8_t* buf)
+static inline uint32_t le_to_h_u32(const uint8_t *buf)
{
return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24);
}
-static inline uint32_t le_to_h_u24(const uint8_t* buf)
+static inline uint32_t le_to_h_u24(const uint8_t *buf)
{
return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16);
}
-static inline uint16_t le_to_h_u16(const uint8_t* buf)
+static inline uint16_t le_to_h_u16(const uint8_t *buf)
{
return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8);
}
@@ -153,17 +153,17 @@ static inline uint64_t be_to_h_u64(const uint8_t *buf)
(uint64_t)buf[0] << 56);
}
-static inline uint32_t be_to_h_u32(const uint8_t* buf)
+static inline uint32_t be_to_h_u32(const uint8_t *buf)
{
return (uint32_t)((uint32_t)buf[3] | (uint32_t)buf[2] << 8 | (uint32_t)buf[1] << 16 | (uint32_t)buf[0] << 24);
}
-static inline uint32_t be_to_h_u24(const uint8_t* buf)
+static inline uint32_t be_to_h_u24(const uint8_t *buf)
{
return (uint32_t)((uint32_t)buf[2] | (uint32_t)buf[1] << 8 | (uint32_t)buf[0] << 16);
}
-static inline uint16_t be_to_h_u16(const uint8_t* buf)
+static inline uint16_t be_to_h_u16(const uint8_t *buf)
{
return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8);
}
@@ -192,7 +192,7 @@ static inline void h_u64_to_be(uint8_t *buf, int64_t val)
buf[7] = (uint8_t) (val >> 0);
}
-static inline void h_u32_to_le(uint8_t* buf, int val)
+static inline void h_u32_to_le(uint8_t *buf, int val)
{
buf[3] = (uint8_t) (val >> 24);
buf[2] = (uint8_t) (val >> 16);
@@ -200,7 +200,7 @@ static inline void h_u32_to_le(uint8_t* buf, int val)
buf[0] = (uint8_t) (val >> 0);
}
-static inline void h_u32_to_be(uint8_t* buf, int val)
+static inline void h_u32_to_be(uint8_t *buf, int val)
{
buf[0] = (uint8_t) (val >> 24);
buf[1] = (uint8_t) (val >> 16);
@@ -208,27 +208,27 @@ static inline void h_u32_to_be(uint8_t* buf, int val)
buf[3] = (uint8_t) (val >> 0);
}
-static inline void h_u24_to_le(uint8_t* buf, int val)
+static inline void h_u24_to_le(uint8_t *buf, int val)
{
buf[2] = (uint8_t) (val >> 16);
buf[1] = (uint8_t) (val >> 8);
buf[0] = (uint8_t) (val >> 0);
}
-static inline void h_u24_to_be(uint8_t* buf, int val)
+static inline void h_u24_to_be(uint8_t *buf, int val)
{
buf[0] = (uint8_t) (val >> 16);
buf[1] = (uint8_t) (val >> 8);
buf[2] = (uint8_t) (val >> 0);
}
-static inline void h_u16_to_le(uint8_t* buf, int val)
+static inline void h_u16_to_le(uint8_t *buf, int val)
{
buf[1] = (uint8_t) (val >> 8);
buf[0] = (uint8_t) (val >> 0);
}
-static inline void h_u16_to_be(uint8_t* buf, int val)
+static inline void h_u16_to_be(uint8_t *buf, int val)
{
buf[0] = (uint8_t) (val >> 8);
buf[1] = (uint8_t) (val >> 0);
@@ -349,7 +349,6 @@ typedef uint64_t uintmax_t;
#endif
-#if BUILD_TARGET64
typedef uint64_t target_addr_t;
#define TARGET_ADDR_MAX UINT64_MAX
#define TARGET_PRIdADDR PRId64
@@ -357,15 +356,6 @@ typedef uint64_t target_addr_t;
#define TARGET_PRIoADDR PRIo64
#define TARGET_PRIxADDR PRIx64
#define TARGET_PRIXADDR PRIX64
-#else
-typedef uint32_t target_addr_t;
-#define TARGET_ADDR_MAX UINT32_MAX
-#define TARGET_PRIdADDR PRId32
-#define TARGET_PRIuADDR PRIu32
-#define TARGET_PRIoADDR PRIo32
-#define TARGET_PRIxADDR PRIx32
-#define TARGET_PRIXADDR PRIX32
-#endif
#define TARGET_ADDR_FMT "0x%8.8" TARGET_PRIxADDR
#endif /* OPENOCD_HELPER_TYPES_H */
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
index a76486399..b82914bcb 100644
--- a/src/jtag/Makefile.am
+++ b/src/jtag/Makefile.am
@@ -56,6 +56,7 @@ endif
%D%/interface.c \
%D%/interfaces.c \
%D%/tcl.c \
+ %D%/swim.c \
%D%/commands.h \
%D%/driver.h \
%D%/interface.h \
@@ -65,6 +66,7 @@ endif
%D%/minidriver/minidriver_imp.h \
%D%/minidummy/jtag_minidriver.h \
%D%/swd.h \
+ %D%/swim.h \
%D%/tcl.h \
$(JTAG_SRCS)
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 29a961338..af75917a3 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -46,7 +46,7 @@
* Holds support for configuring debug adapters from TCl scripts.
*/
-extern struct jtag_interface *jtag_interface;
+struct adapter_driver *adapter_driver;
const char * const jtag_only[] = { "jtag", NULL };
static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
@@ -61,12 +61,12 @@ static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
return JIM_ERR;
}
- const char *name = jtag_interface ? jtag_interface->name : NULL;
+ const char *name = adapter_driver ? adapter_driver->name : NULL;
Jim_SetResultString(goi.interp, name ? : "undefined", -1);
return JIM_OK;
}
-COMMAND_HANDLER(interface_transport_command)
+COMMAND_HANDLER(adapter_transports_command)
{
char **transports;
int retval;
@@ -85,26 +85,26 @@ COMMAND_HANDLER(interface_transport_command)
return retval;
}
-COMMAND_HANDLER(handle_interface_list_command)
+COMMAND_HANDLER(handle_adapter_list_command)
{
- if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0)
+ if (strcmp(CMD_NAME, "list") == 0 && CMD_ARGC > 0)
return ERROR_COMMAND_SYNTAX_ERROR;
- command_print(CMD, "The following debug interfaces are available:");
- for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) {
- const char *name = jtag_interfaces[i]->name;
+ command_print(CMD, "The following debug adapters are available:");
+ for (unsigned i = 0; NULL != adapter_drivers[i]; i++) {
+ const char *name = adapter_drivers[i]->name;
command_print(CMD, "%u: %s", i + 1, name);
}
return ERROR_OK;
}
-COMMAND_HANDLER(handle_interface_command)
+COMMAND_HANDLER(handle_adapter_driver_command)
{
int retval;
/* check whether the interface is already configured */
- if (jtag_interface) {
+ if (adapter_driver) {
LOG_WARNING("Interface already configured, ignoring");
return ERROR_OK;
}
@@ -113,20 +113,20 @@ COMMAND_HANDLER(handle_interface_command)
if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0')
return ERROR_COMMAND_SYNTAX_ERROR;
- for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) {
- if (strcmp(CMD_ARGV[0], jtag_interfaces[i]->name) != 0)
+ for (unsigned i = 0; NULL != adapter_drivers[i]; i++) {
+ if (strcmp(CMD_ARGV[0], adapter_drivers[i]->name) != 0)
continue;
- if (NULL != jtag_interfaces[i]->commands) {
+ if (NULL != adapter_drivers[i]->commands) {
retval = register_commands(CMD_CTX, NULL,
- jtag_interfaces[i]->commands);
+ adapter_drivers[i]->commands);
if (ERROR_OK != retval)
return retval;
}
- jtag_interface = jtag_interfaces[i];
+ adapter_driver = adapter_drivers[i];
- return allow_transports(CMD_CTX, jtag_interface->transports);
+ return allow_transports(CMD_CTX, adapter_driver->transports);
}
/* no valid interface was found (i.e. the configuration option,
@@ -134,7 +134,7 @@ COMMAND_HANDLER(handle_interface_command)
*/
LOG_ERROR("The specified debug interface was not found (%s)",
CMD_ARGV[0]);
- CALL_COMMAND_HANDLER(handle_interface_list_command);
+ CALL_COMMAND_HANDLER(handle_adapter_list_command);
return ERROR_JTAG_INVALID_INTERFACE;
}
@@ -355,7 +355,7 @@ next:
return ERROR_OK;
}
-COMMAND_HANDLER(handle_adapter_nsrst_delay_command)
+COMMAND_HANDLER(handle_adapter_srst_delay_command)
{
if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -365,11 +365,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_delay_command)
jtag_set_nsrst_delay(delay);
}
- command_print(CMD, "adapter_nsrst_delay: %u", jtag_get_nsrst_delay());
+ command_print(CMD, "adapter srst delay: %u", jtag_get_nsrst_delay());
return ERROR_OK;
}
-COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command)
+COMMAND_HANDLER(handle_adapter_srst_pulse_width_command)
{
if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -379,11 +379,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command)
jtag_set_nsrst_assert_width(width);
}
- command_print(CMD, "adapter_nsrst_assert_width: %u", jtag_get_nsrst_assert_width());
+ command_print(CMD, "adapter srst pulse_width: %u", jtag_get_nsrst_assert_width());
return ERROR_OK;
}
-COMMAND_HANDLER(handle_adapter_khz_command)
+COMMAND_HANDLER(handle_adapter_speed_command)
{
if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -411,6 +411,92 @@ COMMAND_HANDLER(handle_adapter_khz_command)
return retval;
}
+COMMAND_HANDLER(handle_adapter_reset_de_assert)
+{
+ enum values {
+ VALUE_UNDEFINED = -1,
+ VALUE_DEASSERT = 0,
+ VALUE_ASSERT = 1,
+ };
+ enum values value;
+ enum values srst = VALUE_UNDEFINED;
+ enum values trst = VALUE_UNDEFINED;
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+ char *signal;
+
+ if (CMD_ARGC == 0) {
+ if (transport_is_jtag()) {
+ if (jtag_reset_config & RESET_HAS_TRST)
+ signal = jtag_get_trst() ? "asserted" : "deasserted";
+ else
+ signal = "not present";
+ command_print(CMD, "trst %s", signal);
+ }
+
+ if (jtag_reset_config & RESET_HAS_SRST)
+ signal = jtag_get_srst() ? "asserted" : "deasserted";
+ else
+ signal = "not present";
+ command_print(CMD, "srst %s", signal);
+
+ return ERROR_OK;
+ }
+
+ if (CMD_ARGC != 1 && CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ value = (strcmp(CMD_NAME, "assert") == 0) ? VALUE_ASSERT : VALUE_DEASSERT;
+ if (strcmp(CMD_ARGV[0], "srst") == 0)
+ srst = value;
+ else if (strcmp(CMD_ARGV[0], "trst") == 0)
+ trst = value;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 3) {
+ if (strcmp(CMD_ARGV[1], "assert") == 0)
+ value = VALUE_ASSERT;
+ else if (strcmp(CMD_ARGV[1], "deassert") == 0)
+ value = VALUE_DEASSERT;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[2], "srst") == 0 && srst == VALUE_UNDEFINED)
+ srst = value;
+ else if (strcmp(CMD_ARGV[2], "trst") == 0 && trst == VALUE_UNDEFINED)
+ trst = value;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (trst == VALUE_UNDEFINED) {
+ if (transport_is_jtag())
+ trst = jtag_get_trst() ? VALUE_ASSERT : VALUE_DEASSERT;
+ else
+ trst = VALUE_DEASSERT; /* unused, safe value */
+ }
+
+ if (srst == VALUE_UNDEFINED) {
+ if (jtag_reset_config & RESET_HAS_SRST)
+ srst = jtag_get_srst() ? VALUE_ASSERT : VALUE_DEASSERT;
+ else
+ srst = VALUE_DEASSERT; /* unused, safe value */
+ }
+
+ if (trst == VALUE_ASSERT && !transport_is_jtag()) {
+ LOG_ERROR("transport has no trst signal");
+ return ERROR_FAIL;
+ }
+
+ if (srst == VALUE_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+ LOG_ERROR("adapter has no srst signal");
+ return ERROR_FAIL;
+ }
+
+ return adapter_resets((trst == VALUE_DEASSERT) ? TRST_DEASSERT : TRST_ASSERT,
+ (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT);
+}
+
#ifndef HAVE_JTAG_MINIDRIVER_H
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
COMMAND_HANDLER(handle_usb_location_command)
@@ -438,7 +524,70 @@ static const struct command_registration adapter_usb_command_handlers[] = {
};
#endif /* MINIDRIVER */
+static const struct command_registration adapter_srst_command_handlers[] = {
+ {
+ .name = "delay",
+ .handler = handle_adapter_srst_delay_command,
+ .mode = COMMAND_ANY,
+ .help = "delay after deasserting SRST in ms",
+ .usage = "[milliseconds]",
+ },
+ {
+ .name = "pulse_width",
+ .handler = handle_adapter_srst_pulse_width_command,
+ .mode = COMMAND_ANY,
+ .help = "SRST assertion pulse width in ms",
+ .usage = "[milliseconds]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
static const struct command_registration adapter_command_handlers[] = {
+ {
+ .name = "driver",
+ .handler = handle_adapter_driver_command,
+ .mode = COMMAND_CONFIG,
+ .help = "Select a debug adapter driver",
+ .usage = "driver_name",
+ },
+ {
+ .name = "speed",
+ .handler = handle_adapter_speed_command,
+ .mode = COMMAND_ANY,
+ .help = "With an argument, change to the specified maximum "
+ "jtag speed. For JTAG, 0 KHz signifies adaptive "
+ "clocking. "
+ "With or without argument, display current setting.",
+ .usage = "[khz]",
+ },
+ {
+ .name = "list",
+ .handler = handle_adapter_list_command,
+ .mode = COMMAND_ANY,
+ .help = "List all built-in debug adapter drivers",
+ .usage = "",
+ },
+ {
+ .name = "name",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_adapter_name,
+ .help = "Returns the name of the currently "
+ "selected adapter (driver)",
+ },
+ {
+ .name = "srst",
+ .mode = COMMAND_ANY,
+ .help = "srst adapter command group",
+ .usage = "",
+ .chain = adapter_srst_command_handlers,
+ },
+ {
+ .name = "transports",
+ .handler = adapter_transports_command,
+ .mode = COMMAND_CONFIG,
+ .help = "Declare transports the adapter supports.",
+ .usage = "transport ... ",
+ },
#ifndef HAVE_JTAG_MINIDRIVER_H
{
.name = "usb",
@@ -448,6 +597,20 @@ static const struct command_registration adapter_command_handlers[] = {
.chain = adapter_usb_command_handlers,
},
#endif /* MINIDRIVER */
+ {
+ .name = "assert",
+ .handler = handle_adapter_reset_de_assert,
+ .mode = COMMAND_EXEC,
+ .help = "Controls SRST and TRST lines.",
+ .usage = "|deassert [srst|trst [assert|deassert srst|trst]]",
+ },
+ {
+ .name = "deassert",
+ .handler = handle_adapter_reset_de_assert,
+ .mode = COMMAND_EXEC,
+ .help = "Controls SRST and TRST lines.",
+ .usage = "|assert [srst|trst [deassert|assert srst|trst]]",
+ },
COMMAND_REGISTRATION_DONE
};
@@ -459,58 +622,6 @@ static const struct command_registration interface_command_handlers[] = {
.usage = "",
.chain = adapter_command_handlers,
},
- {
- .name = "adapter_khz",
- .handler = handle_adapter_khz_command,
- .mode = COMMAND_ANY,
- .help = "With an argument, change to the specified maximum "
- "jtag speed. For JTAG, 0 KHz signifies adaptive "
- " clocking. "
- "With or without argument, display current setting.",
- .usage = "[khz]",
- },
- {
- .name = "adapter_name",
- .mode = COMMAND_ANY,
- .jim_handler = jim_adapter_name,
- .help = "Returns the name of the currently "
- "selected adapter (driver)",
- },
- {
- .name = "adapter_nsrst_delay",
- .handler = handle_adapter_nsrst_delay_command,
- .mode = COMMAND_ANY,
- .help = "delay after deasserting SRST in ms",
- .usage = "[milliseconds]",
- },
- {
- .name = "adapter_nsrst_assert_width",
- .handler = handle_adapter_nsrst_assert_width_command,
- .mode = COMMAND_ANY,
- .help = "delay after asserting SRST in ms",
- .usage = "[milliseconds]",
- },
- {
- .name = "interface",
- .handler = handle_interface_command,
- .mode = COMMAND_CONFIG,
- .help = "Select a debug adapter interface (driver)",
- .usage = "driver_name",
- },
- {
- .name = "interface_transports",
- .handler = interface_transport_command,
- .mode = COMMAND_CONFIG,
- .help = "Declare transports the interface supports.",
- .usage = "transport ... ",
- },
- {
- .name = "interface_list",
- .handler = handle_interface_list_command,
- .mode = COMMAND_ANY,
- .help = "List all built-in debug adapter interfaces (drivers)",
- .usage = "",
- },
{
.name = "reset_config",
.handler = handle_reset_config_command,
diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c
index c83b8c298..90871a138 100644
--- a/src/jtag/aice/aice_interface.c
+++ b/src/jtag/aice/aice_interface.c
@@ -25,7 +25,6 @@
#include
#include
#include
-#include
#include "aice_usb.h"
#define AICE_KHZ_TO_SPEED_MAP_SIZE 16
@@ -518,14 +517,20 @@ static const struct command_registration aice_command_handlers[] = {
/***************************************************************************/
/* End of Command handlers */
-struct jtag_interface aice_interface = {
+static struct jtag_interface aice_interface = {
+ .execute_queue = aice_execute_queue,
+};
+
+struct adapter_driver aice_adapter_driver = {
.name = "aice",
- .commands = aice_command_handlers,
.transports = aice_transports,
+ .commands = aice_command_handlers,
+
.init = aice_init,
.quit = aice_quit,
- .execute_queue = aice_execute_queue,
.speed = aice_speed, /* set interface speed */
- .speed_div = aice_speed_div, /* return readable value */
.khz = aice_khz, /* convert khz to interface speed value */
+ .speed_div = aice_speed_div, /* return readable value */
+
+ .jtag_ops = &aice_interface,
};
diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c
index 15ebcac97..ea710ad25 100644
--- a/src/jtag/aice/aice_transport.c
+++ b/src/jtag/aice/aice_transport.c
@@ -47,6 +47,7 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi,
return JIM_ERR;
}
+ assert(pTap->expected_ids);
memcpy(new_expected_ids, pTap->expected_ids, expected_len);
new_expected_ids[pTap->expected_ids_cnt] = w;
@@ -173,7 +174,7 @@ COMMAND_HANDLER(handle_scan_chain_command)
while (tap) {
uint32_t expected, expected_mask, ii;
- snprintf(expected_id, sizeof expected_id, "0x%08x",
+ snprintf(expected_id, sizeof(expected_id), "0x%08x",
(unsigned)((tap->expected_ids_cnt > 0)
? tap->expected_ids[0]
: 0));
@@ -195,7 +196,7 @@ COMMAND_HANDLER(handle_scan_chain_command)
(unsigned int)(expected_mask));
for (ii = 1; ii < tap->expected_ids_cnt; ii++) {
- snprintf(expected_id, sizeof expected_id, "0x%08x",
+ snprintf(expected_id, sizeof(expected_id), "0x%08x",
(unsigned) tap->expected_ids[ii]);
if (tap->ignore_version)
expected_id[2] = '*';
@@ -442,4 +443,3 @@ static void aice_constructor(void)
{
transport_register(&aice_jtag_transport);
}
-
diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c
index 324ec7c32..442754209 100644
--- a/src/jtag/aice/aice_usb.c
+++ b/src/jtag/aice/aice_usb.c
@@ -19,7 +19,7 @@
#include "config.h"
#endif
-#include
+#include
#include
#include
#include
@@ -349,41 +349,53 @@ static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id,
/* calls the given usb_bulk_* function, allowing for the data to
* trickle in with some timeouts */
static int usb_bulk_with_retries(
- int (*f)(jtag_libusb_device_handle *, int, char *, int, int),
- jtag_libusb_device_handle *dev, int ep,
- char *bytes, int size, int timeout)
+ int (*f)(libusb_device_handle *, int, char *, int, int, int *),
+ libusb_device_handle *dev, int ep,
+ char *bytes, int size, int timeout, int *transferred)
{
int tries = 3, count = 0;
while (tries && (count < size)) {
- int result = f(dev, ep, bytes + count, size - count, timeout);
- if (result > 0)
+ int result, ret;
+
+ ret = f(dev, ep, bytes + count, size - count, timeout, &result);
+ if (ERROR_OK == ret)
count += result;
- else if ((-ETIMEDOUT != result) || !--tries)
- return result;
+ else if ((ERROR_TIMEOUT_REACHED != ret) || !--tries)
+ return ret;
}
- return count;
+
+ *transferred = count;
+ return ERROR_OK;
}
-static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep,
- char *buff, int size, int timeout)
+static int wrap_usb_bulk_write(libusb_device_handle *dev, int ep,
+ char *buff, int size, int timeout, int *transferred)
{
+
/* usb_bulk_write() takes const char *buff */
- return jtag_libusb_bulk_write(dev, ep, buff, size, timeout);
+ jtag_libusb_bulk_write(dev, ep, buff, size, timeout, transferred);
+
+ return 0;
}
-static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep,
+static inline int usb_bulk_write_ex(libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout)
{
- return usb_bulk_with_retries(&wrap_usb_bulk_write,
- dev, ep, bytes, size, timeout);
+ int tr = 0;
+
+ usb_bulk_with_retries(&wrap_usb_bulk_write,
+ dev, ep, bytes, size, timeout, &tr);
+ return tr;
}
-static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep,
+static inline int usb_bulk_read_ex(struct libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout)
{
- return usb_bulk_with_retries(&jtag_libusb_bulk_read,
- dev, ep, bytes, size, timeout);
+ int tr = 0;
+ usb_bulk_with_retries(&jtag_libusb_bulk_read,
+ dev, ep, bytes, size, timeout, &tr);
+ return tr;
}
/* Write data from out_buffer to USB. */
@@ -472,7 +484,9 @@ static int aice_usb_packet_flush(void)
i = 0;
while (1) {
- aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status);
+ int retval = aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status);
+ if (retval != ERROR_OK)
+ return retval;
if (batch_status & 0x1)
return ERROR_OK;
@@ -1785,8 +1799,8 @@ static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val);
static int check_suppressed_exception(uint32_t coreid, uint32_t dbger_value)
{
- uint32_t ir4_value;
- uint32_t ir6_value;
+ uint32_t ir4_value = 0;
+ uint32_t ir6_value = 0;
/* the default value of handling_suppressed_exception is false */
static bool handling_suppressed_exception;
@@ -1840,7 +1854,7 @@ static int check_privilege(uint32_t coreid, uint32_t dbger_value)
static int aice_check_dbger(uint32_t coreid, uint32_t expect_status)
{
uint32_t i = 0;
- uint32_t value_dbger;
+ uint32_t value_dbger = 0;
while (1) {
aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &value_dbger);
@@ -1961,7 +1975,7 @@ static int aice_read_reg(uint32_t coreid, uint32_t num, uint32_t *val)
aice_execute_dim(coreid, instructions, 4);
- uint32_t value_edmsw;
+ uint32_t value_edmsw = 0;
aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw);
if (value_edmsw & NDS_EDMSW_WDV)
aice_read_dtr(coreid, val);
@@ -2006,7 +2020,7 @@ static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val)
LOG_DEBUG("aice_write_reg, reg_no: 0x%08" PRIx32 ", value: 0x%08" PRIx32, num, val);
uint32_t instructions[4]; /** execute instructions in DIM */
- uint32_t value_edmsw;
+ uint32_t value_edmsw = 0;
aice_write_dtr(coreid, val);
aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw);
@@ -2095,9 +2109,9 @@ static int aice_usb_open(struct aice_port_param_s *param)
{
const uint16_t vids[] = { param->vid, 0 };
const uint16_t pids[] = { param->pid, 0 };
- struct jtag_libusb_device_handle *devh;
+ struct libusb_device_handle *devh;
- if (jtag_libusb_open(vids, pids, NULL, &devh) != ERROR_OK)
+ if (jtag_libusb_open(vids, pids, NULL, &devh, NULL) != ERROR_OK)
return ERROR_FAIL;
/* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS
@@ -2113,7 +2127,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
#if IS_WIN32 == 0
- jtag_libusb_reset_device(devh);
+ libusb_reset_device(devh);
#if IS_DARWIN == 0
@@ -2121,7 +2135,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
/* reopen jlink after usb_reset
* on win32 this may take a second or two to re-enumerate */
int retval;
- while ((retval = jtag_libusb_open(vids, pids, NULL, &devh)) != ERROR_OK) {
+ while ((retval = jtag_libusb_open(vids, pids, NULL, &devh, NULL)) != ERROR_OK) {
usleep(1000);
timeout--;
if (!timeout)
@@ -2134,8 +2148,8 @@ static int aice_usb_open(struct aice_port_param_s *param)
#endif
/* usb_set_configuration required under win32 */
- jtag_libusb_set_configuration(devh, 0);
- jtag_libusb_claim_interface(devh, 0);
+ libusb_set_configuration(devh, 0);
+ libusb_claim_interface(devh, 0);
unsigned int aice_read_ep;
unsigned int aice_write_ep;
@@ -2435,7 +2449,7 @@ static int aice_backup_tmp_registers(uint32_t coreid)
LOG_DEBUG("backup_tmp_registers -");
/* backup target DTR first(if the target DTR is valid) */
- uint32_t value_edmsw;
+ uint32_t value_edmsw = 0;
aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw);
core_info[coreid].edmsw_backup = value_edmsw;
if (value_edmsw & 0x1) { /* EDMSW.WDV == 1 */
@@ -2602,13 +2616,13 @@ static int aice_usb_halt(uint32_t coreid)
aice_init_edm_registers(coreid, false);
/** Clear EDM_CTL.DBGIM & EDM_CTL.DBGACKM */
- uint32_t edm_ctl_value;
+ uint32_t edm_ctl_value = 0;
aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CTL, &edm_ctl_value);
if (edm_ctl_value & 0x3)
aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, edm_ctl_value & ~(0x3));
- uint32_t dbger;
- uint32_t acc_ctl_value;
+ uint32_t dbger = 0;
+ uint32_t acc_ctl_value = 0;
core_info[coreid].debug_under_dex_on = false;
aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &dbger);
@@ -2649,7 +2663,7 @@ static int aice_usb_halt(uint32_t coreid)
* it is only for debugging 'debug exception handler' purpose.
* after openocd detaches from target, target behavior is
* undefined. */
- uint32_t ir0_value;
+ uint32_t ir0_value = 0;
uint32_t debug_mode_ir0_value;
aice_read_reg(coreid, IR0, &ir0_value);
debug_mode_ir0_value = ir0_value | 0x408; /* turn on DEX, set POM = 1 */
@@ -4017,7 +4031,7 @@ static int aice_usb_profiling(uint32_t coreid, uint32_t interval, uint32_t itera
/* check status */
uint32_t i;
- uint32_t batch_status;
+ uint32_t batch_status = 0;
i = 0;
while (1) {
diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h
index 15cc1f60d..04021de3b 100644
--- a/src/jtag/aice/aice_usb.h
+++ b/src/jtag/aice/aice_usb.h
@@ -93,7 +93,7 @@
struct aice_usb_handler_s {
unsigned int usb_read_ep;
unsigned int usb_write_ep;
- struct jtag_libusb_device_handle *usb_handle;
+ struct libusb_device_handle *usb_handle;
};
struct cache_info {
diff --git a/src/jtag/commands.c b/src/jtag/commands.c
index 3352e035a..e88a3b74f 100644
--- a/src/jtag/commands.c
+++ b/src/jtag/commands.c
@@ -31,6 +31,7 @@
#endif
#include
+#include
#include "commands.h"
struct cmd_queue_page {
@@ -48,6 +49,19 @@ static struct jtag_command **next_command_pointer = &jtag_command_queue;
void jtag_queue_command(struct jtag_command *cmd)
{
+ if (!transport_is_jtag()) {
+ /*
+ * FIXME: This should not happen!
+ * There could be old code that queues jtag commands with non jtag interfaces so, for
+ * the moment simply highlight it by log an error.
+ * We should fix it quitting with assert(0) because it is an internal error, or returning
+ * an error after call to jtag_command_queue_reset() to free the jtag queue and avoid
+ * memory leaks.
+ * The fix can be applied immediately after next release (v0.11.0 ?)
+ */
+ LOG_ERROR("JTAG API jtag_queue_command() called on non JTAG interface");
+ }
+
/* this command goes on the end, so ensure the queue terminates */
cmd->next = NULL;
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 5e7c1e4bf..1d424b2e4 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -126,10 +126,10 @@ static int rclk_fallback_speed_khz;
static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
static int jtag_speed;
-static struct jtag_interface *jtag;
+/* FIXME: change name to this variable, it is not anymore JTAG only */
+static struct adapter_driver *jtag;
-/* configuration */
-struct jtag_interface *jtag_interface;
+extern struct adapter_driver *adapter_driver;
void jtag_set_flush_queue_sleep(int ms)
{
@@ -503,7 +503,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state)
{
int retval;
- if (!(jtag->supported & DEBUG_CAP_TMS_SEQ))
+ if (!(jtag->jtag_ops->supported & DEBUG_CAP_TMS_SEQ))
return ERROR_JTAG_NOT_IMPLEMENTED;
jtag_checks();
@@ -611,53 +611,42 @@ void jtag_add_clocks(int num_cycles)
}
}
-void swd_add_reset(int req_srst)
+static int adapter_system_reset(int req_srst)
{
+ int retval;
+
if (req_srst) {
if (!(jtag_reset_config & RESET_HAS_SRST)) {
LOG_ERROR("BUG: can't assert SRST");
- jtag_set_error(ERROR_FAIL);
- return;
+ return ERROR_FAIL;
}
req_srst = 1;
}
/* Maybe change SRST signal state */
if (jtag_srst != req_srst) {
- int retval;
-
- retval = interface_jtag_add_reset(0, req_srst);
- if (retval != ERROR_OK)
- jtag_set_error(retval);
- else
- retval = jtag_execute_queue();
-
+ retval = jtag->reset(0, req_srst);
if (retval != ERROR_OK) {
- LOG_ERROR("TRST/SRST error");
- return;
+ LOG_ERROR("SRST error");
+ return ERROR_FAIL;
}
-
- /* SRST resets everything hooked up to that signal */
jtag_srst = req_srst;
- if (jtag_srst) {
+
+ if (req_srst) {
LOG_DEBUG("SRST line asserted");
if (adapter_nsrst_assert_width)
- jtag_add_sleep(adapter_nsrst_assert_width * 1000);
+ jtag_sleep(adapter_nsrst_assert_width * 1000);
} else {
LOG_DEBUG("SRST line released");
if (adapter_nsrst_delay)
- jtag_add_sleep(adapter_nsrst_delay * 1000);
- }
-
- retval = jtag_execute_queue();
- if (retval != ERROR_OK) {
- LOG_ERROR("SRST timings error");
- return;
+ jtag_sleep(adapter_nsrst_delay * 1000);
}
}
+
+ return ERROR_OK;
}
-void jtag_add_reset(int req_tlr_or_trst, int req_srst)
+static void legacy_jtag_add_reset(int req_tlr_or_trst, int req_srst)
{
int trst_with_tlr = 0;
int new_srst = 0;
@@ -765,6 +754,119 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
}
}
+/* FIXME: name is misleading; we do not plan to "add" reset into jtag queue */
+void jtag_add_reset(int req_tlr_or_trst, int req_srst)
+{
+ int retval;
+ int trst_with_tlr = 0;
+ int new_srst = 0;
+ int new_trst = 0;
+
+ if (!jtag->reset) {
+ legacy_jtag_add_reset(req_tlr_or_trst, req_srst);
+ return;
+ }
+
+ /* Without SRST, we must use target-specific JTAG operations
+ * on each target; callers should not be requesting SRST when
+ * that signal doesn't exist.
+ *
+ * RESET_SRST_PULLS_TRST is a board or chip level quirk, which
+ * can kick in even if the JTAG adapter can't drive TRST.
+ */
+ if (req_srst) {
+ if (!(jtag_reset_config & RESET_HAS_SRST)) {
+ LOG_ERROR("BUG: can't assert SRST");
+ jtag_set_error(ERROR_FAIL);
+ return;
+ }
+ if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0
+ && !req_tlr_or_trst) {
+ LOG_ERROR("BUG: can't assert only SRST");
+ jtag_set_error(ERROR_FAIL);
+ return;
+ }
+ new_srst = 1;
+ }
+
+ /* JTAG reset (entry to TAP_RESET state) can always be achieved
+ * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE
+ * state first. TRST accelerates it, and bypasses those states.
+ *
+ * RESET_TRST_PULLS_SRST is a board or chip level quirk, which
+ * can kick in even if the JTAG adapter can't drive SRST.
+ */
+ if (req_tlr_or_trst) {
+ if (!(jtag_reset_config & RESET_HAS_TRST))
+ trst_with_tlr = 1;
+ else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0
+ && !req_srst)
+ trst_with_tlr = 1;
+ else
+ new_trst = 1;
+ }
+
+ /* Maybe change TRST and/or SRST signal state */
+ if (jtag_srst != new_srst || jtag_trst != new_trst) {
+ /* guarantee jtag queue empty before changing reset status */
+ jtag_execute_queue();
+
+ retval = jtag->reset(new_trst, new_srst);
+ if (retval != ERROR_OK) {
+ jtag_set_error(retval);
+ LOG_ERROR("TRST/SRST error");
+ return;
+ }
+ }
+
+ /* SRST resets everything hooked up to that signal */
+ if (jtag_srst != new_srst) {
+ jtag_srst = new_srst;
+ if (jtag_srst) {
+ LOG_DEBUG("SRST line asserted");
+ if (adapter_nsrst_assert_width)
+ jtag_add_sleep(adapter_nsrst_assert_width * 1000);
+ } else {
+ LOG_DEBUG("SRST line released");
+ if (adapter_nsrst_delay)
+ jtag_add_sleep(adapter_nsrst_delay * 1000);
+ }
+ }
+
+ /* Maybe enter the JTAG TAP_RESET state ...
+ * - using only TMS, TCK, and the JTAG state machine
+ * - or else more directly, using TRST
+ *
+ * TAP_RESET should be invisible to non-debug parts of the system.
+ */
+ if (trst_with_tlr) {
+ LOG_DEBUG("JTAG reset with TLR instead of TRST");
+ jtag_add_tlr();
+ jtag_execute_queue();
+
+ } else if (jtag_trst != new_trst) {
+ jtag_trst = new_trst;
+ if (jtag_trst) {
+ LOG_DEBUG("TRST line asserted");
+ tap_set_state(TAP_RESET);
+ if (jtag_ntrst_assert_width)
+ jtag_add_sleep(jtag_ntrst_assert_width * 1000);
+ } else {
+ LOG_DEBUG("TRST line released");
+ if (jtag_ntrst_delay)
+ jtag_add_sleep(jtag_ntrst_delay * 1000);
+
+ /* We just asserted nTRST, so we're now in TAP_RESET.
+ * Inform possible listeners about this, now that
+ * JTAG instructions and data can be shifted. This
+ * sequence must match jtag_add_tlr().
+ */
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+ jtag_notify_event(JTAG_TRST_ASSERTED);
+ }
+ }
+}
+
void jtag_add_sleep(uint32_t us)
{
/** @todo Here, keep_alive() appears to be a layering violation!!! */
@@ -836,7 +938,88 @@ int default_interface_jtag_execute_queue(void)
return ERROR_FAIL;
}
- return jtag->execute_queue();
+ if (!transport_is_jtag()) {
+ /*
+ * FIXME: This should not happen!
+ * There could be old code that queues jtag commands with non jtag interfaces so, for
+ * the moment simply highlight it by log an error and return on empty execute_queue.
+ * We should fix it quitting with assert(0) because it is an internal error.
+ * The fix can be applied immediately after next release (v0.11.0 ?)
+ */
+ LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface");
+ if (!jtag->jtag_ops || !jtag->jtag_ops->execute_queue)
+ return ERROR_OK;
+ }
+
+ int result = jtag->jtag_ops->execute_queue();
+
+#if !BUILD_ZY1000
+ /* Only build this if we use a regular driver with a command queue.
+ * Otherwise jtag_command_queue won't be found at compile/link time. Its
+ * definition is in jtag/commands.c, which is only built/linked by
+ * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables
+ * aren't accessible here. */
+ struct jtag_command *cmd = jtag_command_queue;
+ while (debug_level >= LOG_LVL_DEBUG && cmd) {
+ switch (cmd->type) {
+ case JTAG_SCAN:
+ LOG_DEBUG_IO("JTAG %s SCAN to %s",
+ cmd->cmd.scan->ir_scan ? "IR" : "DR",
+ tap_state_name(cmd->cmd.scan->end_state));
+ for (int i = 0; i < cmd->cmd.scan->num_fields; i++) {
+ struct scan_field *field = cmd->cmd.scan->fields + i;
+ if (field->out_value) {
+ char *str = buf_to_str(field->out_value, field->num_bits, 16);
+ LOG_DEBUG_IO(" %db out: %s", field->num_bits, str);
+ free(str);
+ }
+ if (field->in_value) {
+ char *str = buf_to_str(field->in_value, field->num_bits, 16);
+ LOG_DEBUG_IO(" %db in: %s", field->num_bits, str);
+ free(str);
+ }
+ }
+ break;
+ case JTAG_TLR_RESET:
+ LOG_DEBUG_IO("JTAG TLR RESET to %s",
+ tap_state_name(cmd->cmd.statemove->end_state));
+ break;
+ case JTAG_RUNTEST:
+ LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s",
+ cmd->cmd.runtest->num_cycles,
+ tap_state_name(cmd->cmd.runtest->end_state));
+ break;
+ case JTAG_RESET:
+ {
+ const char *reset_str[3] = {
+ "leave", "deassert", "assert"
+ };
+ LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST",
+ reset_str[cmd->cmd.reset->trst + 1],
+ reset_str[cmd->cmd.reset->srst + 1]);
+ }
+ break;
+ case JTAG_PATHMOVE:
+ LOG_DEBUG_IO("JTAG PATHMOVE (TODO)");
+ break;
+ case JTAG_SLEEP:
+ LOG_DEBUG_IO("JTAG SLEEP (TODO)");
+ break;
+ case JTAG_STABLECLOCKS:
+ LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)");
+ break;
+ case JTAG_TMS:
+ LOG_DEBUG_IO("JTAG TMS (TODO)");
+ break;
+ default:
+ LOG_ERROR("Unknown JTAG command: %d", cmd->type);
+ break;
+ }
+ cmd = cmd->next;
+ }
+#endif
+
+ return result;
}
void jtag_execute_queue_noclear(void)
@@ -1050,7 +1233,7 @@ static int jtag_examine_chain(void)
/* Add room for end-of-chain marker. */
max_taps++;
- uint8_t *idcode_buffer = malloc(max_taps * 4);
+ uint8_t *idcode_buffer = calloc(4, max_taps);
if (idcode_buffer == NULL)
return ERROR_JTAG_INIT_FAILED;
@@ -1086,7 +1269,7 @@ static int jtag_examine_chain(void)
* REVISIT create a jtag_alloc(chip, tap) routine, and
* share it with jim_newtap_cmd().
*/
- tap = calloc(1, sizeof *tap);
+ tap = calloc(1, sizeof(*tap));
if (!tap) {
retval = ERROR_FAIL;
goto out;
@@ -1107,7 +1290,8 @@ static int jtag_examine_chain(void)
if ((idcode & 1) == 0) {
/* Zero for LSB indicates a device in bypass */
- LOG_INFO("TAP %s has invalid IDCODE (0x%x)", tap->dotted_name, idcode);
+ LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%x)",
+ tap->dotted_name, idcode);
tap->hasidcode = false;
tap->idcode = 0;
@@ -1222,7 +1406,7 @@ static int jtag_validate_ircapture(void)
&& tap->ir_length < JTAG_IRLEN_MAX) {
tap->ir_length++;
}
- LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -irlen %d "
+ LOG_WARNING("AUTO %s - use \"jtag newtap %s %s -irlen %d "
"-expected-id 0x%08" PRIx32 "\"",
tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode);
}
@@ -1335,18 +1519,18 @@ int adapter_init(struct command_context *cmd_ctx)
if (jtag)
return ERROR_OK;
- if (!jtag_interface) {
- /* nothing was previously specified by "interface" command */
+ if (!adapter_driver) {
+ /* nothing was previously specified by "adapter driver" command */
LOG_ERROR("Debug Adapter has to be specified, "
- "see \"interface\" command");
+ "see \"adapter driver\" command");
return ERROR_JTAG_INVALID_INTERFACE;
}
int retval;
- retval = jtag_interface->init();
+ retval = adapter_driver->init();
if (retval != ERROR_OK)
return retval;
- jtag = jtag_interface;
+ jtag = adapter_driver;
if (jtag->speed == NULL) {
LOG_INFO("This adapter doesn't support configurable speed");
@@ -1355,7 +1539,7 @@ int adapter_init(struct command_context *cmd_ctx)
if (CLOCK_MODE_UNSELECTED == clock_mode) {
LOG_ERROR("An adapter speed is not selected in the init script."
- " Insert a call to adapter_khz or jtag_rclk to proceed.");
+ " Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed.");
return ERROR_JTAG_INIT_FAILED;
}
@@ -1486,17 +1670,19 @@ int adapter_quit(void)
int swd_init_reset(struct command_context *cmd_ctx)
{
- int retval = adapter_init(cmd_ctx);
+ int retval, retval1;
+
+ retval = adapter_init(cmd_ctx);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("Initializing with hard SRST reset");
if (jtag_reset_config & RESET_HAS_SRST)
- swd_add_reset(1);
- swd_add_reset(0);
- retval = jtag_execute_queue();
- return retval;
+ retval = adapter_system_reset(1);
+ retval1 = adapter_system_reset(0);
+
+ return (retval == ERROR_OK) ? retval1 : retval;
}
int jtag_init_reset(struct command_context *cmd_ctx)
@@ -1686,7 +1872,7 @@ void jtag_set_verify(bool enable)
jtag_verify = enable;
}
-bool jtag_will_verify()
+bool jtag_will_verify(void)
{
return jtag_verify;
}
@@ -1696,7 +1882,7 @@ void jtag_set_verify_capture_ir(bool enable)
jtag_verify_capture_ir = enable;
}
-bool jtag_will_verify_capture_ir()
+bool jtag_will_verify_capture_ir(void)
{
return jtag_verify_capture_ir;
}
@@ -1819,42 +2005,98 @@ bool transport_is_jtag(void)
return get_current_transport() == &jtag_transport;
}
-void adapter_assert_reset(void)
+int adapter_resets(int trst, int srst)
+{
+ if (get_current_transport() == NULL) {
+ LOG_ERROR("transport is not selected");
+ return ERROR_FAIL;
+ }
+
+ if (transport_is_jtag()) {
+ if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+ LOG_ERROR("adapter has no srst signal");
+ return ERROR_FAIL;
+ }
+
+ /* adapters without trst signal will eventually use tlr sequence */
+ jtag_add_reset(trst, srst);
+ /*
+ * The jtag queue is still used for reset by some adapter. Flush it!
+ * FIXME: To be removed when all adapter drivers will be updated!
+ */
+ jtag_execute_queue();
+ return ERROR_OK;
+ } else if (transport_is_swd() || transport_is_hla() ||
+ transport_is_dapdirect_swd() || transport_is_dapdirect_jtag() ||
+ transport_is_swim()) {
+ if (trst == TRST_ASSERT) {
+ LOG_ERROR("transport %s has no trst signal",
+ get_current_transport()->name);
+ return ERROR_FAIL;
+ }
+
+ if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+ LOG_ERROR("adapter has no srst signal");
+ return ERROR_FAIL;
+ }
+ adapter_system_reset(srst);
+ return ERROR_OK;
+ }
+
+ if (trst == TRST_DEASSERT && srst == SRST_DEASSERT)
+ return ERROR_OK;
+
+ LOG_ERROR("reset is not supported on transport %s",
+ get_current_transport()->name);
+
+ return ERROR_FAIL;
+}
+
+int adapter_assert_reset(void)
{
if (transport_is_jtag()) {
if (jtag_reset_config & RESET_SRST_PULLS_TRST)
jtag_add_reset(1, 1);
else
jtag_add_reset(0, 1);
- } else if (transport_is_swd())
- swd_add_reset(1);
+ return ERROR_OK;
+ } else if (transport_is_swd() || transport_is_hla() ||
+ transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() ||
+ transport_is_swim())
+ return adapter_system_reset(1);
else if (get_current_transport() != NULL)
LOG_ERROR("reset is not supported on %s",
get_current_transport()->name);
else
LOG_ERROR("transport is not selected");
+ return ERROR_FAIL;
}
-void adapter_deassert_reset(void)
+int adapter_deassert_reset(void)
{
- if (transport_is_jtag())
+ if (transport_is_jtag()) {
jtag_add_reset(0, 0);
- else if (transport_is_swd())
- swd_add_reset(0);
+ return ERROR_OK;
+ } else if (transport_is_swd() || transport_is_hla() ||
+ transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() ||
+ transport_is_swim())
+ return adapter_system_reset(0);
else if (get_current_transport() != NULL)
LOG_ERROR("reset is not supported on %s",
get_current_transport()->name);
else
LOG_ERROR("transport is not selected");
+ return ERROR_FAIL;
}
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler)
{
- if (jtag->config_trace)
- return jtag->config_trace(enabled, pin_protocol, port_size,
- trace_freq);
- else if (enabled) {
+ if (jtag->config_trace) {
+ return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq,
+ traceclkin_freq, prescaler);
+ } else if (enabled) {
LOG_ERROR("The selected interface does not support tracing");
return ERROR_FAIL;
}
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index 572cd2441..07824f678 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -22,7 +22,7 @@ DRIVERFILES += %D%/driver.c
DRIVERFILES += %D%/jtag_usb_common.c
if USE_LIBUSB1
-DRIVERFILES += %D%/libusb1_common.c
+DRIVERFILES += %D%/libusb_helper.c
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB1_CFLAGS)
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS)
endif
@@ -31,9 +31,6 @@ if USE_LIBUSB0
DRIVERFILES += %D%/usb_common.c
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS)
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS)
-if !USE_LIBUSB1
-DRIVERFILES += %D%/libusb0_common.c
-endif
endif
if USE_LIBFTDI
@@ -136,6 +133,9 @@ if HLADAPTER
DRIVERFILES += %D%/stlink_usb.c
DRIVERFILES += %D%/ti_icdi_usb.c
endif
+if RSHIM
+DRIVERFILES += %D%/rshim.c
+endif
if OSBDM
DRIVERFILES += %D%/osbdm.c
endif
@@ -145,6 +145,9 @@ endif
if SYSFSGPIO
DRIVERFILES += %D%/sysfsgpio.c
endif
+if XLNX_PCIE_XVC
+DRIVERFILES += %D%/xlnx-pcie-xvc.c
+endif
if BCM2835GPIO
DRIVERFILES += %D%/bcm2835gpio.c
endif
@@ -168,9 +171,7 @@ DRIVERHEADERS = \
%D%/bitbang.h \
%D%/bitq.h \
%D%/jtag_usb_common.h \
- %D%/libusb0_common.h \
- %D%/libusb1_common.h \
- %D%/libusb_common.h \
+ %D%/libusb_helper.h \
%D%/minidriver_imp.h \
%D%/mpsse.h \
%D%/rlink.h \
@@ -183,4 +184,3 @@ DRIVERHEADERS = \
%D%/versaloon/versaloon.h \
%D%/versaloon/versaloon_include.h \
%D%/versaloon/versaloon_internal.h
-
diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c
index 045672f0e..f5918a055 100644
--- a/src/jtag/drivers/amt_jtagaccel.c
+++ b/src/jtag/drivers/amt_jtagaccel.c
@@ -393,7 +393,7 @@ int amt_jtagaccel_get_giveio_access(void)
HANDLE h;
OSVERSIONINFO version;
- version.dwOSVersionInfoSize = sizeof version;
+ version.dwOSVersionInfoSize = sizeof(version);
if (!GetVersionEx(&version)) {
errno = EINVAL;
return -1;
@@ -584,7 +584,11 @@ static const struct command_registration amtjtagaccel_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface amt_jtagaccel_interface = {
+static struct jtag_interface amt_jtagaccel_interface = {
+ .execute_queue = amt_jtagaccel_execute_queue,
+};
+
+struct adapter_driver amt_jtagaccel_adapter_driver = {
.name = "amt_jtagaccel",
.transports = jtag_only,
.commands = amtjtagaccel_command_handlers,
@@ -592,5 +596,6 @@ struct jtag_interface amt_jtagaccel_interface = {
.init = amt_jtagaccel_init,
.quit = amt_jtagaccel_quit,
.speed = amt_jtagaccel_speed,
- .execute_queue = amt_jtagaccel_execute_queue,
+
+ .jtag_ops = &amt_jtagaccel_interface,
};
diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c
index 285bf9b7f..405278b9a 100644
--- a/src/jtag/drivers/arm-jtag-ew.c
+++ b/src/jtag/drivers/arm-jtag-ew.c
@@ -107,7 +107,7 @@ static int armjtagew_execute_queue(void)
switch (cmd->type) {
case JTAG_RUNTEST:
LOG_DEBUG_IO("runtest %i cycles, end in %i",
- cmd->cmd.runtest->num_cycles, \
+ cmd->cmd.runtest->num_cycles,
cmd->cmd.runtest->end_state);
armjtagew_end_state(cmd->cmd.runtest->end_state);
@@ -122,8 +122,8 @@ static int armjtagew_execute_queue(void)
break;
case JTAG_PATHMOVE:
- LOG_DEBUG_IO("pathmove: %i states, end in %i", \
- cmd->cmd.pathmove->num_states, \
+ LOG_DEBUG_IO("pathmove: %i states, end in %i",
+ cmd->cmd.pathmove->num_states,
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
armjtagew_path_move(cmd->cmd.pathmove->num_states,
@@ -459,10 +459,10 @@ static int armjtagew_get_version_info(void)
auxinfo[256] = '\0';
LOG_INFO(
- "ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", \
+ "ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s",
usb_in_buffer[1],
- usb_in_buffer[0], \
- isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', \
+ usb_in_buffer[0],
+ isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X',
sn,
auxinfo);
@@ -495,16 +495,22 @@ static const struct command_registration armjtagew_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface armjtagew_interface = {
- .name = "arm-jtag-ew",
- .commands = armjtagew_command_handlers,
- .transports = jtag_only,
+static struct jtag_interface armjtagew_interface = {
.execute_queue = armjtagew_execute_queue,
- .speed = armjtagew_speed,
- .speed_div = armjtagew_speed_div,
- .khz = armjtagew_khz,
+};
+
+struct adapter_driver armjtagew_adapter_driver = {
+ .name = "arm-jtag-ew",
+ .transports = jtag_only,
+ .commands = armjtagew_command_handlers,
+
.init = armjtagew_init,
.quit = armjtagew_quit,
+ .speed = armjtagew_speed,
+ .khz = armjtagew_khz,
+ .speed_div = armjtagew_speed_div,
+
+ .jtag_ops = &armjtagew_interface,
};
/**************************************************************************
@@ -677,7 +683,7 @@ static int armjtagew_tap_execute(void)
/****************************************************************************
* JLink USB low-level functions */
-static struct armjtagew *armjtagew_usb_open()
+static struct armjtagew *armjtagew_usb_open(void)
{
usb_init();
@@ -744,7 +750,7 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
return -1;
}
- result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, \
+ result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT,
(char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT);
LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result);
@@ -758,7 +764,7 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
/* Read data from USB into in_buffer. */
static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length)
{
- int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, \
+ int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN,
(char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT);
LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result);
diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c
index ac655635d..1026847fe 100644
--- a/src/jtag/drivers/at91rm9200.c
+++ b/src/jtag/drivers/at91rm9200.c
@@ -111,7 +111,6 @@ static uint32_t *pio_base;
*/
static bb_value_t at91rm9200_read(void);
static int at91rm9200_write(int tck, int tms, int tdi);
-static int at91rm9200_reset(int trst, int srst);
static int at91rm9200_init(void);
static int at91rm9200_quit(void);
@@ -119,7 +118,6 @@ static int at91rm9200_quit(void);
static struct bitbang_interface at91rm9200_bitbang = {
.read = at91rm9200_read,
.write = at91rm9200_write,
- .reset = at91rm9200_reset,
.blink = 0
};
@@ -189,13 +187,20 @@ static const struct command_registration at91rm9200_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface at91rm9200_interface = {
- .name = "at91rm9200",
+static struct jtag_interface at91rm9200_interface = {
.execute_queue = bitbang_execute_queue,
+};
+
+struct adapter_driver at91rm9200_adapter_driver = {
+ .name = "at91rm9200",
.transports = jtag_only,
.commands = at91rm9200_command_handlers,
+
.init = at91rm9200_init,
.quit = at91rm9200_quit,
+ .reset = at91rm9200_reset,
+
+ .jtag_ops = &at91rm9200_interface,
};
static int at91rm9200_init(void)
diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c
index 36e10b6da..df557c5c6 100644
--- a/src/jtag/drivers/bcm2835gpio.c
+++ b/src/jtag/drivers/bcm2835gpio.c
@@ -51,7 +51,6 @@ static volatile uint32_t *pio_base;
static bb_value_t bcm2835gpio_read(void);
static int bcm2835gpio_write(int tck, int tms, int tdi);
-static int bcm2835gpio_reset(int trst, int srst);
static int bcm2835_swdio_read(void);
static void bcm2835_swdio_drive(bool is_output);
@@ -62,7 +61,6 @@ static int bcm2835gpio_quit(void);
static struct bitbang_interface bcm2835gpio_bitbang = {
.read = bcm2835gpio_read,
.write = bcm2835gpio_write,
- .reset = bcm2835gpio_reset,
.swdio_read = bcm2835_swdio_read,
.swdio_drive = bcm2835_swdio_drive,
.blink = NULL
@@ -407,18 +405,25 @@ static const struct command_registration bcm2835gpio_command_handlers[] = {
static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
-struct jtag_interface bcm2835gpio_interface = {
- .name = "bcm2835gpio",
+static struct jtag_interface bcm2835gpio_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = bitbang_execute_queue,
+};
+
+struct adapter_driver bcm2835gpio_adapter_driver = {
+ .name = "bcm2835gpio",
.transports = bcm2835_transports,
- .swd = &bitbang_swd,
+ .commands = bcm2835gpio_command_handlers,
+
+ .init = bcm2835gpio_init,
+ .quit = bcm2835gpio_quit,
+ .reset = bcm2835gpio_reset,
.speed = bcm2835gpio_speed,
.khz = bcm2835gpio_khz,
.speed_div = bcm2835gpio_speed_div,
- .commands = bcm2835gpio_command_handlers,
- .init = bcm2835gpio_init,
- .quit = bcm2835gpio_quit,
+
+ .jtag_ops = &bcm2835gpio_interface,
+ .swd_ops = &bitbang_swd,
};
static bool bcm2835gpio_jtag_mode_possible(void)
@@ -461,7 +466,11 @@ static int bcm2835gpio_init(void)
return ERROR_JTAG_INIT_FAILED;
}
- dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
+ dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
+ if (dev_mem_fd < 0) {
+ LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
+ dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
+ }
if (dev_mem_fd < 0) {
perror("open");
return ERROR_JTAG_INIT_FAILED;
diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c
index b5078c080..72e9320b4 100644
--- a/src/jtag/drivers/bitbang.c
+++ b/src/jtag/drivers/bitbang.c
@@ -314,17 +314,6 @@ int bitbang_execute_queue(void)
while (cmd) {
switch (cmd->type) {
- case JTAG_RESET:
- LOG_DEBUG_IO("reset trst: %i srst %i",
- cmd->cmd.reset->trst,
- cmd->cmd.reset->srst);
- if ((cmd->cmd.reset->trst == 1) ||
- (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
- tap_set_state(TAP_RESET);
- if (bitbang_interface->reset(cmd->cmd.reset->trst,
- cmd->cmd.reset->srst) != ERROR_OK)
- return ERROR_FAIL;
- break;
case JTAG_RUNTEST:
LOG_DEBUG_IO("runtest %i cycles, end in %s",
cmd->cmd.runtest->num_cycles,
diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h
index 577717ebd..bbbc693df 100644
--- a/src/jtag/drivers/bitbang.h
+++ b/src/jtag/drivers/bitbang.h
@@ -51,13 +51,12 @@ struct bitbang_interface {
/** Set TCK, TMS, and TDI to the given values. */
int (*write)(int tck, int tms, int tdi);
- int (*reset)(int trst, int srst);
int (*blink)(int on);
int (*swdio_read)(void);
void (*swdio_drive)(bool on);
};
-const struct swd_driver bitbang_swd;
+extern const struct swd_driver bitbang_swd;
extern bool swd_mode;
diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c
index 872896ba3..020c4ce39 100644
--- a/src/jtag/drivers/buspirate.c
+++ b/src/jtag/drivers/buspirate.c
@@ -34,6 +34,7 @@
static int buspirate_execute_queue(void);
static int buspirate_init(void);
static int buspirate_quit(void);
+static int buspirate_reset(int trst, int srst);
static void buspirate_end_state(tap_state_t state);
static void buspirate_state_move(void);
@@ -133,7 +134,6 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer,
struct scan_command *command);
static void buspirate_tap_make_space(int scan, int bits);
-static void buspirate_reset(int trst, int srst);
static void buspirate_set_feature(int, char, char);
static void buspirate_set_mode(int, char);
static void buspirate_set_speed(int, char);
@@ -213,18 +213,6 @@ static int buspirate_execute_queue(void)
buffer, scan_size, cmd->cmd.scan);
break;
- case JTAG_RESET:
- LOG_DEBUG_IO("reset trst: %i srst %i",
- cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-
- /* flush buffers, so we can reset */
- buspirate_tap_execute();
-
- if (cmd->cmd.reset->trst == 1)
- tap_set_state(TAP_RESET);
- buspirate_reset(cmd->cmd.reset->trst,
- cmd->cmd.reset->srst);
- break;
case JTAG_SLEEP:
LOG_DEBUG_IO("sleep %i", cmd->cmd.sleep->us);
buspirate_tap_execute();
@@ -548,14 +536,21 @@ static const struct swd_driver buspirate_swd = {
static const char * const buspirate_transports[] = { "jtag", "swd", NULL };
-struct jtag_interface buspirate_interface = {
- .name = "buspirate",
+static struct jtag_interface buspirate_interface = {
.execute_queue = buspirate_execute_queue,
- .commands = buspirate_command_handlers,
+};
+
+struct adapter_driver buspirate_adapter_driver = {
+ .name = "buspirate",
.transports = buspirate_transports,
- .swd = &buspirate_swd,
+ .commands = buspirate_command_handlers,
+
.init = buspirate_init,
- .quit = buspirate_quit
+ .quit = buspirate_quit,
+ .reset = buspirate_reset,
+
+ .jtag_ops = &buspirate_interface,
+ .swd_ops = &buspirate_swd,
};
/*************** jtag execute commands **********************/
@@ -860,7 +855,7 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer,
/*************** wrapper functions *********************/
/* (1) assert or (0) deassert reset lines */
-static void buspirate_reset(int trst, int srst)
+static int buspirate_reset(int trst, int srst)
{
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
@@ -873,6 +868,8 @@ static void buspirate_reset(int trst, int srst)
buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE);
else
buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE);
+
+ return ERROR_OK;
}
static void buspirate_set_feature(int fd, char feat, char action)
diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c
index d52d698a4..ee1cb533c 100644
--- a/src/jtag/drivers/cmsis_dap_usb.c
+++ b/src/jtag/drivers/cmsis_dap_usb.c
@@ -364,8 +364,6 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
free(pending_fifo[i].transfers);
pending_fifo[i].transfers = NULL;
}
-
- return;
}
static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen)
@@ -509,15 +507,15 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data)
return ERROR_OK;
}
-static int cmsis_dap_cmd_DAP_LED(uint8_t leds)
+static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state)
{
int retval;
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_LED;
- buffer[2] = 0x00;
- buffer[3] = leds;
+ buffer[2] = led;
+ buffer[3] = state;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4);
if (retval != ERROR_OK || buffer[1] != 0x00) {
@@ -1086,8 +1084,12 @@ static int cmsis_dap_init(void)
if (retval != ERROR_OK)
return ERROR_FAIL;
}
+ /* Both LEDs on */
+ retval = cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON);
+ if (retval != ERROR_OK)
+ return ERROR_FAIL;
- retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */
+ retval = cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON);
if (retval != ERROR_OK)
return ERROR_FAIL;
@@ -1102,9 +1104,6 @@ static int cmsis_dap_init(void)
LOG_INFO("Connecting under reset");
}
}
-
- cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */
-
LOG_INFO("CMSIS-DAP: Interface ready");
return ERROR_OK;
@@ -1119,28 +1118,31 @@ static int cmsis_dap_swd_init(void)
static int cmsis_dap_quit(void)
{
cmsis_dap_cmd_DAP_Disconnect();
- cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */
+ /* Both LEDs off */
+ cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF);
+ cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF);
cmsis_dap_usb_close(cmsis_dap_handle);
return ERROR_OK;
}
-static void cmsis_dap_execute_reset(struct jtag_command *cmd)
+static int cmsis_dap_reset(int trst, int srst)
{
/* Set both TRST and SRST even if they're not enabled as
* there's no way to tristate them */
output_pins = 0;
- if (!cmd->cmd.reset->srst)
+ if (!srst)
output_pins |= SWJ_PIN_SRST;
- if (!cmd->cmd.reset->trst)
+ if (!trst)
output_pins |= SWJ_PIN_TRST;
int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins,
SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL);
if (retval != ERROR_OK)
LOG_ERROR("CMSIS-DAP: Interface reset failed");
+ return retval;
}
static void cmsis_dap_execute_sleep(struct jtag_command *cmd)
@@ -1581,10 +1583,6 @@ static void cmsis_dap_execute_tms(struct jtag_command *cmd)
static void cmsis_dap_execute_command(struct jtag_command *cmd)
{
switch (cmd->type) {
- case JTAG_RESET:
- cmsis_dap_flush();
- cmsis_dap_execute_reset(cmd);
- break;
case JTAG_SLEEP:
cmsis_dap_flush();
cmsis_dap_execute_sleep(cmd);
@@ -1631,10 +1629,10 @@ static int cmsis_dap_execute_queue(void)
static int cmsis_dap_speed(int speed)
{
if (speed > DAP_MAX_CLOCK)
- LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed);
+ LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed);
if (speed == 0) {
- LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
+ LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\".");
return ERROR_JTAG_NOT_IMPLEMENTED;
}
@@ -1789,17 +1787,23 @@ static const struct swd_driver cmsis_dap_swd_driver = {
static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
-struct jtag_interface cmsis_dap_interface = {
- .name = "cmsis-dap",
+static struct jtag_interface cmsis_dap_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
- .commands = cmsis_dap_command_handlers,
- .swd = &cmsis_dap_swd_driver,
- .transports = cmsis_dap_transport,
-
.execute_queue = cmsis_dap_execute_queue,
- .speed = cmsis_dap_speed,
- .speed_div = cmsis_dap_speed_div,
- .khz = cmsis_dap_khz,
+};
+
+struct adapter_driver cmsis_dap_adapter_driver = {
+ .name = "cmsis-dap",
+ .transports = cmsis_dap_transport,
+ .commands = cmsis_dap_command_handlers,
+
.init = cmsis_dap_init,
.quit = cmsis_dap_quit,
+ .reset = cmsis_dap_reset,
+ .speed = cmsis_dap_speed,
+ .khz = cmsis_dap_khz,
+ .speed_div = cmsis_dap_speed_div,
+
+ .jtag_ops = &cmsis_dap_interface,
+ .swd_ops = &cmsis_dap_swd_driver,
};
diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c
index 4e5b6152c..e66cb6bd5 100644
--- a/src/jtag/drivers/dummy.c
+++ b/src/jtag/drivers/dummy.c
@@ -91,7 +91,6 @@ static int dummy_led(int on)
static struct bitbang_interface dummy_bitbang = {
.read = &dummy_read,
.write = &dummy_write,
- .reset = &dummy_reset,
.blink = &dummy_led,
};
@@ -145,19 +144,22 @@ static const struct command_registration dummy_command_handlers[] = {
/* The dummy driver is used to easily check the code path
* where the target is unresponsive.
*/
-struct jtag_interface dummy_interface = {
- .name = "dummy",
+static struct jtag_interface dummy_interface = {
+ .supported = DEBUG_CAP_TMS_SEQ,
+ .execute_queue = &bitbang_execute_queue,
+};
- .supported = DEBUG_CAP_TMS_SEQ,
- .commands = dummy_command_handlers,
- .transports = jtag_only,
+struct adapter_driver dummy_adapter_driver = {
+ .name = "dummy",
+ .transports = jtag_only,
+ .commands = dummy_command_handlers,
- .execute_queue = &bitbang_execute_queue,
+ .init = &dummy_init,
+ .quit = &dummy_quit,
+ .reset = &dummy_reset,
+ .speed = &dummy_speed,
+ .khz = &dummy_khz,
+ .speed_div = &dummy_speed_div,
- .speed = &dummy_speed,
- .khz = &dummy_khz,
- .speed_div = &dummy_speed_div,
-
- .init = &dummy_init,
- .quit = &dummy_quit,
- };
+ .jtag_ops = &dummy_interface,
+};
diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c
index 4cf318485..5e0e62afa 100644
--- a/src/jtag/drivers/ep93xx.c
+++ b/src/jtag/drivers/ep93xx.c
@@ -50,21 +50,25 @@ static int ep93xx_quit(void);
struct timespec ep93xx_zzzz;
-struct jtag_interface ep93xx_interface = {
- .name = "ep93xx",
-
+static struct jtag_interface ep93xx_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = bitbang_execute_queue,
+};
+
+struct adapter_driver ep93xx_adapter_driver = {
+ .name = "ep93xx",
.transports = jtag_only,
.init = ep93xx_init,
.quit = ep93xx_quit,
+ .reset = ep93xx_reset,
+
+ .jtag_ops = &ep93xx_interface,
};
static struct bitbang_interface ep93xx_bitbang = {
.read = ep93xx_read,
.write = ep93xx_write,
- .reset = ep93xx_reset,
.blink = 0,
};
diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c
index 8cda76ed2..c9ed304a8 100644
--- a/src/jtag/drivers/ft232r.c
+++ b/src/jtag/drivers/ft232r.c
@@ -29,7 +29,7 @@
#include
#include
#include
-#include "libusb1_common.h"
+#include "libusb_helper.h"
/* system includes */
#include
@@ -71,7 +71,7 @@
static char *ft232r_serial_desc;
static uint16_t ft232r_vid = 0x0403; /* FTDI */
static uint16_t ft232r_pid = 0x6001; /* FT232R */
-static jtag_libusb_device_handle *adapter;
+static struct libusb_device_handle *adapter;
static uint8_t *ft232r_output;
static size_t ft232r_output_len;
@@ -132,11 +132,11 @@ static int ft232r_send_recv(void)
bytes_to_write = rxfifo_free;
if (bytes_to_write) {
- int n = jtag_libusb_bulk_write(adapter, IN_EP,
- (char *) ft232r_output + total_written,
- bytes_to_write, 1000);
+ int n;
- if (n == 0) {
+ if (jtag_libusb_bulk_write(adapter, IN_EP,
+ (char *) ft232r_output + total_written,
+ bytes_to_write, 1000, &n) != ERROR_OK) {
LOG_ERROR("usb bulk write failed");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -147,12 +147,10 @@ static int ft232r_send_recv(void)
/* Read */
uint8_t reply[64];
+ int n;
- int n = jtag_libusb_bulk_read(adapter, OUT_EP,
- (char *) reply,
- sizeof(reply), 1000);
-
- if (n == 0) {
+ if (jtag_libusb_bulk_read(adapter, OUT_EP, (char *) reply,
+ sizeof(reply), 1000, &n) != ERROR_OK) {
LOG_ERROR("usb bulk read failed");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -259,7 +257,7 @@ static int ft232r_init(void)
{
uint16_t avids[] = {ft232r_vid, 0};
uint16_t apids[] = {ft232r_pid, 0};
- if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter)) {
+ if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter, NULL)) {
LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n",
ft232r_vid, ft232r_pid, (ft232r_serial_desc == NULL) ? "[any]" : ft232r_serial_desc);
return ERROR_JTAG_INIT_FAILED;
@@ -270,7 +268,7 @@ static int ft232r_init(void)
else /* serial port will be restored after jtag: */
libusb_set_auto_detach_kernel_driver(adapter, 1); /* 1: DONT_DETACH_SIO_MODULE */
- if (jtag_libusb_claim_interface(adapter, 0)) {
+ if (libusb_claim_interface(adapter, 0)) {
LOG_ERROR("unable to claim interface");
return ERROR_JTAG_INIT_FAILED;
}
@@ -332,7 +330,7 @@ static int ft232r_quit(void)
}
}
- if (jtag_libusb_release_interface(adapter, 0) != 0)
+ if (libusb_release_interface(adapter, 0) != 0)
LOG_ERROR("usb release interface failed");
jtag_libusb_close(adapter);
@@ -914,17 +912,21 @@ static int syncbb_execute_queue(void)
return retval;
}
-struct jtag_interface ft232r_interface = {
- .name = "ft232r",
- .commands = ft232r_command_handlers,
- .transports = jtag_only,
+static struct jtag_interface ft232r_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
-
.execute_queue = syncbb_execute_queue,
+};
+
+struct adapter_driver ft232r_adapter_driver = {
+ .name = "ft232r",
+ .transports = jtag_only,
+ .commands = ft232r_command_handlers,
- .speed = ft232r_speed,
.init = ft232r_init,
.quit = ft232r_quit,
- .speed_div = ft232r_speed_div,
+ .speed = ft232r_speed,
.khz = ft232r_khz,
+ .speed_div = ft232r_speed_div,
+
+ .jtag_ops = &ft232r_interface,
};
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index ebe60164a..da4ea20b9 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -249,7 +249,7 @@ static int ftdi_set_signal(const struct signal *s, char value)
return ERROR_OK;
}
-static int ftdi_get_signal(const struct signal *s, uint16_t * value_out)
+static int ftdi_get_signal(const struct signal *s, uint16_t *value_out)
{
uint8_t data_low = 0;
uint8_t data_high = 0;
@@ -582,46 +582,40 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
tap_state_name(tap_get_end_state()));
}
-static void ftdi_execute_reset(struct jtag_command *cmd)
+static int ftdi_reset(int trst, int srst)
{
- LOG_DEBUG_IO("reset trst: %i srst %i",
- cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+ struct signal *sig_ntrst = find_signal_by_name("nTRST");
+ struct signal *sig_nsrst = find_signal_by_name("nSRST");
- if (cmd->cmd.reset->trst == 1
- || (cmd->cmd.reset->srst
- && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
- tap_set_state(TAP_RESET);
+ LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst);
- struct signal *trst = find_signal_by_name("nTRST");
- if (cmd->cmd.reset->trst == 1) {
- if (trst)
- ftdi_set_signal(trst, '0');
+ if (trst == 1) {
+ if (sig_ntrst)
+ ftdi_set_signal(sig_ntrst, '0');
else
LOG_ERROR("Can't assert TRST: nTRST signal is not defined");
- } else if (trst && jtag_get_reset_config() & RESET_HAS_TRST &&
- cmd->cmd.reset->trst == 0) {
+ } else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST &&
+ trst == 0) {
if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
- ftdi_set_signal(trst, 'z');
+ ftdi_set_signal(sig_ntrst, 'z');
else
- ftdi_set_signal(trst, '1');
+ ftdi_set_signal(sig_ntrst, '1');
}
- struct signal *srst = find_signal_by_name("nSRST");
- if (cmd->cmd.reset->srst == 1) {
- if (srst)
- ftdi_set_signal(srst, '0');
+ if (srst == 1) {
+ if (sig_nsrst)
+ ftdi_set_signal(sig_nsrst, '0');
else
LOG_ERROR("Can't assert SRST: nSRST signal is not defined");
- } else if (srst && jtag_get_reset_config() & RESET_HAS_SRST &&
- cmd->cmd.reset->srst == 0) {
+ } else if (sig_nsrst && jtag_get_reset_config() & RESET_HAS_SRST &&
+ srst == 0) {
if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
- ftdi_set_signal(srst, '1');
+ ftdi_set_signal(sig_nsrst, '1');
else
- ftdi_set_signal(srst, 'z');
+ ftdi_set_signal(sig_nsrst, 'z');
}
- LOG_DEBUG_IO("trst: %i, srst: %i",
- cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+ return mpsse_flush(mpsse_ctx);
}
static void ftdi_execute_sleep(struct jtag_command *cmd)
@@ -727,6 +721,11 @@ static int ftdi_initialize(void)
else
LOG_DEBUG("ftdi interface using shortest path jtag state transitions");
+ if (!ftdi_vid[0] && !ftdi_pid[0]) {
+ LOG_ERROR("Please specify ftdi_vid_pid");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
ftdi_serial, jtag_usb_get_location(), ftdi_channel);
@@ -1592,17 +1591,23 @@ static const struct swd_driver ftdi_swd = {
static const char * const ftdi_transports[] = { "jtag", "swd", NULL };
-struct jtag_interface ftdi_interface = {
- .name = "ftdi",
+static struct jtag_interface ftdi_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
- .commands = ftdi_command_handlers,
+ .execute_queue = ftdi_execute_queue,
+};
+
+struct adapter_driver ftdi_adapter_driver = {
+ .name = "ftdi",
.transports = ftdi_transports,
- .swd = &ftdi_swd,
+ .commands = ftdi_command_handlers,
.init = ftdi_initialize,
.quit = ftdi_quit,
+ .reset = ftdi_reset,
.speed = ftdi_speed,
- .speed_div = ftdi_speed_div,
.khz = ftdi_khz,
- .execute_queue = ftdi_execute_queue,
+ .speed_div = ftdi_speed_div,
+
+ .jtag_ops = &ftdi_interface,
+ .swd_ops = &ftdi_swd,
};
diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c
index e65f56cd1..d1699ef01 100644
--- a/src/jtag/drivers/gw16012.c
+++ b/src/jtag/drivers/gw16012.c
@@ -350,7 +350,7 @@ static int gw16012_get_giveio_access(void)
HANDLE h;
OSVERSIONINFO version;
- version.dwOSVersionInfoSize = sizeof version;
+ version.dwOSVersionInfoSize = sizeof(version);
if (!GetVersionEx(&version)) {
errno = EINVAL;
return -1;
@@ -448,7 +448,7 @@ static int gw16012_init_device(void)
LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)");
}
- LOG_DEBUG("requesting privileges for parallel port 0x%lx...", (long unsigned)(gw16012_port));
+ LOG_DEBUG("requesting privileges for parallel port 0x%" PRIx16 "...", gw16012_port);
#if PARPORT_USE_GIVEIO == 1
if (gw16012_get_giveio_access() != 0) {
#else /* PARPORT_USE_GIVEIO */
@@ -521,12 +521,17 @@ static const struct command_registration gw16012_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface gw16012_interface = {
+static struct jtag_interface gw16012_interface = {
+ .execute_queue = gw16012_execute_queue,
+};
+
+struct adapter_driver gw16012_adapter_driver = {
.name = "gw16012",
.transports = jtag_only,
.commands = gw16012_command_handlers,
.init = gw16012_init,
.quit = gw16012_quit,
- .execute_queue = gw16012_execute_queue,
+
+ .jtag_ops = &gw16012_interface,
};
diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c
index 4923dab39..7dcfb6790 100644
--- a/src/jtag/drivers/imx_gpio.c
+++ b/src/jtag/drivers/imx_gpio.c
@@ -84,7 +84,6 @@ static inline bool gpio_level(int g)
static bb_value_t imx_gpio_read(void);
static int imx_gpio_write(int tck, int tms, int tdi);
-static int imx_gpio_reset(int trst, int srst);
static int imx_gpio_swdio_read(void);
static void imx_gpio_swdio_drive(bool is_output);
@@ -95,7 +94,6 @@ static int imx_gpio_quit(void);
static struct bitbang_interface imx_gpio_bitbang = {
.read = imx_gpio_read,
.write = imx_gpio_write,
- .reset = imx_gpio_reset,
.swdio_read = imx_gpio_swdio_read,
.swdio_drive = imx_gpio_swdio_drive,
.blink = NULL
@@ -429,18 +427,25 @@ static const struct command_registration imx_gpio_command_handlers[] = {
static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL };
-struct jtag_interface imx_gpio_interface = {
- .name = "imx_gpio",
+static struct jtag_interface imx_gpio_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = bitbang_execute_queue,
+};
+
+struct adapter_driver imx_gpio_adapter_driver = {
+ .name = "imx_gpio",
.transports = imx_gpio_transports,
- .swd = &bitbang_swd,
+ .commands = imx_gpio_command_handlers,
+
+ .init = imx_gpio_init,
+ .quit = imx_gpio_quit,
+ .reset = imx_gpio_reset,
.speed = imx_gpio_speed,
.khz = imx_gpio_khz,
.speed_div = imx_gpio_speed_div,
- .commands = imx_gpio_command_handlers,
- .init = imx_gpio_init,
- .quit = imx_gpio_quit,
+
+ .jtag_ops = &imx_gpio_interface,
+ .swd_ops = &bitbang_swd,
};
static bool imx_gpio_jtag_mode_possible(void)
diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c
index 09b3a858b..1baf3454e 100644
--- a/src/jtag/drivers/jlink.c
+++ b/src/jtag/drivers/jlink.c
@@ -39,6 +39,7 @@
#include
#include
#include
+#include
#include
@@ -62,6 +63,9 @@ static bool trace_enabled;
static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE;
+/* Maximum SWO frequency deviation. */
+#define SWO_MAX_FREQ_DEV 0.03
+
/* 256 byte non-volatile memory */
struct device_config {
uint8_t usb_address;
@@ -90,6 +94,7 @@ static void jlink_path_move(int num_states, tap_state_t *path);
static void jlink_stableclocks(int num_cycles);
static void jlink_runtest(int num_cycles);
static void jlink_reset(int trst, int srst);
+static int jlink_reset_safe(int trst, int srst);
static int jlink_swd_run_queue(void);
static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk);
static int jlink_swd_switch_seq(enum swd_special_seq seq);
@@ -247,16 +252,6 @@ static void jlink_execute_scan(struct jtag_command *cmd)
tap_state_name(tap_get_end_state()));
}
-static void jlink_execute_reset(struct jtag_command *cmd)
-{
- LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst,
- cmd->cmd.reset->srst);
-
- jlink_flush();
- jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
- jlink_flush();
-}
-
static void jlink_execute_sleep(struct jtag_command *cmd)
{
LOG_DEBUG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us);
@@ -282,9 +277,6 @@ static int jlink_execute_command(struct jtag_command *cmd)
case JTAG_SCAN:
jlink_execute_scan(cmd);
break;
- case JTAG_RESET:
- jlink_execute_reset(cmd);
- break;
case JTAG_SLEEP:
jlink_execute_sleep(cmd);
break;
@@ -952,6 +944,13 @@ static void jlink_reset(int trst, int srst)
jaylink_jtag_set_trst(devh);
}
+static int jlink_reset_safe(int trst, int srst)
+{
+ jlink_flush();
+ jlink_reset(trst, srst);
+ return jlink_flush();
+}
+
COMMAND_HANDLER(jlink_usb_command)
{
int tmp;
@@ -1267,55 +1266,74 @@ static uint32_t calculate_trace_buffer_size(void)
return tmp & 0xffffff00;
}
-static bool check_trace_freq(struct jaylink_swo_speed speed,
- uint32_t trace_freq)
+static bool calculate_swo_prescaler(unsigned int traceclkin_freq,
+ uint32_t trace_freq, uint16_t *prescaler)
{
- double min;
+ unsigned int presc;
double deviation;
+
+ presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1;
+
+ if (presc > TPIU_ACPR_MAX_SWOSCALER)
+ return false;
+
+ deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq));
+
+ if (deviation > SWO_MAX_FREQ_DEV)
+ return false;
+
+ *prescaler = presc;
+
+ return true;
+}
+
+static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed,
+ unsigned int traceclkin_freq, uint32_t *trace_freq,
+ uint16_t *prescaler)
+{
uint32_t divider;
+ unsigned int presc;
+ double deviation;
- min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div)));
+ for (divider = speed.min_div; divider <= speed.max_div; divider++) {
+ *trace_freq = speed.freq / divider;
+ presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1;
- for (divider = speed.min_div; divider < speed.max_div; divider++) {
- deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider)));
+ if (presc > TPIU_ACPR_MAX_SWOSCALER)
+ break;
- if (deviation < 0.03) {
- LOG_DEBUG("Found suitable frequency divider %u with deviation of "
- "%.02f %%.", divider, deviation);
+ deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq));
+
+ if (deviation <= SWO_MAX_FREQ_DEV) {
+ *prescaler = presc;
return true;
}
-
- if (deviation < min)
- min = deviation;
}
- LOG_ERROR("Selected trace frequency is not supported by the device. "
- "Please choose a different trace frequency.");
- LOG_ERROR("Maximum permitted deviation is 3.00 %%, but only %.02f %% "
- "could be achieved.", min * 100);
-
return false;
}
static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler)
{
int ret;
uint32_t buffer_size;
struct jaylink_swo_speed speed;
+ uint32_t divider;
+ uint32_t min_freq;
+ uint32_t max_freq;
+
+ trace_enabled = enabled;
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) {
+ if (!enabled)
+ return ERROR_OK;
+
LOG_ERROR("Trace capturing is not supported by the device.");
return ERROR_FAIL;
}
- if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
- LOG_ERROR("Selected pin protocol is not supported.");
- return ERROR_FAIL;
- }
-
- trace_enabled = enabled;
-
ret = jaylink_swo_stop(devh);
if (ret != JAYLINK_OK) {
@@ -1334,6 +1352,11 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
return ERROR_OK;
}
+ if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
+ LOG_ERROR("Selected pin protocol is not supported.");
+ return ERROR_FAIL;
+ }
+
buffer_size = calculate_trace_buffer_size();
if (!buffer_size) {
@@ -1349,13 +1372,45 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
return ERROR_FAIL;
}
- if (!*trace_freq)
- *trace_freq = speed.freq / speed.min_div;
+ if (*trace_freq > 0) {
+ divider = speed.freq / *trace_freq;
+ min_freq = speed.freq / speed.max_div;
+ max_freq = speed.freq / speed.min_div;
- if (!check_trace_freq(speed, *trace_freq))
- return ERROR_FAIL;
+ if (*trace_freq > max_freq) {
+ LOG_INFO("Given SWO frequency too high, using %u Hz instead.",
+ max_freq);
+ *trace_freq = max_freq;
+ } else if (*trace_freq < min_freq) {
+ LOG_INFO("Given SWO frequency too low, using %u Hz instead.",
+ min_freq);
+ *trace_freq = min_freq;
+ } else if (*trace_freq != speed.freq / divider) {
+ *trace_freq = speed.freq / divider;
- LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size);
+ LOG_INFO("Given SWO frequency is not supported by the device, "
+ "using %u Hz instead.", *trace_freq);
+ }
+
+ if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq,
+ prescaler)) {
+ LOG_ERROR("SWO frequency is not suitable. Please choose a "
+ "different frequency or use auto-detection.");
+ return ERROR_FAIL;
+ }
+ } else {
+ LOG_INFO("Trying to auto-detect SWO frequency.");
+
+ if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq,
+ prescaler)) {
+ LOG_ERROR("Maximum permitted frequency deviation of %.02f %% "
+ "could not be achieved.", SWO_MAX_FREQ_DEV);
+ LOG_ERROR("Auto-detection of SWO frequency failed.");
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("Using SWO frequency of %u Hz.", *trace_freq);
+ }
ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq,
buffer_size);
@@ -1365,6 +1420,9 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
return ERROR_FAIL;
}
+ LOG_DEBUG("Using %u bytes device memory for trace capturing.",
+ buffer_size);
+
/*
* Adjust the SWD transaction buffer size as starting SWO capturing
* allocates device internal memory.
@@ -1470,7 +1528,7 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
} else if (CMD_ARGC == 1) {
str = CMD_ARGV[0];
- if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || \
+ if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' ||
str[8] != ':' || str[11] != ':' || str[14] != ':')) {
command_print(CMD, "Invalid MAC address format.");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -2212,17 +2270,24 @@ static const struct swd_driver jlink_swd = {
static const char * const jlink_transports[] = { "jtag", "swd", NULL };
-struct jtag_interface jlink_interface = {
- .name = "jlink",
- .commands = jlink_command_handlers,
- .transports = jlink_transports,
- .swd = &jlink_swd,
+static struct jtag_interface jlink_interface = {
.execute_queue = &jlink_execute_queue,
- .speed = &jlink_speed,
- .speed_div = &jlink_speed_div,
- .khz = &jlink_khz,
+};
+
+struct adapter_driver jlink_adapter_driver = {
+ .name = "jlink",
+ .transports = jlink_transports,
+ .commands = jlink_command_handlers,
+
.init = &jlink_init,
.quit = &jlink_quit,
+ .reset = &jlink_reset_safe,
+ .speed = &jlink_speed,
+ .khz = &jlink_khz,
+ .speed_div = &jlink_speed_div,
.config_trace = &config_trace,
.poll_trace = &poll_trace,
+
+ .jtag_ops = &jlink_interface,
+ .swd_ops = &jlink_swd,
};
diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c
index 1033cedb2..a5a95a5a3 100644
--- a/src/jtag/drivers/jtag_vpi.c
+++ b/src/jtag/drivers/jtag_vpi.c
@@ -33,6 +33,8 @@
#include
#endif
+#include
+
#define NO_TAP_SHIFT 0
#define TAP_SHIFT 1
@@ -47,34 +49,160 @@
#define CMD_SCAN_CHAIN_FLIP_TMS 3
#define CMD_STOP_SIMU 4
-int server_port = SERVER_PORT;
-char *server_address;
+/* jtag_vpi server port and address to connect to */
+static int server_port = SERVER_PORT;
+static char *server_address;
-int sockfd;
-struct sockaddr_in serv_addr;
+/* Send CMD_STOP_SIMU to server when OpenOCD exits? */
+static bool stop_sim_on_exit;
+static int sockfd;
+static struct sockaddr_in serv_addr;
+
+/* One jtag_vpi "packet" as sent over a TCP channel. */
struct vpi_cmd {
- int cmd;
+ union {
+ uint32_t cmd;
+ unsigned char cmd_buf[4];
+ };
unsigned char buffer_out[XFERT_MAX_SIZE];
unsigned char buffer_in[XFERT_MAX_SIZE];
- int length;
- int nb_bits;
+ union {
+ uint32_t length;
+ unsigned char length_buf[4];
+ };
+ union {
+ uint32_t nb_bits;
+ unsigned char nb_bits_buf[4];
+ };
};
+static char *jtag_vpi_cmd_to_str(int cmd_num)
+{
+ switch (cmd_num) {
+ case CMD_RESET:
+ return "CMD_RESET";
+ case CMD_TMS_SEQ:
+ return "CMD_TMS_SEQ";
+ case CMD_SCAN_CHAIN:
+ return "CMD_SCAN_CHAIN";
+ case CMD_SCAN_CHAIN_FLIP_TMS:
+ return "CMD_SCAN_CHAIN_FLIP_TMS";
+ case CMD_STOP_SIMU:
+ return "CMD_STOP_SIMU";
+ default:
+ return "";
+ }
+}
+
static int jtag_vpi_send_cmd(struct vpi_cmd *vpi)
{
- int retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd));
- if (retval <= 0)
- return ERROR_FAIL;
+ int retval;
+ /* Optional low-level JTAG debug */
+ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) {
+ if (vpi->nb_bits > 0) {
+ /* command with a non-empty data payload */
+ char *char_buf = buf_to_str(vpi->buffer_out,
+ (vpi->nb_bits > DEBUG_JTAG_IOZ)
+ ? DEBUG_JTAG_IOZ
+ : vpi->nb_bits,
+ 16);
+ LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, "
+ "length=%" PRIu32 ", "
+ "nb_bits=%" PRIu32 ", "
+ "buf_out=0x%s%s",
+ jtag_vpi_cmd_to_str(vpi->cmd),
+ vpi->length,
+ vpi->nb_bits,
+ char_buf,
+ (vpi->nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : "");
+ free(char_buf);
+ } else {
+ /* command without data payload */
+ LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, "
+ "length=%" PRIu32 ", "
+ "nb_bits=%" PRIu32,
+ jtag_vpi_cmd_to_str(vpi->cmd),
+ vpi->length,
+ vpi->nb_bits);
+ }
+ }
+
+ /* Use little endian when transmitting/receiving jtag_vpi cmds.
+ The choice of little endian goes against usual networking conventions
+ but is intentional to remain compatible with most older OpenOCD builds
+ (i.e. builds on little-endian platforms). */
+ h_u32_to_le(vpi->cmd_buf, vpi->cmd);
+ h_u32_to_le(vpi->length_buf, vpi->length);
+ h_u32_to_le(vpi->nb_bits_buf, vpi->nb_bits);
+
+retry_write:
+ retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd));
+
+ if (retval < 0) {
+ /* Account for the case when socket write is interrupted. */
+#ifdef _WIN32
+ int wsa_err = WSAGetLastError();
+ if (wsa_err == WSAEINTR)
+ goto retry_write;
+#else
+ if (errno == EINTR)
+ goto retry_write;
+#endif
+ /* Otherwise this is an error using the socket, most likely fatal
+ for the connection. B*/
+ log_socket_error("jtag_vpi xmit");
+ /* TODO: Clean way how adapter drivers can report fatal errors
+ to upper layers of OpenOCD and let it perform an orderly shutdown? */
+ exit(-1);
+ } else if (retval < (int)sizeof(struct vpi_cmd)) {
+ /* This means we could not send all data, which is most likely fatal
+ for the jtag_vpi connection (the underlying TCP connection likely not
+ usable anymore) */
+ LOG_ERROR("Could not send all data through jtag_vpi connection.");
+ exit(-1);
+ }
+
+ /* Otherwise the packet has been sent successfully. */
return ERROR_OK;
}
static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
{
- int retval = read_socket(sockfd, vpi, sizeof(struct vpi_cmd));
- if (retval < (int)sizeof(struct vpi_cmd))
- return ERROR_FAIL;
+ unsigned bytes_buffered = 0;
+ while (bytes_buffered < sizeof(struct vpi_cmd)) {
+ int bytes_to_receive = sizeof(struct vpi_cmd) - bytes_buffered;
+ int retval = read_socket(sockfd, ((char *)vpi) + bytes_buffered, bytes_to_receive);
+ if (retval < 0) {
+#ifdef _WIN32
+ int wsa_err = WSAGetLastError();
+ if (wsa_err == WSAEINTR) {
+ /* socket read interrupted by WSACancelBlockingCall() */
+ continue;
+ }
+#else
+ if (errno == EINTR) {
+ /* socket read interrupted by a signal */
+ continue;
+ }
+#endif
+ /* Otherwise, this is an error when accessing the socket. */
+ log_socket_error("jtag_vpi recv");
+ exit(-1);
+ } else if (retval == 0) {
+ /* Connection closed by the other side */
+ LOG_ERROR("Connection prematurely closed by jtag_vpi server.");
+ exit(-1);
+ }
+ /* Otherwise, we have successfully received some data */
+ bytes_buffered += retval;
+ }
+
+ /* Use little endian when transmitting/receiving jtag_vpi cmds. */
+ vpi->cmd = le_to_h_u32(vpi->cmd_buf);
+ vpi->length = le_to_h_u32(vpi->length_buf);
+ vpi->nb_bits = le_to_h_u32(vpi->nb_bits_buf);
return ERROR_OK;
}
@@ -87,6 +215,7 @@ static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
static int jtag_vpi_reset(int trst, int srst)
{
struct vpi_cmd vpi;
+ memset(&vpi, 0, sizeof(struct vpi_cmd));
vpi.cmd = CMD_RESET;
vpi.length = 0;
@@ -109,6 +238,7 @@ static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits)
struct vpi_cmd vpi;
int nb_bytes;
+ memset(&vpi, 0, sizeof(struct vpi_cmd));
nb_bytes = DIV_ROUND_UP(nb_bits, 8);
vpi.cmd = CMD_TMS_SEQ;
@@ -176,6 +306,8 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
struct vpi_cmd vpi;
int nb_bytes = DIV_ROUND_UP(nb_bits, 8);
+ memset(&vpi, 0, sizeof(struct vpi_cmd));
+
vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
if (bits)
@@ -194,6 +326,16 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
if (retval != ERROR_OK)
return retval;
+ /* Optional low-level JTAG debug */
+ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) {
+ char *char_buf = buf_to_str(vpi.buffer_in,
+ (nb_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : nb_bits,
+ 16);
+ LOG_DEBUG_IO("recvd JTAG VPI data: nb_bits=%d, buf_in=0x%s%s",
+ nb_bits, char_buf, (nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : "");
+ free(char_buf);
+ }
+
if (bits)
memcpy(bits, vpi.buffer_in, nb_bytes);
@@ -384,6 +526,11 @@ static int jtag_vpi_execute_queue(void)
case JTAG_SCAN:
retval = jtag_vpi_scan(cmd->cmd.scan);
break;
+ default:
+ LOG_ERROR("BUG: unknown JTAG command type 0x%X",
+ cmd->type);
+ retval = ERROR_FAIL;
+ break;
}
}
@@ -433,10 +580,28 @@ static int jtag_vpi_init(void)
return ERROR_OK;
}
+static int jtag_vpi_stop_simulation(void)
+{
+ struct vpi_cmd cmd;
+ memset(&cmd, 0, sizeof(struct vpi_cmd));
+ cmd.length = 0;
+ cmd.nb_bits = 0;
+ cmd.cmd = CMD_STOP_SIMU;
+ return jtag_vpi_send_cmd(&cmd);
+}
+
static int jtag_vpi_quit(void)
{
+ if (stop_sim_on_exit) {
+ if (jtag_vpi_stop_simulation() != ERROR_OK)
+ LOG_WARNING("jtag_vpi: failed to send \"stop simulation\" command");
+ }
+ if (close_socket(sockfd) != 0) {
+ LOG_WARNING("jtag_vpi: could not close jtag_vpi client socket");
+ log_socket_error("jtag_vpi");
+ }
free(server_address);
- return close(sockfd);
+ return ERROR_OK;
}
COMMAND_HANDLER(jtag_vpi_set_port)
@@ -466,31 +631,55 @@ COMMAND_HANDLER(jtag_vpi_set_address)
return ERROR_OK;
}
+COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("jtag_vpi_stop_sim_on_exit expects 1 argument (on|off)");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ } else {
+ COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit);
+ }
+ return ERROR_OK;
+}
+
static const struct command_registration jtag_vpi_command_handlers[] = {
{
.name = "jtag_vpi_set_port",
.handler = &jtag_vpi_set_port,
.mode = COMMAND_CONFIG,
.help = "set the port of the VPI server",
- .usage = "description_string",
+ .usage = "tcp_port_num",
},
{
.name = "jtag_vpi_set_address",
.handler = &jtag_vpi_set_address,
.mode = COMMAND_CONFIG,
.help = "set the address of the VPI server",
- .usage = "description_string",
+ .usage = "ipv4_addr",
+ },
+ {
+ .name = "jtag_vpi_stop_sim_on_exit",
+ .handler = &jtag_vpi_stop_sim_on_exit_handler,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure if simulation stop command shall be sent "
+ "before OpenOCD exits (default: off)",
+ .usage = "",
},
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface jtag_vpi_interface = {
- .name = "jtag_vpi",
+static struct jtag_interface jtag_vpi_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
- .commands = jtag_vpi_command_handlers,
+ .execute_queue = jtag_vpi_execute_queue,
+};
+
+struct adapter_driver jtag_vpi_adapter_driver = {
+ .name = "jtag_vpi",
.transports = jtag_only,
+ .commands = jtag_vpi_command_handlers,
.init = jtag_vpi_init,
.quit = jtag_vpi_quit,
- .execute_queue = jtag_vpi_execute_queue,
+
+ .jtag_ops = &jtag_vpi_interface,
};
diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c
index e3ad84d30..efb8da2cd 100644
--- a/src/jtag/drivers/kitprog.c
+++ b/src/jtag/drivers/kitprog.c
@@ -43,7 +43,7 @@
#include
#include
-#include "libusb_common.h"
+#include "libusb_helper.h"
#define VID 0x04b4
#define PID 0xf139
@@ -95,7 +95,7 @@
struct kitprog {
hid_device *hid_handle;
- struct jtag_libusb_device_handle *usb_handle;
+ struct libusb_device_handle *usb_handle;
uint16_t packet_size;
uint16_t packet_index;
uint8_t *packet_buffer;
@@ -280,7 +280,7 @@ static int kitprog_usb_open(void)
const uint16_t pids[] = { PID, 0 };
if (jtag_libusb_open(vids, pids, kitprog_serial,
- &kitprog_handle->usb_handle) != ERROR_OK) {
+ &kitprog_handle->usb_handle, NULL) != ERROR_OK) {
LOG_ERROR("Failed to open or find the device");
return ERROR_FAIL;
}
@@ -311,7 +311,7 @@ static int kitprog_usb_open(void)
}
/* Claim the KitProg Programmer (bulk transfer) interface */
- if (jtag_libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) {
+ if (libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) {
LOG_ERROR("Failed to claim KitProg Programmer (bulk transfer) interface");
return ERROR_FAIL;
}
@@ -358,7 +358,7 @@ static int kitprog_get_version(void)
unsigned char command[3] = {HID_TYPE_START | HID_TYPE_WRITE, 0x00, HID_COMMAND_VERSION};
unsigned char data[64];
- ret = kitprog_hid_command(command, sizeof command, data, sizeof data);
+ ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data));
if (ret != ERROR_OK)
return ret;
@@ -376,7 +376,7 @@ static int kitprog_get_millivolts(void)
unsigned char command[3] = {HID_TYPE_START | HID_TYPE_READ, 0x00, HID_COMMAND_POWER};
unsigned char data[64];
- ret = kitprog_hid_command(command, sizeof command, data, sizeof data);
+ ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data));
if (ret != ERROR_OK)
return ret;
@@ -603,7 +603,7 @@ static int kitprog_generic_acquire(void)
* will take the Cortex-M3 out of reset and enable debugging.
*/
for (int i = 0; i < 2; i++) {
- for (uint8_t j = 0; j < sizeof devices && acquire_count == i; j++) {
+ for (uint8_t j = 0; j < sizeof(devices) && acquire_count == i; j++) {
retval = kitprog_acquire_psoc(devices[j], ACQUIRE_MODE_RESET, 3);
if (retval != ERROR_OK) {
LOG_DEBUG("Aquisition function failed for device 0x%02x.", devices[j]);
@@ -731,14 +731,14 @@ static int kitprog_swd_run_queue(void)
}
}
- ret = jtag_libusb_bulk_write(kitprog_handle->usb_handle,
- BULK_EP_OUT, (char *)buffer, write_count, 0);
- if (ret > 0) {
- queued_retval = ERROR_OK;
- } else {
+ if (jtag_libusb_bulk_write(kitprog_handle->usb_handle,
+ BULK_EP_OUT, (char *)buffer,
+ write_count, 0, &ret)) {
LOG_ERROR("Bulk write failed");
queued_retval = ERROR_FAIL;
break;
+ } else {
+ queued_retval = ERROR_OK;
}
/* KitProg firmware does not send a zero length packet
@@ -754,18 +754,17 @@ static int kitprog_swd_run_queue(void)
if (read_count % 64 == 0)
read_count_workaround = read_count;
- ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle,
+ if (jtag_libusb_bulk_read(kitprog_handle->usb_handle,
BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer,
- read_count_workaround, 1000);
- if (ret > 0) {
+ read_count_workaround, 1000, &ret)) {
+ LOG_ERROR("Bulk read failed");
+ queued_retval = ERROR_FAIL;
+ break;
+ } else {
/* Handle garbage data by offsetting the initial read index */
if ((unsigned int)ret > read_count)
read_index = ret - read_count;
queued_retval = ERROR_OK;
- } else {
- LOG_ERROR("Bulk read failed");
- queued_retval = ERROR_FAIL;
- break;
}
for (int i = 0; i < pending_transfer_count; i++) {
@@ -819,11 +818,16 @@ static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
/*************** jtag lowlevel functions ********************/
-static void kitprog_execute_reset(struct jtag_command *cmd)
+static int kitprog_reset(int trst, int srst)
{
int retval = ERROR_OK;
- if (cmd->cmd.reset->srst == 1) {
+ if (trst == 1) {
+ LOG_ERROR("KitProg: Interface has no TRST");
+ return ERROR_FAIL;
+ }
+
+ if (srst == 1) {
retval = kitprog_reset_target();
/* Since the previous command also disables SWCLK output, we need to send an
* SWD bus reset command to re-enable it. For some reason, running
@@ -836,38 +840,7 @@ static void kitprog_execute_reset(struct jtag_command *cmd)
if (retval != ERROR_OK)
LOG_ERROR("KitProg: Interface reset failed");
-}
-
-static void kitprog_execute_sleep(struct jtag_command *cmd)
-{
- jtag_sleep(cmd->cmd.sleep->us);
-}
-
-static void kitprog_execute_command(struct jtag_command *cmd)
-{
- switch (cmd->type) {
- case JTAG_RESET:
- kitprog_execute_reset(cmd);
- break;
- case JTAG_SLEEP:
- kitprog_execute_sleep(cmd);
- break;
- default:
- LOG_ERROR("BUG: unknown JTAG command type encountered");
- exit(-1);
- }
-}
-
-static int kitprog_execute_queue(void)
-{
- struct jtag_command *cmd = jtag_command_queue;
-
- while (cmd != NULL) {
- kitprog_execute_command(cmd);
- cmd = cmd->next;
- }
-
- return ERROR_OK;
+ return retval;
}
COMMAND_HANDLER(kitprog_handle_info_command)
@@ -961,12 +934,14 @@ static const struct swd_driver kitprog_swd = {
static const char * const kitprog_transports[] = { "swd", NULL };
-struct jtag_interface kitprog_interface = {
+struct adapter_driver kitprog_adapter_driver = {
.name = "kitprog",
- .commands = kitprog_command_handlers,
.transports = kitprog_transports,
- .swd = &kitprog_swd,
- .execute_queue = kitprog_execute_queue,
+ .commands = kitprog_command_handlers,
+
.init = kitprog_init,
- .quit = kitprog_quit
+ .quit = kitprog_quit,
+ .reset = kitprog_reset,
+
+ .swd_ops = &kitprog_swd,
};
diff --git a/src/jtag/drivers/libusb0_common.c b/src/jtag/drivers/libusb0_common.c
deleted file mode 100644
index 14a8b61cc..000000000
--- a/src/jtag/drivers/libusb0_common.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 by Zachary T Welch *
- * *
- * Copyright (C) 2011 by Mauro Gamba *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see . *
- ***************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "log.h"
-#include "libusb0_common.h"
-
-static bool jtag_libusb_match(struct jtag_libusb_device *dev,
- const uint16_t vids[], const uint16_t pids[])
-{
- for (unsigned i = 0; vids[i]; i++) {
- if (dev->descriptor.idVendor == vids[i] &&
- dev->descriptor.idProduct == pids[i]) {
- return true;
- }
- }
- return false;
-}
-
-/* Returns true if the string descriptor indexed by str_index in device matches string */
-static bool string_descriptor_equal(usb_dev_handle *device, uint8_t str_index,
- const char *string)
-{
- int retval;
- bool matched;
- char desc_string[256+1]; /* Max size of string descriptor */
-
- if (str_index == 0)
- return false;
-
- retval = usb_get_string_simple(device, str_index,
- desc_string, sizeof(desc_string)-1);
- if (retval < 0) {
- LOG_ERROR("usb_get_string_simple() failed with %d", retval);
- return false;
- }
-
- /* Null terminate descriptor string in case it needs to be logged. */
- desc_string[sizeof(desc_string)-1] = '\0';
-
- matched = strncmp(string, desc_string, sizeof(desc_string)) == 0;
- if (!matched)
- LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'",
- desc_string, string);
- return matched;
-}
-
-int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
- const char *serial,
- struct jtag_libusb_device_handle **out)
-{
- int retval = ERROR_FAIL;
- bool serial_mismatch = false;
- struct jtag_libusb_device_handle *libusb_handle;
- usb_init();
-
- usb_find_busses();
- usb_find_devices();
-
- struct usb_bus *busses = usb_get_busses();
- for (struct usb_bus *bus = busses; bus; bus = bus->next) {
- for (struct usb_device *dev = bus->devices;
- dev; dev = dev->next) {
- if (!jtag_libusb_match(dev, vids, pids))
- continue;
-
- libusb_handle = usb_open(dev);
- if (NULL == libusb_handle) {
- LOG_ERROR("usb_open() failed with %s", usb_strerror());
- continue;
- }
-
- /* Device must be open to use libusb_get_string_descriptor_ascii. */
- if (serial != NULL &&
- !string_descriptor_equal(libusb_handle, dev->descriptor.iSerialNumber, serial)) {
- serial_mismatch = true;
- usb_close(libusb_handle);
- continue;
- }
- *out = libusb_handle;
- retval = ERROR_OK;
- serial_mismatch = false;
- break;
- }
- }
-
- if (serial_mismatch)
- LOG_INFO("No device matches the serial string");
-
- return retval;
-}
-
-void jtag_libusb_close(jtag_libusb_device_handle *dev)
-{
- /* Close device */
- usb_close(dev);
-}
-
-int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType,
- uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
- uint16_t size, unsigned int timeout)
-{
- int transferred = 0;
-
- transferred = usb_control_msg(dev, requestType, request, wValue, wIndex,
- bytes, size, timeout);
-
- if (transferred < 0)
- transferred = 0;
-
- return transferred;
-}
-
-int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
- int size, int timeout)
-{
- return usb_bulk_write(dev, ep, bytes, size, timeout);
-}
-
-int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
- int size, int timeout)
-{
- return usb_bulk_read(dev, ep, bytes, size, timeout);
-}
-
-int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
- int configuration)
-{
- struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
-
- return usb_set_configuration(devh,
- udev->config[configuration].bConfigurationValue);
-}
-
-int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
- unsigned int *usb_read_ep,
- unsigned int *usb_write_ep,
- int bclass, int subclass, int protocol, int trans_type)
-{
- struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
- struct usb_interface *iface = udev->config->interface;
- struct usb_interface_descriptor *desc = iface->altsetting;
-
- *usb_read_ep = *usb_write_ep = 0;
-
- for (int i = 0; i < desc->bNumEndpoints; i++) {
- if ((bclass > 0 && desc->bInterfaceClass != bclass) ||
- (subclass > 0 && desc->bInterfaceSubClass != subclass) ||
- (protocol > 0 && desc->bInterfaceProtocol != protocol) ||
- (trans_type > 0 && (desc->endpoint[i].bmAttributes & 0x3) != trans_type))
- continue;
-
- uint8_t epnum = desc->endpoint[i].bEndpointAddress;
- bool is_input = epnum & 0x80;
- LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum);
- if (is_input)
- *usb_read_ep = epnum;
- else
- *usb_write_ep = epnum;
-
- if (*usb_read_ep && *usb_write_ep) {
- LOG_DEBUG("Claiming interface %d", (int)desc->bInterfaceNumber);
- usb_claim_interface(devh, (int)desc->bInterfaceNumber);
- return ERROR_OK;
- }
- }
-
- return ERROR_FAIL;
-}
-
-int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
-{
- if (!dev)
- return ERROR_FAIL;
-
- *pid = dev->descriptor.idProduct;
- return ERROR_OK;
-}
diff --git a/src/jtag/drivers/libusb0_common.h b/src/jtag/drivers/libusb0_common.h
deleted file mode 100644
index 676f43acd..000000000
--- a/src/jtag/drivers/libusb0_common.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 by Zachary T Welch *
- * *
- * Copyright (C) 2011 by Mauro Gamba *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see . *
- ***************************************************************************/
-
-#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H
-#define OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H
-
-#include
-
-#define jtag_libusb_device usb_device
-#define jtag_libusb_device_handle usb_dev_handle
-#define jtag_libusb_device_descriptor usb_device_descriptor
-#define jtag_libusb_interface usb_interface
-#define jtag_libusb_interface_descriptor usb_interface_descriptor
-#define jtag_libusb_endpoint_descriptor usb_endpoint_descriptor
-#define jtag_libusb_config_descriptor usb_config_descriptor
-
-#define jtag_libusb_reset_device(dev) usb_reset(dev)
-#define jtag_libusb_get_device(devh) usb_device(devh)
-
-/* make some defines compatible to libusb1 */
-#define LIBUSB_REQUEST_TYPE_VENDOR USB_TYPE_VENDOR
-#define LIBUSB_RECIPIENT_DEVICE USB_RECIP_DEVICE
-#define LIBUSB_ENDPOINT_OUT USB_ENDPOINT_OUT
-#define LIBUSB_ENDPOINT_IN USB_ENDPOINT_IN
-#define LIBUSB_TRANSFER_TYPE_BULK USB_ENDPOINT_TYPE_BULK
-
-static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh,
- int iface)
-{
- return usb_claim_interface(devh, iface);
-};
-
-static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh,
- int iface)
-{
- return usb_release_interface(devh, iface);
-}
-
-int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
- const char *serial,
- struct jtag_libusb_device_handle **out);
-void jtag_libusb_close(jtag_libusb_device_handle *dev);
-int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
- uint8_t requestType, uint8_t request, uint16_t wValue,
- uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout);
-int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep,
- char *bytes, int size, int timeout);
-int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
- char *bytes, int size, int timeout);
-int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
- int configuration);
-int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
- unsigned int *usb_read_ep,
- unsigned int *usb_write_ep,
- int bclass, int subclass, int protocol, int trans_type);
-int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
-
-#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H */
diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb_helper.c
similarity index 70%
rename from src/jtag/drivers/libusb1_common.c
rename to src/jtag/drivers/libusb_helper.c
index d96ac7692..184882abc 100644
--- a/src/jtag/drivers/libusb1_common.c
+++ b/src/jtag/drivers/libusb_helper.c
@@ -21,7 +21,7 @@
#include "config.h"
#endif
#include
-#include "libusb1_common.h"
+#include "libusb_helper.h"
#include "log.h"
/*
@@ -33,7 +33,32 @@
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
static libusb_device **devs; /**< The usb device list **/
-static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc,
+static int jtag_libusb_error(int err)
+{
+ switch (err) {
+ case LIBUSB_SUCCESS:
+ return ERROR_OK;
+ case LIBUSB_ERROR_TIMEOUT:
+ return ERROR_TIMEOUT_REACHED;
+ case LIBUSB_ERROR_IO:
+ case LIBUSB_ERROR_INVALID_PARAM:
+ case LIBUSB_ERROR_ACCESS:
+ case LIBUSB_ERROR_NO_DEVICE:
+ case LIBUSB_ERROR_NOT_FOUND:
+ case LIBUSB_ERROR_BUSY:
+ case LIBUSB_ERROR_OVERFLOW:
+ case LIBUSB_ERROR_PIPE:
+ case LIBUSB_ERROR_INTERRUPTED:
+ case LIBUSB_ERROR_NO_MEM:
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ case LIBUSB_ERROR_OTHER:
+ return ERROR_FAIL;
+ default:
+ return ERROR_FAIL;
+ }
+}
+
+static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
const uint16_t vids[], const uint16_t pids[])
{
for (unsigned i = 0; vids[i]; i++) {
@@ -98,14 +123,45 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
return matched;
}
+static bool jtag_libusb_match_serial(libusb_device_handle *device,
+ struct libusb_device_descriptor *dev_desc, const char *serial,
+ adapter_get_alternate_serial_fn adapter_get_alternate_serial)
+{
+ if (string_descriptor_equal(device, dev_desc->iSerialNumber, serial))
+ return true;
+
+ /* check the alternate serial helper */
+ if (!adapter_get_alternate_serial)
+ return false;
+
+ /* get the alternate serial */
+ char *alternate_serial = adapter_get_alternate_serial(device, dev_desc);
+
+ /* check possible failures */
+ if (alternate_serial == NULL)
+ return false;
+
+ /* then compare and free the alternate serial */
+ bool match = false;
+ if (strcmp(serial, alternate_serial) == 0)
+ match = true;
+ else
+ LOG_DEBUG("Device alternate serial number '%s' doesn't match requested serial '%s'",
+ alternate_serial, serial);
+
+ free(alternate_serial);
+ return match;
+}
+
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial,
- struct jtag_libusb_device_handle **out)
+ struct libusb_device_handle **out,
+ adapter_get_alternate_serial_fn adapter_get_alternate_serial)
{
int cnt, idx, errCode;
int retval = ERROR_FAIL;
bool serial_mismatch = false;
- struct jtag_libusb_device_handle *libusb_handle = NULL;
+ struct libusb_device_handle *libusb_handle = NULL;
if (libusb_init(&jtag_libusb_context) < 0)
return ERROR_FAIL;
@@ -118,7 +174,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
if (libusb_get_device_descriptor(devs[idx], &dev_desc) != 0)
continue;
- if (!jtag_libusb_match(&dev_desc, vids, pids))
+ if (!jtag_libusb_match_ids(&dev_desc, vids, pids))
continue;
if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
@@ -134,7 +190,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
/* Device must be open to use libusb_get_string_descriptor_ascii. */
if (serial != NULL &&
- !string_descriptor_equal(libusb_handle, dev_desc.iSerialNumber, serial)) {
+ !jtag_libusb_match_serial(libusb_handle, &dev_desc, serial, adapter_get_alternate_serial)) {
serial_mismatch = true;
libusb_close(libusb_handle);
continue;
@@ -152,10 +208,13 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
if (serial_mismatch)
LOG_INFO("No device matches the serial string");
+ if (retval != ERROR_OK)
+ libusb_exit(jtag_libusb_context);
+
return retval;
}
-void jtag_libusb_close(jtag_libusb_device_handle *dev)
+void jtag_libusb_close(struct libusb_device_handle *dev)
{
/* Close device */
libusb_close(dev);
@@ -163,7 +222,7 @@ void jtag_libusb_close(jtag_libusb_device_handle *dev)
libusb_exit(jtag_libusb_context);
}
-int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType,
+int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t requestType,
uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
uint16_t size, unsigned int timeout)
{
@@ -178,30 +237,44 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t request
return transferred;
}
-int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
- int size, int timeout)
+int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes,
+ int size, int timeout, int *transferred)
{
- int transferred = 0;
+ int ret;
- libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
- &transferred, timeout);
- return transferred;
+ *transferred = 0;
+
+ ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
+ transferred, timeout);
+ if (ret != LIBUSB_SUCCESS) {
+ LOG_ERROR("libusb_bulk_write error: %s", libusb_error_name(ret));
+ return jtag_libusb_error(ret);
+ }
+
+ return ERROR_OK;
}
-int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
- int size, int timeout)
+int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, char *bytes,
+ int size, int timeout, int *transferred)
{
- int transferred = 0;
+ int ret;
- libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
- &transferred, timeout);
- return transferred;
+ *transferred = 0;
+
+ ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
+ transferred, timeout);
+ if (ret != LIBUSB_SUCCESS) {
+ LOG_ERROR("libusb_bulk_read error: %s", libusb_error_name(ret));
+ return jtag_libusb_error(ret);
+ }
+
+ return ERROR_OK;
}
-int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
+int jtag_libusb_set_configuration(struct libusb_device_handle *devh,
int configuration)
{
- struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
+ struct libusb_device *udev = libusb_get_device(devh);
int retCode = -99;
struct libusb_config_descriptor *config = NULL;
@@ -226,12 +299,12 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
return retCode;
}
-int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
+int jtag_libusb_choose_interface(struct libusb_device_handle *devh,
unsigned int *usb_read_ep,
unsigned int *usb_write_ep,
int bclass, int subclass, int protocol, int trans_type)
{
- struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
+ struct libusb_device *udev = libusb_get_device(devh);
const struct libusb_interface *inter;
const struct libusb_interface_descriptor *interdesc;
const struct libusb_endpoint_descriptor *epdesc;
@@ -278,7 +351,7 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
return ERROR_FAIL;
}
-int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
+int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid)
{
struct libusb_device_descriptor dev_desc;
diff --git a/src/jtag/drivers/libusb1_common.h b/src/jtag/drivers/libusb_helper.h
similarity index 61%
rename from src/jtag/drivers/libusb1_common.h
rename to src/jtag/drivers/libusb_helper.h
index 7c73d29a4..74bb23c52 100644
--- a/src/jtag/drivers/libusb1_common.h
+++ b/src/jtag/drivers/libusb_helper.h
@@ -17,46 +17,29 @@
* along with this program. If not, see . *
***************************************************************************/
-#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H
-#define OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H
+#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H
+#define OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H
#include
-#define jtag_libusb_device libusb_device
-#define jtag_libusb_device_handle libusb_device_handle
-#define jtag_libusb_device_descriptor libusb_device_descriptor
-#define jtag_libusb_interface libusb_interface
-#define jtag_libusb_interface_descriptor libusb_interface_descriptor
-#define jtag_libusb_endpoint_descriptor libusb_endpoint_descriptor
-#define jtag_libusb_config_descriptor libusb_config_descriptor
-
-#define jtag_libusb_reset_device(dev) libusb_reset_device(dev)
-#define jtag_libusb_get_device(devh) libusb_get_device(devh)
-
-static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh,
- int iface)
-{
- return libusb_claim_interface(devh, iface);
-};
-
-static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh,
- int iface)
-{
- return libusb_release_interface(devh, iface);
-}
+/* this callback should return a non NULL value only when the serial could not
+ * be retrieved by the standard 'libusb_get_string_descriptor_ascii' */
+typedef char * (*adapter_get_alternate_serial_fn)(libusb_device_handle *device,
+ struct libusb_device_descriptor *dev_desc);
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial,
- struct jtag_libusb_device_handle **out);
-void jtag_libusb_close(jtag_libusb_device_handle *dev);
-int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
+ struct libusb_device_handle **out,
+ adapter_get_alternate_serial_fn adapter_get_alternate_serial);
+void jtag_libusb_close(struct libusb_device_handle *dev);
+int jtag_libusb_control_transfer(struct libusb_device_handle *dev,
uint8_t requestType, uint8_t request, uint16_t wValue,
uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout);
-int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep,
- char *bytes, int size, int timeout);
-int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
- char *bytes, int size, int timeout);
-int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
+int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep,
+ char *bytes, int size, int timeout, int *transferred);
+int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep,
+ char *bytes, int size, int timeout, int *transferred);
+int jtag_libusb_set_configuration(struct libusb_device_handle *devh,
int configuration);
/**
* Find the first interface optionally matching class, subclass and
@@ -72,10 +55,10 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
* @param trans_type `bmAttributes Bits 0..1 Transfer type` to match, or -1 to ignore this field.
* @returns Returns ERROR_OK on success, ERROR_FAIL otherwise.
*/
-int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
+int jtag_libusb_choose_interface(struct libusb_device_handle *devh,
unsigned int *usb_read_ep,
unsigned int *usb_write_ep,
int bclass, int subclass, int protocol, int trans_type);
-int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
+int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid);
-#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H */
+#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H */
diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c
index c0d883bf5..7488d9dd8 100644
--- a/src/jtag/drivers/mpsse.c
+++ b/src/jtag/drivers/mpsse.c
@@ -890,6 +890,7 @@ int mpsse_flush(struct mpsse_ctx *ctx)
/* Polling loop, more or less taken from libftdi */
int64_t start = timeval_ms();
+ int64_t warn_after = 2000;
while (!write_result.done || !read_result.done) {
struct timeval timeout_usb;
@@ -913,9 +914,11 @@ int mpsse_flush(struct mpsse_ctx *ctx)
}
}
- if (timeval_ms() - start > 2000) {
- LOG_ERROR("Timed out handling USB events in mpsse_flush().");
- break;
+ int64_t now = timeval_ms();
+ if (now - start > warn_after) {
+ LOG_WARNING("Haven't made progress in mpsse_flush() for %" PRId64
+ "ms.", now - start);
+ warn_after *= 2;
}
}
diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c
index 5f352af89..bb223f417 100644
--- a/src/jtag/drivers/opendous.c
+++ b/src/jtag/drivers/opendous.c
@@ -32,7 +32,7 @@
#include
#include
-#include "libusb_common.h"
+#include "libusb_helper.h"
#include
#include
@@ -134,7 +134,7 @@ static void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_co
/* opendous lowlevel functions */
struct opendous_jtag {
- struct jtag_libusb_device_handle *usb_handle;
+ struct libusb_device_handle *usb_handle;
};
static struct opendous_jtag *opendous_usb_open(void);
@@ -234,13 +234,19 @@ static const struct command_registration opendous_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface opendous_interface = {
+static struct jtag_interface opendous_interface = {
+ .execute_queue = opendous_execute_queue,
+};
+
+struct adapter_driver opendous_adapter_driver = {
.name = "opendous",
.transports = jtag_only,
.commands = opendous_command_handlers,
- .execute_queue = opendous_execute_queue,
+
.init = opendous_init,
.quit = opendous_quit,
+
+ .jtag_ops = &opendous_interface,
};
static int opendous_execute_queue(void)
@@ -253,7 +259,7 @@ static int opendous_execute_queue(void)
while (cmd != NULL) {
switch (cmd->type) {
case JTAG_RUNTEST:
- LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \
+ LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles,
cmd->cmd.runtest->end_state);
if (cmd->cmd.runtest->end_state != -1)
@@ -270,8 +276,8 @@ static int opendous_execute_queue(void)
break;
case JTAG_PATHMOVE:
- LOG_DEBUG_IO("pathmove: %i states, end in %i", \
- cmd->cmd.pathmove->num_states, \
+ LOG_DEBUG_IO("pathmove: %i states, end in %i",
+ cmd->cmd.pathmove->num_states,
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path);
@@ -708,12 +714,12 @@ struct opendous_jtag *opendous_usb_open(void)
{
struct opendous_jtag *result;
- struct jtag_libusb_device_handle *devh;
- if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh) != ERROR_OK)
+ struct libusb_device_handle *devh;
+ if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK)
return NULL;
jtag_libusb_set_configuration(devh, 0);
- jtag_libusb_claim_interface(devh, 0);
+ libusb_claim_interface(devh, 0);
result = malloc(sizeof(*result));
result->usb_handle = devh;
@@ -764,8 +770,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length)
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
} else {
- result = jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, \
- (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
+ jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT,
+ (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result);
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("USB write end: %d bytes", result);
@@ -791,8 +797,8 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag)
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
} else {
- result = jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT,
- (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
+ jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT,
+ (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result);
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("USB read end: %d bytes", result);
diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c
index 7a3aa2337..7eab5c130 100644
--- a/src/jtag/drivers/openjtag.c
+++ b/src/jtag/drivers/openjtag.c
@@ -45,7 +45,7 @@
#include
#include
-#include "libusb_common.h"
+#include "libusb_helper.h"
static enum {
OPENJTAG_VARIANT_STANDARD,
@@ -111,7 +111,7 @@ static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE];
static struct openjtag_scan_result openjtag_scan_result_buffer[OPENJTAG_MAX_PENDING_RESULTS];
static int openjtag_scan_result_count;
-static jtag_libusb_device_handle *usbh;
+static struct libusb_device_handle *usbh;
/* CY7C65215 model only */
#define CY7C65215_JTAG_REQUEST 0x40 /* bmRequestType: vendor host-to-device */
@@ -229,7 +229,7 @@ static int openjtag_buf_write_standard(
return ERROR_JTAG_DEVICE_ERROR;
}
- *bytes_written += retval;
+ *bytes_written = retval;
return ERROR_OK;
}
@@ -256,10 +256,9 @@ static int openjtag_buf_write_cy7c65215(
return ERROR_JTAG_DEVICE_ERROR;
}
- ret = jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
- CY7C65215_USB_TIMEOUT);
- if (ret < 0) {
- LOG_ERROR("bulk write failed, error %d", ret);
+ if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
+ CY7C65215_USB_TIMEOUT, &ret)) {
+ LOG_ERROR("bulk write failed, error");
return ERROR_JTAG_DEVICE_ERROR;
}
*bytes_written = ret;
@@ -324,10 +323,9 @@ static int openjtag_buf_read_cy7c65215(
return ERROR_JTAG_DEVICE_ERROR;
}
- ret = jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
- CY7C65215_USB_TIMEOUT);
- if (ret < 0) {
- LOG_ERROR("bulk read failed, error %d", ret);
+ if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
+ CY7C65215_USB_TIMEOUT, &ret)) {
+ LOG_ERROR("bulk read failed, error");
return ERROR_JTAG_DEVICE_ERROR;
}
*bytes_read = ret;
@@ -451,7 +449,7 @@ static int openjtag_init_cy7c65215(void)
int ret;
usbh = NULL;
- ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh);
+ ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL);
if (ret != ERROR_OK) {
LOG_ERROR("unable to open cy7c65215 device");
goto err;
@@ -654,7 +652,6 @@ static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command *
/* whole byte */
/* bits to transfer */
- bits = 7;
command |= (7 << 5);
length -= 8;
}
@@ -692,7 +689,7 @@ static void openjtag_execute_sleep(struct jtag_command *cmd)
static void openjtag_set_state(uint8_t openocd_state)
{
- int8_t state = openjtag_get_tap_state(openocd_state);
+ uint8_t state = openjtag_get_tap_state(openocd_state);
uint8_t buf = 0;
buf = 0x01;
@@ -892,17 +889,20 @@ static const struct command_registration openjtag_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface openjtag_interface = {
+static struct jtag_interface openjtag_interface = {
+ .execute_queue = openjtag_execute_queue,
+};
+
+struct adapter_driver openjtag_adapter_driver = {
.name = "openjtag",
.transports = jtag_only,
.commands = openjtag_command_handlers,
- .execute_queue = openjtag_execute_queue,
- .speed = openjtag_speed,
- .speed_div = openjtag_speed_div,
- .khz = openjtag_khz,
.init = openjtag_init,
.quit = openjtag_quit,
+ .speed = openjtag_speed,
+ .khz = openjtag_khz,
+ .speed_div = openjtag_speed_div,
+
+ .jtag_ops = &openjtag_interface,
};
-
-
diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c
index 5db36a122..dc236660e 100644
--- a/src/jtag/drivers/osbdm.c
+++ b/src/jtag/drivers/osbdm.c
@@ -23,7 +23,7 @@
#include
#include
#include
-#include "libusb_common.h"
+#include "libusb_helper.h"
struct sequence {
int len;
@@ -132,7 +132,7 @@ static const uint16_t osbdm_vid[] = { 0x15a2, 0x15a2, 0x15a2, 0 };
static const uint16_t osbdm_pid[] = { 0x0042, 0x0058, 0x005e, 0 };
struct osbdm {
- struct jtag_libusb_device_handle *devh; /* USB handle */
+ struct libusb_device_handle *devh; /* USB handle */
uint8_t buffer[OSBDM_USB_BUFSIZE]; /* Data to send and receive */
int count; /* Count data to send and to read */
};
@@ -144,10 +144,12 @@ static struct osbdm osbdm_context;
static int osbdm_send_and_recv(struct osbdm *osbdm)
{
/* Send request */
- int count = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE,
- (char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT);
+ int count, ret;
- if (count != osbdm->count) {
+ ret = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE,
+ (char *)osbdm->buffer, osbdm->count,
+ OSBDM_USB_TIMEOUT, &count);
+ if (ret || count != osbdm->count) {
LOG_ERROR("OSBDM communication error: can't write");
return ERROR_FAIL;
}
@@ -156,13 +158,12 @@ static int osbdm_send_and_recv(struct osbdm *osbdm)
uint8_t cmd_saved = osbdm->buffer[0];
/* Reading answer */
- osbdm->count = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ,
- (char *)osbdm->buffer, OSBDM_USB_BUFSIZE, OSBDM_USB_TIMEOUT);
-
+ ret = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ,
+ (char *)osbdm->buffer, OSBDM_USB_BUFSIZE,
+ OSBDM_USB_TIMEOUT, &osbdm->count);
/* Now perform basic checks for data sent by BDM device
*/
-
- if (osbdm->count < 0) {
+ if (ret) {
LOG_ERROR("OSBDM communication error: can't read");
return ERROR_FAIL;
}
@@ -296,7 +297,7 @@ static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi,
return ERROR_OK;
}
-static int osbdm_flush(struct osbdm *osbdm, struct queue* queue)
+static int osbdm_flush(struct osbdm *osbdm, struct queue *queue)
{
uint8_t tms[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)];
uint8_t tdi[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)];
@@ -373,10 +374,10 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue* queue)
static int osbdm_open(struct osbdm *osbdm)
{
(void)memset(osbdm, 0, sizeof(*osbdm));
- if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh) != ERROR_OK)
+ if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK)
return ERROR_FAIL;
- if (jtag_libusb_claim_interface(osbdm->devh, 0) != ERROR_OK)
+ if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
@@ -688,12 +689,16 @@ static int osbdm_init(void)
return ERROR_OK;
}
-struct jtag_interface osbdm_interface = {
- .name = "osbdm",
-
- .transports = jtag_only,
+static struct jtag_interface osbdm_interface = {
.execute_queue = osbdm_execute_queue,
+};
+
+struct adapter_driver osbdm_adapter_driver = {
+ .name = "osbdm",
+ .transports = jtag_only,
.init = osbdm_init,
- .quit = osbdm_quit
+ .quit = osbdm_quit,
+
+ .jtag_ops = &osbdm_interface,
};
diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c
index 8e44dcb79..b3abd1205 100644
--- a/src/jtag/drivers/parport.c
+++ b/src/jtag/drivers/parport.c
@@ -237,7 +237,7 @@ static int parport_get_giveio_access(void)
HANDLE h;
OSVERSIONINFO version;
- version.dwOSVersionInfoSize = sizeof version;
+ version.dwOSVersionInfoSize = sizeof(version);
if (!GetVersionEx(&version)) {
errno = EINVAL;
return -1;
@@ -260,7 +260,6 @@ static int parport_get_giveio_access(void)
static struct bitbang_interface parport_bitbang = {
.read = &parport_read,
.write = &parport_write,
- .reset = &parport_reset,
.blink = &parport_led,
};
@@ -514,16 +513,22 @@ static const struct command_registration parport_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface parport_interface = {
- .name = "parport",
+static struct jtag_interface parport_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
+ .execute_queue = bitbang_execute_queue,
+};
+
+struct adapter_driver parport_adapter_driver = {
+ .name = "parport",
.transports = jtag_only,
.commands = parport_command_handlers,
.init = parport_init,
.quit = parport_quit,
+ .reset = parport_reset,
+ .speed = parport_speed,
.khz = parport_khz,
.speed_div = parport_speed_div,
- .speed = parport_speed,
- .execute_queue = bitbang_execute_queue,
+
+ .jtag_ops = &parport_interface,
};
diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c
index 2a94d0618..3849a27f9 100644
--- a/src/jtag/drivers/presto.c
+++ b/src/jtag/drivers/presto.c
@@ -561,15 +561,20 @@ static int presto_jtag_quit(void)
return ERROR_OK;
}
-struct jtag_interface presto_interface = {
+static struct jtag_interface presto_interface = {
+ .execute_queue = bitq_execute_queue,
+};
+
+struct adapter_driver presto_adapter_driver = {
.name = "presto",
.transports = jtag_only,
.commands = presto_command_handlers,
- .execute_queue = bitq_execute_queue,
+ .init = presto_jtag_init,
+ .quit = presto_jtag_quit,
.speed = presto_jtag_speed,
.khz = presto_adapter_khz,
.speed_div = presto_jtag_speed_div,
- .init = presto_jtag_init,
- .quit = presto_jtag_quit,
+
+ .jtag_ops = &presto_interface,
};
diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c
index a35489487..663795296 100644
--- a/src/jtag/drivers/remote_bitbang.c
+++ b/src/jtag/drivers/remote_bitbang.c
@@ -199,7 +199,6 @@ static struct bitbang_interface remote_bitbang_bitbang = {
.sample = &remote_bitbang_sample,
.read_sample = &remote_bitbang_read_sample,
.write = &remote_bitbang_write,
- .reset = &remote_bitbang_reset,
.blink = &remote_bitbang_blink,
};
@@ -342,11 +341,18 @@ static const struct command_registration remote_bitbang_command_handlers[] = {
COMMAND_REGISTRATION_DONE,
};
-struct jtag_interface remote_bitbang_interface = {
- .name = "remote_bitbang",
+static struct jtag_interface remote_bitbang_interface = {
.execute_queue = &bitbang_execute_queue,
+};
+
+struct adapter_driver remote_bitbang_adapter_driver = {
+ .name = "remote_bitbang",
.transports = jtag_only,
.commands = remote_bitbang_command_handlers,
+
.init = &remote_bitbang_init,
.quit = &remote_bitbang_quit,
+ .reset = &remote_bitbang_reset,
+
+ .jtag_ops = &remote_bitbang_interface,
};
diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c
index 317e8b808..e0533997c 100644
--- a/src/jtag/drivers/rlink.c
+++ b/src/jtag/drivers/rlink.c
@@ -1660,13 +1660,19 @@ static int rlink_quit(void)
return ERROR_OK;
}
-struct jtag_interface rlink_interface = {
+static struct jtag_interface rlink_interface = {
+ .execute_queue = rlink_execute_queue,
+};
+
+struct adapter_driver rlink_adapter_driver = {
.name = "rlink",
.transports = jtag_only,
+
.init = rlink_init,
.quit = rlink_quit,
.speed = rlink_speed,
- .speed_div = rlink_speed_div,
.khz = rlink_khz,
- .execute_queue = rlink_execute_queue,
+ .speed_div = rlink_speed_div,
+
+ .jtag_ops = &rlink_interface,
};
diff --git a/src/jtag/drivers/rlink_call.m4 b/src/jtag/drivers/rlink_call.m4
index b27f39238..bf07afa4e 100644
--- a/src/jtag/drivers/rlink_call.m4
+++ b/src/jtag/drivers/rlink_call.m4
@@ -479,5 +479,3 @@ m4_delay(HOLD_DELAY_CYCLES - 10)
A = X
DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
BRANCH
-
-
diff --git a/src/jtag/drivers/rlink_speed_table.c b/src/jtag/drivers/rlink_speed_table.c
index b84357731..660aac414 100644
--- a/src/jtag/drivers/rlink_speed_table.c
+++ b/src/jtag/drivers/rlink_speed_table.c
@@ -98,4 +98,3 @@ const struct rlink_speed_table rlink_speed_table[] = {{
} };
const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table);
-
diff --git a/src/jtag/drivers/rshim.c b/src/jtag/drivers/rshim.c
new file mode 100644
index 000000000..c718af5d2
--- /dev/null
+++ b/src/jtag/drivers/rshim.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2020, Mellanox Technologies Ltd. - All Rights Reserved
+ * Liming Sun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_SYS_IOCTL_H
+#include
+#endif
+#include
+#include
+
+/* Rshim channel where the CoreSight register resides. */
+#define RSH_MMIO_CHANNEL_RSHIM 0x1
+
+/* APB and tile address translation. */
+#define RSH_CS_ROM_BASE 0x80000000
+#define RSH_CS_TILE_BASE 0x44000000
+#define RSH_CS_TILE_SIZE 0x04000000
+
+/*
+ * APB-AP Identification Register
+ * The default value is defined in "CoreSight on-chip trace and debug
+ * (Revision: r1p0)", Section 3.16.5 APB-AP register summary.
+ */
+#define APB_AP_IDR 0x44770002
+
+/* CoreSight register definition. */
+#define RSH_CORESIGHT_CTL 0x0e00
+#define RSH_CORESIGHT_CTL_GO_SHIFT 0
+#define RSH_CORESIGHT_CTL_GO_MASK 0x1ULL
+#define RSH_CORESIGHT_CTL_ACTION_SHIFT 1
+#define RSH_CORESIGHT_CTL_ACTION_MASK 0x2ULL
+#define RSH_CORESIGHT_CTL_ADDR_SHIFT 2
+#define RSH_CORESIGHT_CTL_ADDR_MASK 0x7ffffffcULL
+#define RSH_CORESIGHT_CTL_ERR_SHIFT 31
+#define RSH_CORESIGHT_CTL_ERR_MASK 0x80000000ULL
+#define RSH_CORESIGHT_CTL_DATA_SHIFT 32
+#define RSH_CORESIGHT_CTL_DATA_MASK 0xffffffff00000000ULL
+
+/* Util macros to access the CoreSight register. */
+#define RSH_CS_GET_FIELD(reg, field) \
+ (((uint64_t)(reg) & RSH_CORESIGHT_CTL_##field##_MASK) >> \
+ RSH_CORESIGHT_CTL_##field##_SHIFT)
+
+#define RSH_CS_SET_FIELD(reg, field, value) \
+ (reg) = (((reg) & ~RSH_CORESIGHT_CTL_##field##_MASK) | \
+ (((uint64_t)(value) << RSH_CORESIGHT_CTL_##field##_SHIFT) & \
+ RSH_CORESIGHT_CTL_##field##_MASK))
+
+#ifdef HAVE_SYS_IOCTL_H
+/* Message used to program rshim via ioctl(). */
+typedef struct {
+ uint32_t addr;
+ uint64_t data;
+} __attribute__((packed)) rshim_ioctl_msg;
+
+enum {
+ RSH_IOC_READ = _IOWR('R', 0, rshim_ioctl_msg),
+ RSH_IOC_WRITE = _IOWR('R', 1, rshim_ioctl_msg),
+};
+#endif
+
+/* Use local variable stub for DP/AP registers. */
+static uint32_t dp_ctrl_stat;
+static uint32_t dp_id_code;
+static uint32_t ap_sel, ap_bank;
+static uint32_t ap_csw;
+static uint32_t ap_drw;
+static uint32_t ap_tar, ap_tar_inc;
+
+/* Static functions to read/write via rshim/coresight. */
+static int (*rshim_read)(int chan, int addr, uint64_t *value);
+static int (*rshim_write)(int chan, int addr, uint64_t value);
+static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata);
+static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value);
+
+/* RShim file handler. */
+static int rshim_fd = -1;
+
+/* DAP error code. */
+static int rshim_dap_retval = ERROR_OK;
+
+/* Default rshim device. */
+#define RSHIM_DEV_PATH_DEFAULT "/dev/rshim0/rshim"
+static char *rshim_dev_path;
+
+static int rshim_dev_read(int chan, int addr, uint64_t *value)
+{
+ int rc;
+
+ addr = (addr & 0xFFFF) | (1 << 16);
+ rc = pread(rshim_fd, value, sizeof(*value), addr);
+
+#ifdef HAVE_SYS_IOCTL_H
+ if (rc < 0 && errno == ENOSYS) {
+ rshim_ioctl_msg msg;
+
+ msg.addr = addr;
+ msg.data = 0;
+ rc = ioctl(rshim_fd, RSH_IOC_READ, &msg);
+ if (!rc)
+ *value = msg.data;
+ }
+#endif
+
+ return rc;
+}
+
+static int rshim_dev_write(int chan, int addr, uint64_t value)
+{
+ int rc;
+
+ addr = (addr & 0xFFFF) | (1 << 16);
+ rc = pwrite(rshim_fd, &value, sizeof(value), addr);
+
+#ifdef HAVE_SYS_IOCTL_H
+ if (rc < 0 && errno == ENOSYS) {
+ rshim_ioctl_msg msg;
+
+ msg.addr = addr;
+ msg.data = value;
+ rc = ioctl(rshim_fd, RSH_IOC_WRITE, &msg);
+ }
+#endif
+
+ return rc;
+}
+
+/* Convert AP address to tile local address. */
+static void ap_addr_2_tile(int *tile, uint32_t *addr)
+{
+ *addr -= RSH_CS_ROM_BASE;
+
+ if (*addr < RSH_CS_TILE_BASE) {
+ *tile = 0;
+ } else {
+ *addr -= RSH_CS_TILE_BASE;
+ *tile = *addr / RSH_CS_TILE_SIZE + 1;
+ *addr = *addr % RSH_CS_TILE_SIZE;
+ }
+}
+
+/*
+ * Write 4 bytes on the APB bus.
+ * tile = 0: access the root CS_ROM table
+ * > 0: access the ROM table of cluster (tile - 1)
+ */
+static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata)
+{
+ uint64_t ctl = 0;
+ int rc;
+
+ if (!rshim_read || !rshim_write)
+ return ERROR_FAIL;
+
+ /*
+ * ADDR[28] - must be set to 1 due to coresight ip.
+ * ADDR[27:24] - linear tile id
+ */
+ addr = (addr >> 2) | (tile << 24);
+ if (tile)
+ addr |= (1 << 28);
+ RSH_CS_SET_FIELD(ctl, ADDR, addr);
+ RSH_CS_SET_FIELD(ctl, ACTION, 0); /* write */
+ RSH_CS_SET_FIELD(ctl, DATA, wdata);
+ RSH_CS_SET_FIELD(ctl, GO, 1); /* start */
+
+ rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl);
+
+ do {
+ rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM,
+ RSH_CORESIGHT_CTL, &ctl);
+ if (rc < 0) {
+ LOG_ERROR("Failed to read rshim.\n");
+ return rc;
+ }
+ } while (RSH_CS_GET_FIELD(ctl, GO));
+
+ return ERROR_OK;
+}
+
+static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value)
+{
+ uint64_t ctl = 0;
+ int rc;
+
+ if (!rshim_read || !rshim_write)
+ return ERROR_FAIL;
+
+ /*
+ * ADDR[28] - must be set to 1 due to coresight ip.
+ * ADDR[27:24] - linear tile id
+ */
+ addr = (addr >> 2) | (tile << 24);
+ if (tile)
+ addr |= (1 << 28);
+ RSH_CS_SET_FIELD(ctl, ADDR, addr);
+ RSH_CS_SET_FIELD(ctl, ACTION, 1); /* read */
+ RSH_CS_SET_FIELD(ctl, GO, 1); /* start */
+
+ rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl);
+
+ do {
+ rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM,
+ RSH_CORESIGHT_CTL, &ctl);
+ if (rc < 0) {
+ LOG_ERROR("Failed to write rshim.\n");
+ return rc;
+ }
+ } while (RSH_CS_GET_FIELD(ctl, GO));
+
+ *value = RSH_CS_GET_FIELD(ctl, DATA);
+ return ERROR_OK;
+}
+
+static int rshim_dp_q_read(struct adiv5_dap *dap, unsigned int reg,
+ uint32_t *data)
+{
+ if (!data)
+ return ERROR_OK;
+
+ switch (reg) {
+ case DP_DPIDR:
+ *data = dp_id_code;
+ break;
+
+ case DP_CTRL_STAT:
+ *data = CDBGPWRUPACK | CSYSPWRUPACK;
+ break;
+
+ default:
+ break;
+ }
+
+ return ERROR_OK;
+}
+
+static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg,
+ uint32_t data)
+{
+ switch (reg) {
+ case DP_CTRL_STAT:
+ dp_ctrl_stat = data;
+ break;
+ case DP_SELECT:
+ ap_sel = (data & DP_SELECT_APSEL) >> 24;
+ ap_bank = (data & DP_SELECT_APBANK) >> 4;
+ break;
+ default:
+ LOG_INFO("Unknown command");
+ break;
+ }
+
+ return ERROR_OK;
+}
+
+static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg,
+ uint32_t *data)
+{
+ uint32_t addr;
+ int rc = ERROR_OK, tile;
+
+ switch (reg) {
+ case MEM_AP_REG_CSW:
+ *data = ap_csw;
+ break;
+
+ case MEM_AP_REG_CFG:
+ *data = 0;
+ break;
+
+ case MEM_AP_REG_BASE:
+ *data = RSH_CS_ROM_BASE;
+ break;
+
+ case AP_REG_IDR:
+ if (ap->ap_num == 0)
+ *data = APB_AP_IDR;
+ else
+ *data = 0;
+ break;
+
+ case MEM_AP_REG_BD0:
+ case MEM_AP_REG_BD1:
+ case MEM_AP_REG_BD2:
+ case MEM_AP_REG_BD3:
+ addr = (ap_tar & ~0xf) + (reg & 0x0C);
+ ap_addr_2_tile(&tile, &addr);
+ rc = coresight_read(tile, addr, data);
+ break;
+
+ case MEM_AP_REG_DRW:
+ addr = (ap_tar & ~0x3) + ap_tar_inc;
+ ap_addr_2_tile(&tile, &addr);
+ rc = coresight_read(tile, addr, data);
+ if (!rc && (ap_csw & CSW_ADDRINC_MASK))
+ ap_tar_inc += (ap_csw & 0x03) * 2;
+ break;
+
+ default:
+ LOG_INFO("Unknown command");
+ rc = ERROR_FAIL;
+ break;
+ }
+
+ /* Track the last error code. */
+ if (rc != ERROR_OK)
+ rshim_dap_retval = rc;
+
+ return rc;
+}
+
+static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg,
+ uint32_t data)
+{
+ int rc = ERROR_OK, tile;
+ uint32_t addr;
+
+ if (ap_bank != 0) {
+ rshim_dap_retval = ERROR_FAIL;
+ return ERROR_FAIL;
+ }
+
+ switch (reg) {
+ case MEM_AP_REG_CSW:
+ ap_csw = data;
+ break;
+
+ case MEM_AP_REG_TAR:
+ ap_tar = data;
+ ap_tar_inc = 0;
+ break;
+
+ case MEM_AP_REG_BD0:
+ case MEM_AP_REG_BD1:
+ case MEM_AP_REG_BD2:
+ case MEM_AP_REG_BD3:
+ addr = (ap_tar & ~0xf) + (reg & 0x0C);
+ ap_addr_2_tile(&tile, &addr);
+ rc = coresight_write(tile, addr, data);
+ break;
+
+ case MEM_AP_REG_DRW:
+ ap_drw = data;
+ addr = (ap_tar & ~0x3) + ap_tar_inc;
+ ap_addr_2_tile(&tile, &addr);
+ rc = coresight_write(tile, addr, data);
+ if (!rc && (ap_csw & CSW_ADDRINC_MASK))
+ ap_tar_inc += (ap_csw & 0x03) * 2;
+ break;
+
+ default:
+ rc = EINVAL;
+ break;
+ }
+
+ /* Track the last error code. */
+ if (rc != ERROR_OK)
+ rshim_dap_retval = rc;
+
+ return rc;
+}
+
+static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
+{
+ return ERROR_OK;
+}
+
+static int rshim_dp_run(struct adiv5_dap *dap)
+{
+ int retval = rshim_dap_retval;
+
+ /* Clear the error code. */
+ rshim_dap_retval = ERROR_OK;
+
+ return retval;
+}
+
+static int rshim_connect(struct adiv5_dap *dap)
+{
+ char *path = rshim_dev_path ? rshim_dev_path : RSHIM_DEV_PATH_DEFAULT;
+
+ rshim_fd = open(path, O_RDWR | O_SYNC);
+ if (rshim_fd == -1) {
+ LOG_ERROR("Unable to open %s\n", path);
+ return ERROR_FAIL;
+ }
+
+ /*
+ * Set read/write operation via the device file. Funtion pointers
+ * are used here so more ways like remote accessing via socket could
+ * be added later.
+ */
+ rshim_read = rshim_dev_read;
+ rshim_write = rshim_dev_write;
+
+ return ERROR_OK;
+}
+
+static void rshim_disconnect(struct adiv5_dap *dap)
+{
+ if (rshim_fd != -1) {
+ close(rshim_fd);
+ rshim_fd = -1;
+ }
+}
+
+COMMAND_HANDLER(rshim_dap_device_command)
+{
+ if (CMD_ARGC != 1) {
+ command_print(CMD, "Too many arguments");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ free(rshim_dev_path);
+ rshim_dev_path = strdup(CMD_ARGV[0]);
+ return ERROR_OK;
+}
+
+static const struct command_registration rshim_dap_subcommand_handlers[] = {
+ {
+ .name = "device",
+ .handler = rshim_dap_device_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the rshim device",
+ .usage = "/rshim>",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration rshim_dap_command_handlers[] = {
+ {
+ .name = "rshim",
+ .mode = COMMAND_ANY,
+ .help = "perform rshim management",
+ .chain = rshim_dap_subcommand_handlers,
+ .usage = "",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static int rshim_dap_init(void)
+{
+ return ERROR_OK;
+}
+
+static int rshim_dap_quit(void)
+{
+ return ERROR_OK;
+}
+
+static int rshim_dap_reset(int req_trst, int req_srst)
+{
+ return ERROR_OK;
+}
+
+static int rshim_dap_speed(int speed)
+{
+ return ERROR_OK;
+}
+
+static int rshim_dap_khz(int khz, int *jtag_speed)
+{
+ *jtag_speed = khz;
+ return ERROR_OK;
+}
+
+static int rshim_dap_speed_div(int speed, int *khz)
+{
+ *khz = speed;
+ return ERROR_OK;
+}
+
+/* DAP operations. */
+static const struct dap_ops rshim_dap_ops = {
+ .connect = rshim_connect,
+ .queue_dp_read = rshim_dp_q_read,
+ .queue_dp_write = rshim_dp_q_write,
+ .queue_ap_read = rshim_ap_q_read,
+ .queue_ap_write = rshim_ap_q_write,
+ .queue_ap_abort = rshim_ap_q_abort,
+ .run = rshim_dp_run,
+ .quit = rshim_disconnect,
+};
+
+static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL };
+
+struct adapter_driver rshim_dap_adapter_driver = {
+ .name = "rshim",
+ .transports = rshim_dap_transport,
+ .commands = rshim_dap_command_handlers,
+
+ .init = rshim_dap_init,
+ .quit = rshim_dap_quit,
+ .reset = rshim_dap_reset,
+ .speed = rshim_dap_speed,
+ .khz = rshim_dap_khz,
+ .speed_div = rshim_dap_speed_div,
+
+ .dap_swd_ops = &rshim_dap_ops,
+};
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index ea3dc003e..72975d5ac 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -31,27 +31,31 @@
/* project specific includes */
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
#include
-#include "libusb_common.h"
+#include "libusb_helper.h"
#ifdef HAVE_LIBUSB1
#define USE_LIBUSB_ASYNCIO
#endif
+#define STLINK_SERIAL_LEN 24
+
#define ENDPOINT_IN 0x80
#define ENDPOINT_OUT 0x00
#define STLINK_WRITE_TIMEOUT 1000
#define STLINK_READ_TIMEOUT 1000
-#define STLINK_NULL_EP 0
#define STLINK_RX_EP (1|ENDPOINT_IN)
#define STLINK_TX_EP (2|ENDPOINT_OUT)
#define STLINK_TRACE_EP (3|ENDPOINT_IN)
@@ -76,7 +80,7 @@
/*
* ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and
* this limits the bulk packet size and the 8bit read/writes to max 64 bytes.
- * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes.
+ * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6.
*/
#define STLINK_MAX_RW8 (64)
#define STLINKV3_MAX_RW8 (512)
@@ -92,6 +96,15 @@ enum stlink_jtag_api_version {
STLINK_JTAG_API_V3,
};
+enum stlink_mode {
+ STLINK_MODE_UNKNOWN = 0,
+ STLINK_MODE_DFU,
+ STLINK_MODE_MASS,
+ STLINK_MODE_DEBUG_JTAG,
+ STLINK_MODE_DEBUG_SWD,
+ STLINK_MODE_DEBUG_SWIM
+};
+
/** */
struct stlink_usb_version {
/** */
@@ -109,7 +122,7 @@ struct stlink_usb_version {
/** */
struct stlink_usb_handle_s {
/** */
- struct jtag_libusb_device_handle *fd;
+ struct libusb_device_handle *fd;
/** */
struct libusb_transfer *trans;
/** */
@@ -129,7 +142,7 @@ struct stlink_usb_handle_s {
/** */
uint32_t max_mem_packet;
/** */
- enum hl_transports transport;
+ enum stlink_mode st_mode;
/** */
struct stlink_usb_version version;
/** */
@@ -265,10 +278,14 @@ struct stlink_usb_handle_s {
#define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42
#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43
#define STLINK_DEBUG_APIV2_JTAG_SET_FREQ 0x44
-
+#define STLINK_DEBUG_APIV2_READ_DAP_REG 0x45
+#define STLINK_DEBUG_APIV2_WRITE_DAP_REG 0x46
#define STLINK_DEBUG_APIV2_READMEM_16BIT 0x47
#define STLINK_DEBUG_APIV2_WRITEMEM_16BIT 0x48
+#define STLINK_DEBUG_APIV2_INIT_AP 0x4B
+#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C
+
#define STLINK_APIV3_SET_COM_FREQ 0x61
#define STLINK_APIV3_GET_COM_FREQ 0x62
@@ -278,21 +295,13 @@ struct stlink_usb_handle_s {
#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01
#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02
+#define STLINK_DEBUG_PORT_ACCESS 0xffff
+
#define STLINK_TRACE_SIZE 4096
#define STLINK_TRACE_MAX_HZ 2000000
#define STLINK_V3_MAX_FREQ_NB 10
-/** */
-enum stlink_mode {
- STLINK_MODE_UNKNOWN = 0,
- STLINK_MODE_DFU,
- STLINK_MODE_MASS,
- STLINK_MODE_DEBUG_JTAG,
- STLINK_MODE_DEBUG_SWD,
- STLINK_MODE_DEBUG_SWIM
-};
-
#define REQUEST_SENSE 0x03
#define REQUEST_SENSE_LENGTH 18
@@ -300,11 +309,17 @@ enum stlink_mode {
* Map the relevant features, quirks and workaround for specific firmware
* version of stlink
*/
-#define STLINK_F_HAS_TRACE (1UL << 0)
-#define STLINK_F_HAS_SWD_SET_FREQ (1UL << 1)
-#define STLINK_F_HAS_JTAG_SET_FREQ (1UL << 2)
-#define STLINK_F_HAS_MEM_16BIT (1UL << 3)
-#define STLINK_F_HAS_GETLASTRWSTATUS2 (1UL << 4)
+#define STLINK_F_HAS_TRACE BIT(0)
+#define STLINK_F_HAS_SWD_SET_FREQ BIT(1)
+#define STLINK_F_HAS_JTAG_SET_FREQ BIT(2)
+#define STLINK_F_HAS_MEM_16BIT BIT(3)
+#define STLINK_F_HAS_GETLASTRWSTATUS2 BIT(4)
+#define STLINK_F_HAS_DAP_REG BIT(5)
+#define STLINK_F_QUIRK_JTAG_DP_READ BIT(6)
+#define STLINK_F_HAS_AP_INIT BIT(7)
+#define STLINK_F_HAS_DPBANKSEL BIT(8)
+#define STLINK_F_HAS_RW8_512BYTES BIT(9)
+#define STLINK_F_FIX_CLOSE_AP BIT(10)
/* aliases */
#define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE
@@ -332,7 +347,6 @@ static const struct speed_map stlink_khz_to_speed_map_swd[] = {
/* JTAG clock speed */
static const struct speed_map stlink_khz_to_speed_map_jtag[] = {
- {18000, 2},
{9000, 4},
{4500, 8},
{2250, 16},
@@ -347,6 +361,7 @@ static int stlink_swim_status(void *handle);
void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size);
static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map);
static int stlink_speed(void *handle, int khz, bool query);
+static int stlink_usb_open_ap(void *handle, unsigned short apsel);
/** */
static unsigned int stlink_usb_block(void *handle)
@@ -355,7 +370,7 @@ static unsigned int stlink_usb_block(void *handle)
assert(handle != NULL);
- if (h->version.stlink == 3)
+ if (h->version.flags & STLINK_F_HAS_RW8_512BYTES)
return STLINKV3_MAX_RW8;
else
return STLINK_MAX_RW8;
@@ -437,7 +452,8 @@ struct jtag_xfer {
struct libusb_transfer *transfer;
};
-static int jtag_libusb_bulk_transfer_n(jtag_libusb_device_handle *dev_handle,
+static int jtag_libusb_bulk_transfer_n(
+ struct libusb_device_handle *dev_handle,
struct jtag_xfer *transfers,
size_t n_transfers,
int timeout)
@@ -518,14 +534,16 @@ static int jtag_libusb_bulk_transfer_n(jtag_libusb_device_handle *dev_handle,
static int stlink_usb_xfer_v1_get_status(void *handle)
{
struct stlink_usb_handle_s *h = handle;
+ int tr, ret;
assert(handle != NULL);
/* read status */
memset(h->cmdbuf, 0, STLINK_SG_SIZE);
- if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf,
- 13, STLINK_READ_TIMEOUT) != 13)
+ ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13,
+ STLINK_READ_TIMEOUT, &tr);
+ if (ret || tr != 13)
return ERROR_FAIL;
uint32_t t1;
@@ -589,23 +607,26 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size)
{
struct stlink_usb_handle_s *h = handle;
+ int tr, ret;
assert(handle != NULL);
- if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, cmdsize,
- STLINK_WRITE_TIMEOUT) != cmdsize) {
+ ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf,
+ cmdsize, STLINK_WRITE_TIMEOUT, &tr);
+ if (ret || tr != cmdsize)
return ERROR_FAIL;
- }
if (h->direction == h->tx_ep && size) {
- if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
- size, STLINK_WRITE_TIMEOUT) != size) {
+ ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
+ size, STLINK_WRITE_TIMEOUT, &tr);
+ if (ret || tr != size) {
LOG_DEBUG("bulk write failed");
return ERROR_FAIL;
}
} else if (h->direction == h->rx_ep && size) {
- if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
- size, STLINK_READ_TIMEOUT) != size) {
+ ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
+ size, STLINK_READ_TIMEOUT, &tr);
+ if (ret || tr != size) {
LOG_DEBUG("bulk read failed");
return ERROR_FAIL;
}
@@ -691,7 +712,7 @@ static int stlink_usb_error_check(void *handle)
assert(handle != NULL);
- if (h->transport == HL_TRANSPORT_SWIM) {
+ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
switch (h->databuf[0]) {
case STLINK_SWIM_ERR_OK:
return ERROR_OK;
@@ -800,13 +821,13 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
struct stlink_usb_handle_s *h = handle;
while (1) {
- if ((h->transport != HL_TRANSPORT_SWIM) || !retries) {
+ if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) {
res = stlink_usb_xfer_noerrcheck(handle, buf, size);
if (res != ERROR_OK)
return res;
}
- if (h->transport == HL_TRANSPORT_SWIM) {
+ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
res = stlink_swim_status(handle);
if (res != ERROR_OK)
return res;
@@ -814,7 +835,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
res = stlink_usb_error_check(handle);
if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
- useconds_t delay_us = (1<version.flags & STLINK_F_HAS_TRACE);
- if (jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf,
- size, STLINK_READ_TIMEOUT) != size) {
+ ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size,
+ STLINK_READ_TIMEOUT, &tr);
+ if (ret || tr != size) {
LOG_ERROR("bulk trace read failed");
return ERROR_FAIL;
}
@@ -991,13 +1014,32 @@ static int stlink_usb_version(void *handle)
flags |= STLINK_F_HAS_SWD_SET_FREQ;
/* API to set JTAG frequency from J24 */
- if (h->version.jtag >= 24)
+ /* API to access DAP registers from J24 */
+ if (h->version.jtag >= 24) {
flags |= STLINK_F_HAS_JTAG_SET_FREQ;
+ flags |= STLINK_F_HAS_DAP_REG;
+ }
+
+ /* Quirk for read DP in JTAG mode (V2 only) from J24, fixed in J32 */
+ if (h->version.jtag >= 24 && h->version.jtag < 32)
+ flags |= STLINK_F_QUIRK_JTAG_DP_READ;
/* API to read/write memory at 16 bit from J26 */
if (h->version.jtag >= 26)
flags |= STLINK_F_HAS_MEM_16BIT;
+ /* API required to init AP before any AP access from J28 */
+ if (h->version.jtag >= 28)
+ flags |= STLINK_F_HAS_AP_INIT;
+
+ /* API required to return proper error code on close AP from J29 */
+ if (h->version.jtag >= 29)
+ flags |= STLINK_F_FIX_CLOSE_AP;
+
+ /* Banked regs (DPv1 & DPv2) support from V2J32 */
+ if (h->version.jtag >= 32)
+ flags |= STLINK_F_HAS_DPBANKSEL;
+
break;
case 3:
/* all STLINK-V3 use api-v3 */
@@ -1012,9 +1054,26 @@ static int stlink_usb_version(void *handle)
/* preferred API to get last R/W status */
flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
+ /* API to access DAP registers */
+ flags |= STLINK_F_HAS_DAP_REG;
+
/* API to read/write memory at 16 bit */
flags |= STLINK_F_HAS_MEM_16BIT;
+ /* API required to init AP before any AP access */
+ flags |= STLINK_F_HAS_AP_INIT;
+
+ /* API required to return proper error code on close AP */
+ flags |= STLINK_F_FIX_CLOSE_AP;
+
+ /* Banked regs (DPv1 & DPv2) support from V3J2 */
+ if (h->version.jtag >= 2)
+ flags |= STLINK_F_HAS_DPBANKSEL;
+
+ /* 8bit read/write max packet size 512 bytes from V3J6 */
+ if (h->version.jtag >= 6)
+ flags |= STLINK_F_HAS_RW8_512BYTES;
+
break;
default:
break;
@@ -1180,9 +1239,8 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
case STLINK_MODE_DEBUG_SWIM:
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER;
- /* no answer for this function... */
- rx_size = 0;
- break;
+ /* swim enter does not return any response or status */
+ return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0);
case STLINK_MODE_DFU:
case STLINK_MODE_MASS:
default:
@@ -1200,7 +1258,8 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
assert(handle != NULL);
- stlink_usb_init_buffer(handle, STLINK_NULL_EP, 0);
+ /* command with no reply, use a valid endpoint but zero size */
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
switch (type) {
case STLINK_MODE_DEBUG_JTAG:
@@ -1221,7 +1280,7 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
return ERROR_FAIL;
}
- res = stlink_usb_xfer_noerrcheck(handle, 0, 0);
+ res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
@@ -1238,20 +1297,17 @@ static enum stlink_mode stlink_get_mode(enum hl_transports t)
return STLINK_MODE_DEBUG_SWD;
case HL_TRANSPORT_JTAG:
return STLINK_MODE_DEBUG_JTAG;
- case HL_TRANSPORT_SWIM:
- return STLINK_MODE_DEBUG_SWIM;
default:
return STLINK_MODE_UNKNOWN;
}
}
/** */
-static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed)
+static int stlink_usb_exit_mode(void *handle)
{
int res;
uint8_t mode;
enum stlink_mode emode;
- struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
@@ -1280,12 +1336,25 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init
break;
}
- if (emode != STLINK_MODE_UNKNOWN) {
- res = stlink_usb_mode_leave(handle, emode);
+ if (emode != STLINK_MODE_UNKNOWN)
+ return stlink_usb_mode_leave(handle, emode);
- if (res != ERROR_OK)
- return res;
- }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed)
+{
+ int res;
+ uint8_t mode;
+ enum stlink_mode emode;
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ res = stlink_usb_exit_mode(handle);
+ if (res != ERROR_OK)
+ return res;
res = stlink_usb_current_mode(handle, &mode);
@@ -1318,7 +1387,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init
LOG_DEBUG("MODE: 0x%02X", mode);
/* set selected mode */
- emode = stlink_get_mode(h->transport);
+ emode = h->st_mode;
if (emode == STLINK_MODE_UNKNOWN) {
LOG_ERROR("selected mode (transport) not supported");
@@ -1326,12 +1395,12 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init
}
/* set the speed before entering the mode, as the chip discovery phase should be done at this speed too */
- if (h->transport == HL_TRANSPORT_JTAG) {
+ if (emode == STLINK_MODE_DEBUG_JTAG) {
if (h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ) {
stlink_dump_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag));
stlink_speed(h, initial_interface_speed, false);
}
- } else if (h->transport == HL_TRANSPORT_SWD) {
+ } else if (emode == STLINK_MODE_DEBUG_SWD) {
if (h->version.flags & STLINK_F_HAS_SWD_SET_FREQ) {
stlink_dump_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd));
stlink_speed(h, initial_interface_speed, false);
@@ -1341,7 +1410,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init
if (h->version.jtag_api == STLINK_JTAG_API_V3) {
struct speed_map map[STLINK_V3_MAX_FREQ_NB];
- stlink_get_com_freq(h, (h->transport == HL_TRANSPORT_JTAG), map);
+ stlink_get_com_freq(h, (emode == STLINK_MODE_DEBUG_JTAG), map);
stlink_dump_speed_map(map, ARRAY_SIZE(map));
stlink_speed(h, initial_interface_speed, false);
}
@@ -1582,7 +1651,7 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode)
assert(handle != NULL);
/* there is no swim read core id cmd */
- if (h->transport == HL_TRANSPORT_SWIM) {
+ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
*idcode = 0;
return ERROR_OK;
}
@@ -1713,22 +1782,9 @@ static enum target_state stlink_usb_state(void *handle)
assert(handle != NULL);
- if (h->transport == HL_TRANSPORT_SWIM) {
- res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
- if (res != ERROR_OK)
- return TARGET_UNKNOWN;
-
- res = stlink_swim_resync(handle);
- if (res != ERROR_OK)
- return TARGET_UNKNOWN;
-
- return ERROR_OK;
- }
-
if (h->reconnect_pending) {
LOG_INFO("Previous state query failed, trying to reconnect");
- res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
-
+ res = stlink_usb_mode_enter(handle, h->st_mode);
if (res != ERROR_OK)
return TARGET_UNKNOWN;
@@ -1768,7 +1824,7 @@ static int stlink_usb_assert_srst(void *handle, int srst)
assert(handle != NULL);
- if (h->transport == HL_TRANSPORT_SWIM)
+ if (h->st_mode == STLINK_MODE_DEBUG_SWIM)
return stlink_swim_assert_reset(handle, srst);
if (h->version.stlink == 1)
@@ -1845,9 +1901,6 @@ static int stlink_usb_reset(void *handle)
assert(handle != NULL);
- if (h->transport == HL_TRANSPORT_SWIM)
- return stlink_swim_generate_rst(handle);
-
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
@@ -2269,17 +2322,12 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
while (count) {
- bytes_remaining = (size != 1) ? \
+ bytes_remaining = (size != 1) ?
stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h);
if (count < bytes_remaining)
bytes_remaining = count;
- if (h->transport == HL_TRANSPORT_SWIM) {
- retval = stlink_swim_readbytes(handle, addr, bytes_remaining, buffer);
- if (retval != ERROR_OK)
- return retval;
- } else
/*
* all stlink support 8/32bit memory read/writes and only from
* stlink V2J26 there is support for 16 bit memory read/write.
@@ -2354,17 +2402,12 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
while (count) {
- bytes_remaining = (size != 1) ? \
+ bytes_remaining = (size != 1) ?
stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h);
if (count < bytes_remaining)
bytes_remaining = count;
- if (h->transport == HL_TRANSPORT_SWIM) {
- retval = stlink_swim_writebytes(handle, addr, bytes_remaining, buffer);
- if (retval != ERROR_OK)
- return retval;
- } else
/*
* all stlink support 8/32bit memory read/writes and only from
* stlink V2J26 there is support for 16 bit memory read/write.
@@ -2430,17 +2473,20 @@ static int stlink_usb_override_target(const char *targetname)
static int stlink_speed_swim(void *handle, int khz, bool query)
{
+ int retval;
+
/*
- we dont care what the khz rate is
we only have low and high speed...
before changing speed the SWIM_CSR HS bit
must be updated
*/
- if (khz == 0)
- stlink_swim_speed(handle, 0);
- else
- stlink_swim_speed(handle, 1);
- return khz;
+ if (!query) {
+ retval = stlink_swim_speed(handle, (khz < SWIM_FREQ_HIGH) ? 0 : 1);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Unable to set adapter speed");
+ }
+
+ return (khz < SWIM_FREQ_HIGH) ? SWIM_FREQ_LOW : SWIM_FREQ_HIGH;
}
static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_size, int khz, bool query)
@@ -2478,7 +2524,7 @@ static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_
match = false;
if (!match && query) {
- LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \
+ LOG_INFO("Unable to match requested speed %d kHz, using %d kHz",
khz, map[speed_index].speed);
}
@@ -2624,17 +2670,16 @@ static int stlink_speed(void *handle, int khz, bool query)
if (!handle)
return khz;
- switch (h->transport) {
- case HL_TRANSPORT_SWIM:
+ switch (h->st_mode) {
+ case STLINK_MODE_DEBUG_SWIM:
return stlink_speed_swim(handle, khz, query);
- break;
- case HL_TRANSPORT_SWD:
+ case STLINK_MODE_DEBUG_SWD:
if (h->version.jtag_api == STLINK_JTAG_API_V3)
return stlink_speed_v3(handle, false, khz, query);
else
return stlink_speed_swd(handle, khz, query);
break;
- case HL_TRANSPORT_JTAG:
+ case STLINK_MODE_DEBUG_JTAG:
if (h->version.jtag_api == STLINK_JTAG_API_V3)
return stlink_speed_v3(handle, true, khz, query);
else
@@ -2650,53 +2695,101 @@ static int stlink_speed(void *handle, int khz, bool query)
/** */
static int stlink_usb_close(void *handle)
{
- int res;
- uint8_t mode;
- enum stlink_mode emode;
struct stlink_usb_handle_s *h = handle;
- if (h && h->fd)
- res = stlink_usb_current_mode(handle, &mode);
- else
- res = ERROR_FAIL;
- /* do not exit if return code != ERROR_OK,
- it prevents us from closing jtag_libusb */
-
- if (res == ERROR_OK) {
- /* try to exit current mode */
- switch (mode) {
- case STLINK_DEV_DFU_MODE:
- emode = STLINK_MODE_DFU;
- break;
- case STLINK_DEV_DEBUG_MODE:
- emode = STLINK_MODE_DEBUG_SWD;
- break;
- case STLINK_DEV_SWIM_MODE:
- emode = STLINK_MODE_DEBUG_SWIM;
- break;
- case STLINK_DEV_BOOTLOADER_MODE:
- case STLINK_DEV_MASS_MODE:
- default:
- emode = STLINK_MODE_UNKNOWN;
- break;
- }
-
- if (emode != STLINK_MODE_UNKNOWN)
- stlink_usb_mode_leave(handle, emode);
- /* do not check return code, it prevent
- us from closing jtag_libusb */
- }
-
- if (h && h->fd)
+ if (h && h->fd) {
+ stlink_usb_exit_mode(h);
+ /* do not check return code, it prevent
+ us from closing jtag_libusb */
jtag_libusb_close(h->fd);
+ }
free(h);
return ERROR_OK;
}
+/* Compute ST-Link serial number from the device descriptor
+ * this function will help to work-around a bug in old ST-Link/V2 DFU
+ * the buggy DFU returns an incorrect serial in the USB descriptor
+ * example for the following serial "57FF72067265575742132067"
+ * - the correct descriptor serial is:
+ * 0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 0x32, 0x00 ...
+ * this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the serial in unicode format
+ * the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... >> 57FF72 ...
+ * this format could be read correctly by 'libusb_get_string_descriptor_ascii'
+ * so this case is managed by libusb_helper::string_descriptor_equal
+ * - the buggy DFU is not doing any unicode conversion and returns a raw serial data in the descriptor
+ * 0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ...
+ * >> 57 FF 72 ...
+ * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial
+ * and then we have just to convert the raw data into printable characters using sprintf
+ */
+char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
+ struct libusb_device_descriptor *dev_desc)
+{
+ int usb_retval;
+ unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2];
+
+ if (dev_desc->iSerialNumber == 0)
+ return NULL;
+
+ /* get the LANGID from String Descriptor Zero */
+ usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial,
+ sizeof(desc_serial));
+
+ if (usb_retval < LIBUSB_SUCCESS) {
+ LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
+ libusb_error_name(usb_retval), usb_retval);
+ return NULL;
+ } else if (usb_retval < 4) {
+ /* the size should be least 4 bytes to contain a minimum of 1 supported LANGID */
+ LOG_ERROR("could not get the LANGID");
+ return NULL;
+ }
+
+ uint32_t langid = desc_serial[2] | (desc_serial[3] << 8);
+
+ /* get the serial */
+ usb_retval = libusb_get_string_descriptor(device, dev_desc->iSerialNumber,
+ langid, desc_serial, sizeof(desc_serial));
+
+ unsigned char len = desc_serial[0];
+
+ if (usb_retval < LIBUSB_SUCCESS) {
+ LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
+ libusb_error_name(usb_retval), usb_retval);
+ return NULL;
+ } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) {
+ LOG_ERROR("invalid string in ST-LINK USB serial descriptor");
+ return NULL;
+ }
+
+ if (len == ((STLINK_SERIAL_LEN + 1) * 2)) {
+ /* good ST-Link adapter, this case is managed by
+ * libusb::libusb_get_string_descriptor_ascii */
+ return NULL;
+ } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) {
+ LOG_ERROR("unexpected serial length (%d) in descriptor", len);
+ return NULL;
+ }
+
+ /* else (len == 26) => buggy ST-Link */
+
+ char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char));
+ if (alternate_serial == NULL)
+ return NULL;
+
+ for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2)
+ sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]);
+
+ alternate_serial[STLINK_SERIAL_LEN] = '\0';
+
+ return alternate_serial;
+}
+
/** */
-static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
+static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
{
int err, retry_count = 1;
struct stlink_usb_handle_s *h;
@@ -2710,11 +2803,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
return ERROR_FAIL;
}
- h->transport = param->transport;
+ h->st_mode = mode;
for (unsigned i = 0; param->vid[i]; i++) {
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
- param->transport, param->vid[i], param->pid[i],
+ h->st_mode, param->vid[i], param->pid[i],
param->serial ? param->serial : "");
}
@@ -2728,14 +2821,15 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
in order to become operational.
*/
do {
- if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) {
+ if (jtag_libusb_open(param->vid, param->pid, param->serial,
+ &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
LOG_ERROR("open failed");
goto error_open;
}
jtag_libusb_set_configuration(h->fd, 0);
- if (jtag_libusb_claim_interface(h->fd, 0) != ERROR_OK) {
+ if (libusb_claim_interface(h->fd, 0) != ERROR_OK) {
LOG_DEBUG("claim interface failed");
goto error_open;
}
@@ -2744,7 +2838,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
h->rx_ep = STLINK_RX_EP;
uint16_t pid;
- if (jtag_libusb_get_pid(jtag_libusb_get_device(h->fd), &pid) != ERROR_OK) {
+ if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) {
LOG_DEBUG("libusb_get_pid failed");
goto error_open;
}
@@ -2788,13 +2882,13 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
LOG_ERROR("read version failed");
goto error_open;
} else {
- err = jtag_libusb_release_interface(h->fd, 0);
+ err = libusb_release_interface(h->fd, 0);
if (err != ERROR_OK) {
LOG_ERROR("release interface failed");
goto error_open;
}
- err = jtag_libusb_reset_device(h->fd);
+ err = libusb_reset_device(h->fd);
if (err != ERROR_OK) {
LOG_ERROR("reset device failed");
goto error_open;
@@ -2813,16 +2907,16 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
/* check if mode is supported */
err = ERROR_OK;
- switch (h->transport) {
- case HL_TRANSPORT_SWD:
+ switch (h->st_mode) {
+ case STLINK_MODE_DEBUG_SWD:
if (h->version.jtag_api == STLINK_JTAG_API_V1)
err = ERROR_FAIL;
/* fall-through */
- case HL_TRANSPORT_JTAG:
+ case STLINK_MODE_DEBUG_JTAG:
if (h->version.jtag == 0)
err = ERROR_FAIL;
break;
- case HL_TRANSPORT_SWIM:
+ case STLINK_MODE_DEBUG_SWIM:
if (h->version.swim == 0)
err = ERROR_FAIL;
break;
@@ -2844,7 +2938,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
goto error_open;
}
- if (h->transport == HL_TRANSPORT_SWIM) {
+ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
err = stlink_swim_enter(h);
if (err != ERROR_OK) {
LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)");
@@ -2860,6 +2954,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
h->max_mem_packet = (1 << 10);
uint8_t buffer[4];
+ stlink_usb_open_ap(h, 0);
err = stlink_usb_read_mem32(h, CPUID, 4, buffer);
if (err == ERROR_OK) {
uint32_t cpuid = le_to_h_u32(buffer);
@@ -2882,10 +2977,18 @@ error_open:
return ERROR_FAIL;
}
-int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
+{
+ return stlink_usb_open(param, stlink_get_mode(param->transport), fd);
+}
+
+int stlink_config_trace(void *handle, bool enabled,
+ enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+ unsigned int *trace_freq, unsigned int traceclkin_freq,
+ uint16_t *prescaler)
{
struct stlink_usb_handle_s *h = handle;
+ uint16_t presc;
if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) ||
pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
@@ -2908,15 +3011,116 @@ int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_p
if (!*trace_freq)
*trace_freq = STLINK_TRACE_MAX_HZ;
+
+ presc = traceclkin_freq / *trace_freq;
+
+ if (traceclkin_freq % *trace_freq > 0)
+ presc++;
+
+ if (presc > TPIU_ACPR_MAX_SWOSCALER) {
+ LOG_ERROR("SWO frequency is not suitable. Please choose a different "
+ "frequency.");
+ return ERROR_FAIL;
+ }
+
+ *prescaler = presc;
h->trace.source_hz = *trace_freq;
return stlink_usb_trace_enable(h);
}
+/** */
+static int stlink_usb_init_access_port(void *handle, unsigned char ap_num)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_COMMAND_NOTFOUND;
+
+ LOG_DEBUG_IO("init ap_num = %d", ap_num);
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_INIT_AP;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+}
+
+/** */
+static int stlink_usb_close_access_port(void *handle, unsigned char ap_num)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_COMMAND_NOTFOUND;
+
+ LOG_DEBUG_IO("close ap_num = %d", ap_num);
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+
+ /* ignore incorrectly returned error on bogus FW */
+ if (h->version.flags & STLINK_F_FIX_CLOSE_AP)
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+ else
+ return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
+
+}
+
+/** */
+static int stlink_read_dap_register(void *handle, unsigned short dap_port,
+ unsigned short addr, uint32_t *val)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int retval;
+
+ assert(handle != NULL);
+
+ if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
+ return ERROR_COMMAND_NOTFOUND;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_DAP_REG;
+ h_u16_to_le(&h->cmdbuf[2], dap_port);
+ h_u16_to_le(&h->cmdbuf[4], addr);
+
+ retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8);
+ *val = le_to_h_u32(h->databuf + 4);
+ LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%x", dap_port, addr, *val);
+ return retval;
+}
+
+/** */
+static int stlink_write_dap_register(void *handle, unsigned short dap_port,
+ unsigned short addr, uint32_t val)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
+ return ERROR_COMMAND_NOTFOUND;
+
+ LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%x", dap_port, addr, val);
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG;
+ h_u16_to_le(&h->cmdbuf[2], dap_port);
+ h_u16_to_le(&h->cmdbuf[4], addr);
+ h_u32_to_le(&h->cmdbuf[6], val);
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+}
+
/** */
struct hl_layout_api_s stlink_usb_layout_api = {
/** */
- .open = stlink_usb_open,
+ .open = stlink_usb_hl_open,
/** */
.close = stlink_usb_close,
/** */
@@ -2954,3 +3158,648 @@ struct hl_layout_api_s stlink_usb_layout_api = {
/** */
.poll_trace = stlink_usb_trace_read,
};
+
+/*****************************************************************************
+ * DAP direct interface
+ */
+
+static struct stlink_usb_handle_s *stlink_dap_handle;
+static struct hl_interface_param_s stlink_dap_param;
+static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1);
+static int stlink_dap_error = ERROR_OK;
+
+static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
+ uint32_t *data);
+
+/** */
+static int stlink_dap_record_error(int error)
+{
+ if (stlink_dap_error == ERROR_OK)
+ stlink_dap_error = error;
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_get_and_clear_error(void)
+{
+ int retval = stlink_dap_error;
+ stlink_dap_error = ERROR_OK;
+ return retval;
+}
+
+static int stlink_usb_open_ap(void *handle, unsigned short apsel)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int retval;
+
+ /* nothing to do on old versions */
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_OK;
+
+ if (apsel > DP_APSEL_MAX)
+ return ERROR_FAIL;
+
+ if (test_bit(apsel, opened_ap))
+ return ERROR_OK;
+
+ retval = stlink_usb_init_access_port(h, apsel);
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_DEBUG("AP %d enabled", apsel);
+ set_bit(apsel, opened_ap);
+ return ERROR_OK;
+}
+
+static int stlink_dap_open_ap(unsigned short apsel)
+{
+ return stlink_usb_open_ap(stlink_dap_handle, apsel);
+}
+
+/** */
+static int stlink_dap_closeall_ap(void)
+{
+ int retval, apsel;
+
+ /* nothing to do on old versions */
+ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_OK;
+
+ for (apsel = 0; apsel <= DP_APSEL_MAX; apsel++) {
+ if (!test_bit(apsel, opened_ap))
+ continue;
+ retval = stlink_usb_close_access_port(stlink_dap_handle, apsel);
+ if (retval != ERROR_OK)
+ return retval;
+ clear_bit(apsel, opened_ap);
+ }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_reinit_interface(void)
+{
+ int retval;
+
+ /*
+ * On JTAG only, it should be enough to call stlink_usb_reset(). But on
+ * some firmware version it does not work as expected, and there is no
+ * equivalent for SWD.
+ * At least for now, to reset the interface quit from JTAG/SWD mode then
+ * select the mode again.
+ */
+
+ if (!stlink_dap_handle->reconnect_pending) {
+ stlink_dap_handle->reconnect_pending = true;
+ stlink_usb_mode_leave(stlink_dap_handle, stlink_dap_handle->st_mode);
+ }
+
+ retval = stlink_usb_mode_enter(stlink_dap_handle, stlink_dap_handle->st_mode);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stlink_dap_handle->reconnect_pending = false;
+ /* on new FW, calling mode-leave closes all the opened AP; reopen them! */
+ if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)
+ for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++)
+ if (test_bit(apsel, opened_ap)) {
+ clear_bit(apsel, opened_ap);
+ stlink_dap_open_ap(apsel);
+ }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_op_connect(struct adiv5_dap *dap)
+{
+ uint32_t idcode;
+ int retval;
+
+ LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : "");
+
+ /* Check if we should reset srst already when connecting, but not if reconnecting. */
+ if (!dap->do_reconnect) {
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING)
+ adapter_assert_reset();
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ }
+ }
+
+ dap->do_reconnect = false;
+ dap_invalidate_cache(dap);
+
+ retval = dap_dp_init(dap);
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+
+ retval = stlink_usb_idcode(stlink_dap_handle, &idcode);
+ if (retval == ERROR_OK)
+ LOG_INFO("%s %#8.8" PRIx32,
+ (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) ? "JTAG IDCODE" : "SWD DPIDR",
+ idcode);
+ else
+ dap->do_reconnect = true;
+
+ return retval;
+}
+
+/** */
+static int stlink_dap_check_reconnect(struct adiv5_dap *dap)
+{
+ int retval;
+
+ if (!dap->do_reconnect)
+ return ERROR_OK;
+
+ retval = stlink_dap_reinit_interface();
+ if (retval != ERROR_OK)
+ return retval;
+
+ return stlink_dap_op_connect(dap);
+}
+
+/** */
+static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+ /* Ignore the request */
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
+ uint32_t *data)
+{
+ uint32_t dummy;
+ int retval;
+
+ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL))
+ if (reg & 0x000000F0) {
+ LOG_ERROR("Banked DP registers not supported in current STLink FW");
+ return ERROR_COMMAND_NOTFOUND;
+ }
+
+ retval = stlink_dap_check_reconnect(dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ data = data ? : &dummy;
+ if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ
+ && stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) {
+ /* Quirk required in JTAG. Read RDBUFF to get the data */
+ retval = stlink_read_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, reg, &dummy);
+ if (retval == ERROR_OK)
+ retval = stlink_read_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, DP_RDBUFF, data);
+ } else {
+ retval = stlink_read_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, reg, data);
+ }
+
+ return stlink_dap_record_error(retval);
+}
+
+/** */
+static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
+ uint32_t data)
+{
+ int retval;
+
+ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL))
+ if (reg & 0x000000F0) {
+ LOG_ERROR("Banked DP registers not supported in current STLink FW");
+ return ERROR_COMMAND_NOTFOUND;
+ }
+
+ if (reg == DP_SELECT && (data & DP_SELECT_DPBANK) != 0) {
+ /* ignored if STLINK_F_HAS_DPBANKSEL, not properly managed otherwise */
+ LOG_DEBUG("Ignoring DPBANKSEL while write SELECT");
+ data &= ~DP_SELECT_DPBANK;
+ }
+
+ retval = stlink_dap_check_reconnect(dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* ST-Link does not like that we set CORUNDETECT */
+ if (reg == DP_CTRL_STAT)
+ data &= ~CORUNDETECT;
+
+ retval = stlink_write_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, reg, data);
+ return stlink_dap_record_error(retval);
+}
+
+/** */
+static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned reg,
+ uint32_t *data)
+{
+ struct adiv5_dap *dap = ap->dap;
+ uint32_t dummy;
+ int retval;
+
+ retval = stlink_dap_check_reconnect(dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (reg != AP_REG_IDR) {
+ retval = stlink_dap_open_ap(ap->ap_num);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ data = data ? : &dummy;
+ retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg,
+ data);
+ dap->stlink_flush_ap_write = false;
+ return stlink_dap_record_error(retval);
+}
+
+/** */
+static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned reg,
+ uint32_t data)
+{
+ struct adiv5_dap *dap = ap->dap;
+ int retval;
+
+ retval = stlink_dap_check_reconnect(dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stlink_dap_open_ap(ap->ap_num);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg,
+ data);
+ dap->stlink_flush_ap_write = true;
+ return stlink_dap_record_error(retval);
+}
+
+/** */
+static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
+{
+ LOG_WARNING("stlink_dap_op_queue_ap_abort()");
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_op_run(struct adiv5_dap *dap)
+{
+ uint32_t ctrlstat, pwrmask;
+ int retval, saved_retval;
+
+ /* Here no LOG_DEBUG. This is called continuously! */
+
+ /*
+ * ST-Link returns immediately after a DAP write, without waiting for it
+ * to complete.
+ * Run a dummy read to DP_RDBUFF, as suggested in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16363.html
+ */
+ if (dap->stlink_flush_ap_write) {
+ dap->stlink_flush_ap_write = false;
+ retval = stlink_dap_op_queue_dp_read(dap, DP_RDBUFF, NULL);
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+ }
+
+ saved_retval = stlink_dap_get_and_clear_error();
+
+ retval = stlink_dap_op_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+ retval = stlink_dap_get_and_clear_error();
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect");
+ dap->do_reconnect = true;
+ return retval;
+ }
+
+ if (ctrlstat & SSTICKYERR) {
+ if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG)
+ retval = stlink_dap_op_queue_dp_write(dap, DP_CTRL_STAT,
+ ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR));
+ else
+ retval = stlink_dap_op_queue_dp_write(dap, DP_ABORT, STKERRCLR);
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+ retval = stlink_dap_get_and_clear_error();
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+ }
+
+ /* check for power lost */
+ pwrmask = dap->dp_ctrl_stat & (CDBGPWRUPREQ | CSYSPWRUPREQ);
+ if ((ctrlstat & pwrmask) != pwrmask)
+ dap->do_reconnect = true;
+
+ return saved_retval;
+}
+
+/** */
+static void stlink_dap_op_quit(struct adiv5_dap *dap)
+{
+ int retval;
+
+ retval = stlink_dap_closeall_ap();
+ if (retval != ERROR_OK)
+ LOG_ERROR("Error closing APs");
+}
+
+static int stlink_swim_op_srst(void)
+{
+ return stlink_swim_generate_rst(stlink_dap_handle);
+}
+
+static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size,
+ uint32_t count, uint8_t *buffer)
+{
+ int retval;
+ uint32_t bytes_remaining;
+
+ LOG_DEBUG_IO("read at 0x%08x len %d*0x%08x", addr, size, count);
+ count *= size;
+
+ while (count) {
+ bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count;
+ retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += bytes_remaining;
+ addr += bytes_remaining;
+ count -= bytes_remaining;
+ }
+
+ return ERROR_OK;
+}
+
+static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size,
+ uint32_t count, const uint8_t *buffer)
+{
+ int retval;
+ uint32_t bytes_remaining;
+
+ LOG_DEBUG_IO("write at 0x%08x len %d*0x%08x", addr, size, count);
+ count *= size;
+
+ while (count) {
+ bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count;
+ retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += bytes_remaining;
+ addr += bytes_remaining;
+ count -= bytes_remaining;
+ }
+
+ return ERROR_OK;
+}
+
+static int stlink_swim_op_reconnect(void)
+{
+ int retval;
+
+ retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return stlink_swim_resync(stlink_dap_handle);
+}
+
+static int stlink_dap_config_trace(bool enabled,
+ enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+ unsigned int *trace_freq, unsigned int traceclkin_freq,
+ uint16_t *prescaler)
+{
+ return stlink_config_trace(stlink_dap_handle, enabled, pin_protocol,
+ port_size, trace_freq, traceclkin_freq,
+ prescaler);
+}
+
+static int stlink_dap_trace_read(uint8_t *buf, size_t *size)
+{
+ return stlink_usb_trace_read(stlink_dap_handle, buf, size);
+}
+
+/** */
+COMMAND_HANDLER(stlink_dap_serial_command)
+{
+ LOG_DEBUG("stlink_dap_serial_command");
+
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("Expected exactly one argument for \"st-link serial \".");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (stlink_dap_param.serial) {
+ LOG_WARNING("Command \"st-link serial\" already used. Replacing previous value");
+ free((void *)stlink_dap_param.serial);
+ }
+
+ stlink_dap_param.serial = strdup(CMD_ARGV[0]);
+ return ERROR_OK;
+}
+
+/** */
+COMMAND_HANDLER(stlink_dap_vid_pid)
+{
+ unsigned int i, max_usb_ids = HLA_MAX_USB_IDS;
+
+ if (CMD_ARGC > max_usb_ids * 2) {
+ LOG_WARNING("ignoring extra IDs in vid_pid "
+ "(maximum is %d pairs)", max_usb_ids);
+ CMD_ARGC = max_usb_ids * 2;
+ }
+ if (CMD_ARGC < 2 || (CMD_ARGC & 1)) {
+ LOG_WARNING("incomplete vid_pid configuration directive");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ for (i = 0; i < CMD_ARGC; i += 2) {
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]);
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]);
+ }
+
+ /* null termination */
+ stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0;
+
+ return ERROR_OK;
+}
+
+/** */
+static const struct command_registration stlink_dap_subcommand_handlers[] = {
+ {
+ .name = "serial",
+ .handler = stlink_dap_serial_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the serial number of the adapter",
+ .usage = "",
+ },
+ {
+ .name = "vid_pid",
+ .handler = stlink_dap_vid_pid,
+ .mode = COMMAND_CONFIG,
+ .help = "USB VID and PID of the adapter",
+ .usage = "(vid pid)+",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+/** */
+static const struct command_registration stlink_dap_command_handlers[] = {
+ {
+ .name = "st-link",
+ .mode = COMMAND_ANY,
+ .help = "perform st-link management",
+ .chain = stlink_dap_subcommand_handlers,
+ .usage = "",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+/** */
+static int stlink_dap_init(void)
+{
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+ enum stlink_mode mode;
+ int retval;
+
+ LOG_DEBUG("stlink_dap_init()");
+
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING)
+ stlink_dap_param.connect_under_reset = true;
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ }
+
+ if (transport_is_dapdirect_swd())
+ mode = STLINK_MODE_DEBUG_SWD;
+ else if (transport_is_dapdirect_jtag())
+ mode = STLINK_MODE_DEBUG_JTAG;
+ else if (transport_is_swim())
+ mode = STLINK_MODE_DEBUG_SWIM;
+ else {
+ LOG_ERROR("Unsupported transport");
+ return ERROR_FAIL;
+ }
+
+ retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((mode != STLINK_MODE_DEBUG_SWIM) &&
+ !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) {
+ LOG_ERROR("ST-Link version does not support DAP direct transport");
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_quit(void)
+{
+ LOG_DEBUG("stlink_dap_quit()");
+
+ free((void *)stlink_dap_param.serial);
+ stlink_dap_param.serial = NULL;
+
+ return stlink_usb_close(stlink_dap_handle);
+}
+
+/** */
+static int stlink_dap_reset(int req_trst, int req_srst)
+{
+ LOG_DEBUG("stlink_dap_reset(%d)", req_srst);
+ return stlink_usb_assert_srst(stlink_dap_handle,
+ req_srst ? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW
+ : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH);
+}
+
+/** */
+static int stlink_dap_speed(int speed)
+{
+ if (speed == 0) {
+ LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+ }
+
+ stlink_dap_param.initial_interface_speed = speed;
+ stlink_speed(stlink_dap_handle, speed, false);
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_khz(int khz, int *jtag_speed)
+{
+ if (khz == 0) {
+ LOG_ERROR("RCLK not supported");
+ return ERROR_FAIL;
+ }
+
+ *jtag_speed = stlink_speed(stlink_dap_handle, khz, true);
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_speed_div(int speed, int *khz)
+{
+ *khz = speed;
+ return ERROR_OK;
+}
+
+static const struct dap_ops stlink_dap_ops = {
+ .connect = stlink_dap_op_connect,
+ .send_sequence = stlink_dap_op_send_sequence,
+ .queue_dp_read = stlink_dap_op_queue_dp_read,
+ .queue_dp_write = stlink_dap_op_queue_dp_write,
+ .queue_ap_read = stlink_dap_op_queue_ap_read,
+ .queue_ap_write = stlink_dap_op_queue_ap_write,
+ .queue_ap_abort = stlink_dap_op_queue_ap_abort,
+ .run = stlink_dap_op_run,
+ .sync = NULL, /* optional */
+ .quit = stlink_dap_op_quit, /* optional */
+};
+
+static const struct swim_driver stlink_swim_ops = {
+ .srst = stlink_swim_op_srst,
+ .read_mem = stlink_swim_op_read_mem,
+ .write_mem = stlink_swim_op_write_mem,
+ .reconnect = stlink_swim_op_reconnect,
+};
+
+static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL };
+
+struct adapter_driver stlink_dap_adapter_driver = {
+ .name = "st-link",
+ .transports = stlink_dap_transport,
+ .commands = stlink_dap_command_handlers,
+
+ .init = stlink_dap_init,
+ .quit = stlink_dap_quit,
+ .reset = stlink_dap_reset,
+ .speed = stlink_dap_speed,
+ .khz = stlink_dap_khz,
+ .speed_div = stlink_dap_speed_div,
+ .config_trace = stlink_dap_config_trace,
+ .poll_trace = stlink_dap_trace_read,
+
+ .dap_jtag_ops = &stlink_dap_ops,
+ .dap_swd_ops = &stlink_dap_ops,
+ .swim_ops = &stlink_swim_ops,
+};
diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c
index eb4941e6b..a4d7ad9ec 100644
--- a/src/jtag/drivers/sysfsgpio.c
+++ b/src/jtag/drivers/sysfsgpio.c
@@ -52,6 +52,7 @@
#include "config.h"
#endif
+#include
#include
#include "bitbang.h"
@@ -60,7 +61,7 @@
*
* Assume here that there will be less than 10000 gpios on a system
*/
-static int is_gpio_valid(int gpio)
+static bool is_gpio_valid(int gpio)
{
return gpio >= 0 && gpio < 10000;
}
@@ -97,8 +98,6 @@ static void unexport_sysfs_gpio(int gpio)
snprintf(gpiostr, sizeof(gpiostr), "%d", gpio);
if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0)
LOG_ERROR("Couldn't unexport gpio %d", gpio);
-
- return;
}
/*
@@ -112,6 +111,7 @@ static void unexport_sysfs_gpio(int gpio)
*/
static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
{
+ struct timeval timeout, now;
char buf[40];
char gpiostr[5];
int ret;
@@ -131,8 +131,19 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
}
}
+ gettimeofday(&timeout, NULL);
+ timeval_add_time(&timeout, 0, 500000);
+
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio);
- ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
+ for (;;) {
+ ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
+ if (ret >= 0 || errno != EACCES)
+ break;
+ gettimeofday(&now, NULL);
+ if (timeval_compare(&now, &timeout) >= 0)
+ break;
+ jtag_sleep(10000);
+ }
if (ret < 0) {
LOG_ERROR("Couldn't set direction for gpio %d", gpio);
perror("sysfsgpio: ");
@@ -141,7 +152,15 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
}
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
- ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
+ for (;;) {
+ ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
+ if (ret >= 0 || errno != EACCES)
+ break;
+ gettimeofday(&now, NULL);
+ if (timeval_compare(&now, &timeout) >= 0)
+ break;
+ jtag_sleep(10000);
+ }
if (ret < 0) {
LOG_ERROR("Couldn't open value for gpio %d", gpio);
perror("sysfsgpio: ");
@@ -530,21 +549,27 @@ static int sysfsgpio_quit(void);
static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL };
-struct jtag_interface sysfsgpio_interface = {
- .name = "sysfsgpio",
+static struct jtag_interface sysfsgpio_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = bitbang_execute_queue,
+};
+
+struct adapter_driver sysfsgpio_adapter_driver = {
+ .name = "sysfsgpio",
.transports = sysfsgpio_transports,
- .swd = &bitbang_swd,
.commands = sysfsgpio_command_handlers,
+
.init = sysfsgpio_init,
.quit = sysfsgpio_quit,
+ .reset = sysfsgpio_reset,
+
+ .jtag_ops = &sysfsgpio_interface,
+ .swd_ops = &bitbang_swd,
};
static struct bitbang_interface sysfsgpio_bitbang = {
.read = sysfsgpio_read,
.write = sysfsgpio_write,
- .reset = sysfsgpio_reset,
.swdio_read = sysfsgpio_swdio_read,
.swdio_drive = sysfsgpio_swdio_drive,
.blink = 0
@@ -576,23 +601,23 @@ static void cleanup_all_fds(void)
static bool sysfsgpio_jtag_mode_possible(void)
{
if (!is_gpio_valid(tck_gpio))
- return 0;
+ return false;
if (!is_gpio_valid(tms_gpio))
- return 0;
+ return false;
if (!is_gpio_valid(tdi_gpio))
- return 0;
+ return false;
if (!is_gpio_valid(tdo_gpio))
- return 0;
- return 1;
+ return false;
+ return true;
}
static bool sysfsgpio_swd_mode_possible(void)
{
if (!is_gpio_valid(swclk_gpio))
- return 0;
+ return false;
if (!is_gpio_valid(swdio_gpio))
- return 0;
- return 1;
+ return false;
+ return true;
}
static int sysfsgpio_init(void)
@@ -688,4 +713,3 @@ static int sysfsgpio_quit(void)
cleanup_all_fds();
return ERROR_OK;
}
-
diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c
index bbe08aae7..242c04fe3 100644
--- a/src/jtag/drivers/ulink.c
+++ b/src/jtag/drivers/ulink.c
@@ -235,7 +235,7 @@ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd);
int ulink_post_process_scan(struct ulink_cmd *ulink_cmd);
int ulink_post_process_queue(struct ulink *device);
-/* JTAG driver functions (registered in struct jtag_interface) */
+/* adapter driver functions */
static int ulink_execute_queue(void);
static int ulink_khz(int khz, int *jtag_speed);
static int ulink_speed(int speed);
@@ -650,7 +650,7 @@ void ulink_clear_queue(struct ulink *device)
int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
{
int newsize_out, newsize_in;
- int ret;
+ int ret = ERROR_OK;
newsize_out = ulink_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1
+ ulink_cmd->payload_out_size;
@@ -663,14 +663,12 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
/* New command does not fit. Execute all commands in queue before starting
* new queue with the current command as first entry. */
ret = ulink_execute_queued_commands(device, USB_TIMEOUT);
- if (ret != ERROR_OK)
- return ret;
- ret = ulink_post_process_queue(device);
- if (ret != ERROR_OK)
- return ret;
+ if (ret == ERROR_OK)
+ ret = ulink_post_process_queue(device);
- ulink_clear_queue(device);
+ if (ret == ERROR_OK)
+ ulink_clear_queue(device);
}
if (device->queue_start == NULL) {
@@ -687,7 +685,10 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
device->queue_end = ulink_cmd;
}
- return ERROR_OK;
+ if (ret != ERROR_OK)
+ ulink_clear_queue(device);
+
+ return ret;
}
/**
@@ -764,58 +765,40 @@ static const char *ulink_cmd_id_string(uint8_t id)
switch (id) {
case CMD_SCAN_IN:
return "CMD_SCAN_IN";
- break;
case CMD_SLOW_SCAN_IN:
return "CMD_SLOW_SCAN_IN";
- break;
case CMD_SCAN_OUT:
return "CMD_SCAN_OUT";
- break;
case CMD_SLOW_SCAN_OUT:
return "CMD_SLOW_SCAN_OUT";
- break;
case CMD_SCAN_IO:
return "CMD_SCAN_IO";
- break;
case CMD_SLOW_SCAN_IO:
return "CMD_SLOW_SCAN_IO";
- break;
case CMD_CLOCK_TMS:
return "CMD_CLOCK_TMS";
- break;
case CMD_SLOW_CLOCK_TMS:
return "CMD_SLOW_CLOCK_TMS";
- break;
case CMD_CLOCK_TCK:
return "CMD_CLOCK_TCK";
- break;
case CMD_SLOW_CLOCK_TCK:
return "CMD_SLOW_CLOCK_TCK";
- break;
case CMD_SLEEP_US:
return "CMD_SLEEP_US";
- break;
case CMD_SLEEP_MS:
return "CMD_SLEEP_MS";
- break;
case CMD_GET_SIGNALS:
return "CMD_GET_SIGNALS";
- break;
case CMD_SET_SIGNALS:
return "CMD_SET_SIGNALS";
- break;
case CMD_CONFIGURE_TCK_FREQ:
return "CMD_CONFIGURE_TCK_FREQ";
- break;
case CMD_SET_LEDS:
return "CMD_SET_LEDS";
- break;
case CMD_TEST:
return "CMD_TEST";
- break;
default:
return "CMD_UNKNOWN";
- break;
}
}
@@ -1627,6 +1610,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd)
if (ret != ERROR_OK) {
free(tdi_buffer_start);
+ free(tdo_buffer_start);
return ret;
}
}
@@ -2209,14 +2193,17 @@ static int ulink_init(void)
}
ulink_clear_queue(ulink_handle);
- ulink_append_get_signals_cmd(ulink_handle);
- ulink_execute_queued_commands(ulink_handle, 200);
+ ret = ulink_append_get_signals_cmd(ulink_handle);
+ if (ret == ERROR_OK)
+ ret = ulink_execute_queued_commands(ulink_handle, 200);
- /* Post-process the single CMD_GET_SIGNALS command */
- input_signals = ulink_handle->queue_start->payload_in[0];
- output_signals = ulink_handle->queue_start->payload_in[1];
+ if (ret == ERROR_OK) {
+ /* Post-process the single CMD_GET_SIGNALS command */
+ input_signals = ulink_handle->queue_start->payload_in[0];
+ output_signals = ulink_handle->queue_start->payload_in[1];
- ulink_print_signal_states(input_signals, output_signals);
+ ulink_print_signal_states(input_signals, output_signals);
+ }
ulink_clear_queue(ulink_handle);
@@ -2272,17 +2259,20 @@ static const struct command_registration ulink_command_handlers[] = {
COMMAND_REGISTRATION_DONE,
};
-struct jtag_interface ulink_interface = {
- .name = "ulink",
-
- .commands = ulink_command_handlers,
- .transports = jtag_only,
-
+static struct jtag_interface ulink_interface = {
.execute_queue = ulink_execute_queue,
- .khz = ulink_khz,
- .speed = ulink_speed,
- .speed_div = ulink_speed_div,
+};
+
+struct adapter_driver ulink_adapter_driver = {
+ .name = "ulink",
+ .transports = jtag_only,
+ .commands = ulink_command_handlers,
.init = ulink_init,
- .quit = ulink_quit
+ .quit = ulink_quit,
+ .speed = ulink_speed,
+ .khz = ulink_khz,
+ .speed_div = ulink_speed_div,
+
+ .jtag_ops = &ulink_interface,
};
diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
index d99173369..e2556cec0 100644
--- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
+++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
@@ -23,7 +23,7 @@
#endif
#include
#include
-#include
+#include
#include
#include "ublast_access.h"
@@ -42,28 +42,37 @@
static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
unsigned size, uint32_t *bytes_read)
{
- *bytes_read = jtag_libusb_bulk_read(low->libusb_dev,
- USBBLASTER_EPIN | \
+ int ret, tmp = 0;
+
+ ret = jtag_libusb_bulk_read(low->libusb_dev,
+ USBBLASTER_EPIN |
LIBUSB_ENDPOINT_IN,
(char *)buf,
size,
- 100);
- return ERROR_OK;
+ 100, &tmp);
+ *bytes_read = tmp;
+
+ return ret;
}
static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf,
int size, uint32_t *bytes_written)
{
- *bytes_written = jtag_libusb_bulk_write(low->libusb_dev,
- USBBLASTER_EPOUT | \
+ int ret, tmp = 0;
+
+ ret = jtag_libusb_bulk_write(low->libusb_dev,
+ USBBLASTER_EPOUT |
LIBUSB_ENDPOINT_OUT,
(char *)buf,
size,
- 100);
- return ERROR_OK;
+ 100, &tmp);
+ *bytes_written = tmp;
+
+ return ret;
+
}
-static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libusb_dev,
+static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_dev,
struct image *firmware_image, int section_index)
{
uint16_t chunk_size;
@@ -97,7 +106,7 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu
chunk_size = bytes_remaining;
jtag_libusb_control_transfer(libusb_dev,
- LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT,
USBBLASTER_CTRL_LOAD_FIRM,
addr,
@@ -114,7 +123,7 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu
return ERROR_OK;
}
-static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_dev,
+static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
struct ublast_lowlevel *low)
{
struct image ublast2_firmware_image;
@@ -143,7 +152,7 @@ static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_de
char value = CPU_RESET;
jtag_libusb_control_transfer(libusb_dev,
- LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT,
USBBLASTER_CTRL_LOAD_FIRM,
EZUSB_CPUCS,
@@ -164,7 +173,7 @@ static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_de
value = !CPU_RESET;
jtag_libusb_control_transfer(libusb_dev,
- LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT,
USBBLASTER_CTRL_LOAD_FIRM,
EZUSB_CPUCS,
@@ -182,11 +191,11 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
{
const uint16_t vids[] = { low->ublast_vid_uninit, 0 };
const uint16_t pids[] = { low->ublast_pid_uninit, 0 };
- struct jtag_libusb_device_handle *temp;
+ struct libusb_device_handle *temp;
bool renumeration = false;
int ret;
- if (jtag_libusb_open(vids, pids, NULL, &temp) == ERROR_OK) {
+ if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) {
LOG_INFO("Altera USB-Blaster II (uninitialized) found");
LOG_INFO("Loading firmware...");
ret = load_usb_blaster_firmware(temp, low);
@@ -200,13 +209,15 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
const uint16_t pids_renum[] = { low->ublast_pid, 0 };
if (renumeration == false) {
- if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK) {
+ if (jtag_libusb_open(vids_renum, pids_renum, NULL,
+ &low->libusb_dev, NULL) != ERROR_OK) {
LOG_ERROR("Altera USB-Blaster II not found");
return ERROR_FAIL;
}
} else {
int retry = 10;
- while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK && retry--) {
+ while (jtag_libusb_open(vids_renum, pids_renum, NULL,
+ &low->libusb_dev, NULL) != ERROR_OK && retry--) {
usleep(1000000);
LOG_INFO("Waiting for renumerate...");
}
@@ -219,7 +230,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
char buffer[5];
jtag_libusb_control_transfer(low->libusb_dev,
- LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_IN,
USBBLASTER_CTRL_READ_REV,
0,
diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h
index 252f003a9..ad20d65d4 100644
--- a/src/jtag/drivers/usb_blaster/ublast_access.h
+++ b/src/jtag/drivers/usb_blaster/ublast_access.h
@@ -28,8 +28,6 @@
#ifndef OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H
#define OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H
-#include
-
/* Low level flags */
#define COPY_TDO_BUFFER (1 << 0)
@@ -39,7 +37,7 @@ struct ublast_lowlevel {
uint16_t ublast_vid_uninit;
uint16_t ublast_pid_uninit;
char *ublast_device_desc;
- struct jtag_libusb_device_handle *libusb_dev;
+ struct libusb_device_handle *libusb_dev;
char *firmware_path;
int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size,
diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c
index 165ebdcd3..d30483b63 100644
--- a/src/jtag/drivers/usb_blaster/usb_blaster.c
+++ b/src/jtag/drivers/usb_blaster/usb_blaster.c
@@ -816,6 +816,11 @@ static int ublast_execute_queue(void)
case JTAG_SCAN:
ret = ublast_scan(cmd->cmd.scan);
break;
+ default:
+ LOG_ERROR("BUG: unknown JTAG command type 0x%X",
+ cmd->type);
+ ret = ERROR_FAIL;
+ break;
}
}
@@ -1037,8 +1042,8 @@ static const struct command_registration ublast_command_handlers[] = {
.name = "usb_blaster_vid_pid",
.handler = ublast_handle_vid_pid_command,
.mode = COMMAND_CONFIG,
- .help = "the vendor ID and product ID of the USB-Blaster and " \
- "vendor ID and product ID of the uninitialized device " \
+ .help = "the vendor ID and product ID of the USB-Blaster and "
+ "vendor ID and product ID of the uninitialized device "
"for USB-Blaster II",
.usage = "vid pid vid_uninit pid_uninit",
},
@@ -1066,13 +1071,18 @@ static const struct command_registration ublast_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface usb_blaster_interface = {
+static struct jtag_interface usb_blaster_interface = {
+ .supported = DEBUG_CAP_TMS_SEQ,
+ .execute_queue = ublast_execute_queue,
+};
+
+struct adapter_driver usb_blaster_adapter_driver = {
.name = "usb_blaster",
.transports = jtag_only,
.commands = ublast_command_handlers,
- .supported = DEBUG_CAP_TMS_SEQ,
- .execute_queue = ublast_execute_queue,
.init = ublast_init,
.quit = ublast_quit,
+
+ .jtag_ops = &usb_blaster_interface,
};
diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c
index 35a95202e..7b27eaff2 100644
--- a/src/jtag/drivers/usbprog.c
+++ b/src/jtag/drivers/usbprog.c
@@ -381,7 +381,7 @@ static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag)
static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen)
{
int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100);
- if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \
+ if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) ||
(msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9))
return 1;
if (res == msglen) {
@@ -596,11 +596,16 @@ static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag)
}
}
-struct jtag_interface usbprog_interface = {
+static struct jtag_interface usbprog_interface = {
+ .execute_queue = usbprog_execute_queue,
+};
+
+struct adapter_driver usbprog_adapter_driver = {
.name = "usbprog",
.transports = jtag_only,
- .execute_queue = usbprog_execute_queue,
.init = usbprog_init,
- .quit = usbprog_quit
+ .quit = usbprog_quit,
+
+ .jtag_ops = &usbprog_interface,
};
diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c
index 53a7e989b..678b097c9 100644
--- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c
+++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c
@@ -48,7 +48,7 @@ uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN];
#define usbtoxxx_get_type_name(type) \
types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \
- % (sizeof(types_name) / sizeof(types_name[0]))]
+ % ARRAY_SIZE(types_name)]
static uint8_t type_pre;
static uint16_t usbtoxxx_buffer_index;
diff --git a/src/jtag/drivers/versaloon/versaloon_internal.h b/src/jtag/drivers/versaloon/versaloon_internal.h
index 497b6b9ce..8372970b1 100644
--- a/src/jtag/drivers/versaloon/versaloon_internal.h
+++ b/src/jtag/drivers/versaloon/versaloon_internal.h
@@ -91,7 +91,7 @@ struct versaloon_pending_t {
void *extra_data;
versaloon_callback_t callback;
};
-extern struct versaloon_pending_t \
+extern struct versaloon_pending_t
versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
extern uint16_t versaloon_pending_idx;
void versaloon_set_pending_id(uint32_t id);
diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c
index 4907ef0e2..5fb9bcdcc 100644
--- a/src/jtag/drivers/vsllink.c
+++ b/src/jtag/drivers/vsllink.c
@@ -59,7 +59,7 @@ static void vsllink_runtest(int num_cycles);
static void vsllink_stableclocks(int num_cycles, int tms);
static void vsllink_scan(bool ir_scan, enum scan_type type,
uint8_t *buffer, int scan_size, struct scan_command *command);
-static void vsllink_reset(int trst, int srst);
+static int vsllink_reset(int trst, int srst);
/* VSLLink tap buffer functions */
static void vsllink_tap_append_step(int tms, int tdi);
@@ -164,20 +164,6 @@ static int vsllink_execute_queue(void)
cmd->cmd.scan);
break;
- case JTAG_RESET:
- LOG_DEBUG_IO("reset trst: %i srst %i",
- cmd->cmd.reset->trst,
- cmd->cmd.reset->srst);
-
- vsllink_tap_execute();
-
- if (cmd->cmd.reset->trst == 1)
- tap_set_state(TAP_RESET);
-
- vsllink_reset(cmd->cmd.reset->trst,
- cmd->cmd.reset->srst);
- break;
-
case JTAG_SLEEP:
LOG_DEBUG_IO("sleep %i", cmd->cmd.sleep->us);
vsllink_tap_execute();
@@ -306,7 +292,7 @@ static int vsllink_interface_init(void)
libusb_init(&vsllink_handle->libusb_ctx);
if (ERROR_OK != vsllink_usb_open(vsllink_handle)) {
- LOG_ERROR("Can't find USB JTAG Interface!" \
+ LOG_ERROR("Can't find USB JTAG Interface!"
"Please check connection and permissions.");
return ERROR_JTAG_INIT_FAILED;
}
@@ -478,7 +464,7 @@ static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
vsllink_state_move();
}
-static void vsllink_reset(int trst, int srst)
+static int vsllink_reset(int trst, int srst)
{
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
@@ -494,7 +480,7 @@ static void vsllink_reset(int trst, int srst)
versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0);
}
- versaloon_interface.adaptors.peripheral_commit();
+ return versaloon_interface.adaptors.peripheral_commit();
}
COMMAND_HANDLER(vsllink_handle_usb_vid_command)
@@ -962,17 +948,23 @@ static const struct swd_driver vsllink_swd_driver = {
.run = vsllink_swd_run_queue,
};
-struct jtag_interface vsllink_interface = {
- .name = "vsllink",
+static struct jtag_interface vsllink_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
- .commands = vsllink_command_handlers,
+ .execute_queue = vsllink_execute_queue,
+};
+
+struct adapter_driver vsllink_adapter_driver = {
+ .name = "vsllink",
.transports = vsllink_transports,
- .swd = &vsllink_swd_driver,
+ .commands = vsllink_command_handlers,
.init = vsllink_init,
.quit = vsllink_quit,
- .khz = vsllink_khz,
+ .reset = vsllink_reset,
.speed = vsllink_speed,
+ .khz = vsllink_khz,
.speed_div = vsllink_speed_div,
- .execute_queue = vsllink_execute_queue,
+
+ .jtag_ops = &vsllink_interface,
+ .swd_ops = &vsllink_swd_driver,
};
diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c
index f25023ba7..5e4df93c2 100644
--- a/src/jtag/drivers/xds110.c
+++ b/src/jtag/drivers/xds110.c
@@ -41,6 +41,12 @@
#define OCD_FIRMWARE_UPGRADE \
"XDS110: upgrade to version 2.3.0.11+ for improved support"
+/* Firmware version that introduced improved TCK performance */
+#define FAST_TCK_FIRMWARE_VERSION 0x03000000
+
+/* Firmware version that introduced 10 MHz and 12 MHz TCK support */
+#define FAST_TCK_PLUS_FIRMWARE_VERSION 0x03000003
+
/***************************************************************************
* USB Connection Buffer Definitions *
***************************************************************************/
@@ -60,15 +66,6 @@
#endif
#define MAX_RESULT_QUEUE (MAX_DATA_BLOCK / 4)
-/***************************************************************************
- * USB Connection Endpoints *
- ***************************************************************************/
-
-/* Bulk endpoints used by the XDS110 debug interface */
-#define INTERFACE_DEBUG (2)
-#define ENDPOINT_DEBUG_IN (3 | LIBUSB_ENDPOINT_IN)
-#define ENDPOINT_DEBUG_OUT (2 | LIBUSB_ENDPOINT_OUT)
-
/***************************************************************************
* XDS110 Firmware API Definitions *
***************************************************************************/
@@ -91,8 +88,17 @@
/* TCK frequency limits */
#define XDS110_MIN_TCK_SPEED 100 /* kHz */
-#define XDS110_MAX_TCK_SPEED 2500 /* kHz */
-#define XDS110_TCK_PULSE_INCREMENT 66.0
+#define XDS110_MAX_SLOW_TCK_SPEED 2500 /* kHz */
+#define XDS110_MAX_FAST_TCK_SPEED 14000 /* kHz */
+#define XDS110_DEFAULT_TCK_SPEED 2500 /* kHz */
+
+/* Fixed TCK delay values for "Fast" TCK frequencies */
+#define FAST_TCK_DELAY_14000_KHZ 0
+#define FAST_TCK_DELAY_10000_KHZ 0xfffffffd
+#define FAST_TCK_DELAY_12000_KHZ 0xfffffffe
+#define FAST_TCK_DELAY_8500_KHZ 1
+#define FAST_TCK_DELAY_5500_KHZ 2
+/* For TCK frequencies below 5500 kHz, use calculated delay */
/* Scan mode on connect */
#define MODE_JTAG 1
@@ -212,6 +218,13 @@ struct xds110_info {
unsigned char read_payload[USB_PAYLOAD_SIZE];
unsigned char write_packet[3];
unsigned char write_payload[USB_PAYLOAD_SIZE];
+ /* Device vid/pid */
+ uint16_t vid;
+ uint16_t pid;
+ /* Debug interface */
+ uint8_t interface;
+ uint8_t endpoint_in;
+ uint8_t endpoint_out;
/* Status flags */
bool is_connected;
bool is_cmapi_connected;
@@ -244,12 +257,17 @@ struct xds110_info {
static struct xds110_info xds110 = {
.ctx = NULL,
.dev = NULL,
+ .vid = 0,
+ .pid = 0,
+ .interface = 0,
+ .endpoint_in = 0,
+ .endpoint_out = 0,
.is_connected = false,
.is_cmapi_connected = false,
.is_cmapi_acquired = false,
.is_swd_mode = false,
.is_ap_dirty = false,
- .speed = XDS110_MAX_TCK_SPEED,
+ .speed = XDS110_DEFAULT_TCK_SPEED,
.delay_count = 0,
.serial = {0},
.voltage = 0,
@@ -305,12 +323,20 @@ static bool usb_connect(void)
struct libusb_device_descriptor desc;
- uint16_t vid = 0x0451;
- uint16_t pid = 0xbef3;
+ /* The vid/pids of possible XDS110 configurations */
+ uint16_t vids[] = { 0x0451, 0x0451, 0x1cbe };
+ uint16_t pids[] = { 0xbef3, 0xbef4, 0x02a5 };
+ /* Corresponding interface and endpoint numbers for configurations */
+ uint8_t interfaces[] = { 2, 2, 0 };
+ uint8_t endpoints_in[] = { 3, 3, 1 };
+ uint8_t endpoints_out[] = { 2, 2, 1 };
+
ssize_t count = 0;
ssize_t i = 0;
int result = 0;
bool found = false;
+ uint32_t device = 0;
+ bool match = false;
/* Initialize libusb context */
result = libusb_init(&ctx);
@@ -327,13 +353,21 @@ static bool usb_connect(void)
if (0 == result) {
/* Scan through list of devices for any XDS110s */
for (i = 0; i < count; i++) {
- /* Check for device VID/PID match */
+ /* Check for device vid/pid match */
libusb_get_device_descriptor(list[i], &desc);
- if (desc.idVendor == vid && desc.idProduct == pid) {
+ match = false;
+ for (device = 0; device < sizeof(vids)/sizeof(vids[0]); device++) {
+ if (desc.idVendor == vids[device] &&
+ desc.idProduct == pids[device]) {
+ match = true;
+ break;
+ }
+ }
+ if (match) {
result = libusb_open(list[i], &dev);
if (0 == result) {
- const int MAX_DATA = 256;
- unsigned char data[MAX_DATA + 1];
+ const int max_data = 256;
+ unsigned char data[max_data + 1];
*data = '\0';
/* May be the requested device if serial number matches */
@@ -344,7 +378,7 @@ static bool usb_connect(void)
} else {
/* Get the device's serial number string */
result = libusb_get_string_descriptor_ascii(dev,
- desc.iSerialNumber, data, MAX_DATA);
+ desc.iSerialNumber, data, max_data);
if (0 < result &&
0 == strcmp((char *)data, (char *)xds110.serial)) {
found = true;
@@ -372,6 +406,15 @@ static bool usb_connect(void)
}
if (found) {
+ /* Save the vid/pid of the device we're using */
+ xds110.vid = vids[device];
+ xds110.pid = pids[device];
+
+ /* Save the debug interface and endpoints for the device */
+ xds110.interface = interfaces[device];
+ xds110.endpoint_in = endpoints_in[device] | LIBUSB_ENDPOINT_IN;
+ xds110.endpoint_out = endpoints_out[device] | LIBUSB_ENDPOINT_OUT;
+
/* Save the context and device handles */
xds110.ctx = ctx;
xds110.dev = dev;
@@ -380,7 +423,7 @@ static bool usb_connect(void)
(void)libusb_set_auto_detach_kernel_driver(dev, 1);
/* Claim the debug interface on the XDS110 */
- result = libusb_claim_interface(dev, INTERFACE_DEBUG);
+ result = libusb_claim_interface(dev, xds110.interface);
} else {
/* Couldn't find an XDS110, flag the error */
result = -1;
@@ -390,7 +433,7 @@ static bool usb_connect(void)
if (0 != result) {
if (NULL != dev) {
/* Release the debug and data interface on the XDS110 */
- (void)libusb_release_interface(dev, INTERFACE_DEBUG);
+ (void)libusb_release_interface(dev, xds110.interface);
libusb_close(dev);
}
if (NULL != ctx)
@@ -412,7 +455,7 @@ static void usb_disconnect(void)
{
if (NULL != xds110.dev) {
/* Release the debug and data interface on the XDS110 */
- (void)libusb_release_interface(xds110.dev, INTERFACE_DEBUG);
+ (void)libusb_release_interface(xds110.dev, xds110.interface);
libusb_close(xds110.dev);
xds110.dev = NULL;
}
@@ -436,7 +479,7 @@ static bool usb_read(unsigned char *buffer, int size, int *bytes_read,
if (0 == timeout)
timeout = DEFAULT_TIMEOUT;
- result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_IN, buffer, size,
+ result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_in, buffer, size,
bytes_read, timeout);
return (0 == result) ? true : false;
@@ -451,13 +494,13 @@ static bool usb_write(unsigned char *buffer, int size, int *written)
if (NULL == xds110.dev || NULL == buffer)
return false;
- result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_OUT, buffer,
+ result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer,
size, &bytes_written, 0);
while (LIBUSB_ERROR_PIPE == result && retries < 3) {
/* Try clearing the pipe stall and retry transfer */
- libusb_clear_halt(xds110.dev, ENDPOINT_DEBUG_OUT);
- result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_OUT, buffer,
+ libusb_clear_halt(xds110.dev, xds110.endpoint_out);
+ result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer,
size, &bytes_written, 0);
retries++;
}
@@ -1345,6 +1388,7 @@ static void xds110_show_info(void)
{
uint32_t firmware = xds110.firmware;
+ LOG_INFO("XDS110: vid/pid = %04x/%04x", xds110.vid, xds110.pid);
LOG_INFO("XDS110: firmware version = %d.%d.%d.%d",
(((firmware >> 28) & 0xf) * 10) + ((firmware >> 24) & 0xf),
(((firmware >> 20) & 0xf) * 10) + ((firmware >> 16) & 0xf),
@@ -1592,48 +1636,58 @@ static void xds110_flush(void)
xds110.txn_result_count = 0;
}
-static void xds110_execute_reset(struct jtag_command *cmd)
+static int xds110_reset(int trst, int srst)
{
- char trst;
- char srst;
+ uint8_t value;
+ bool success;
+ int retval = ERROR_OK;
- if (cmd->cmd.reset->trst != -1) {
- if (cmd->cmd.reset->trst == 0) {
+ if (trst != -1) {
+ if (trst == 0) {
/* Deassert nTRST (active low) */
- trst = 1;
+ value = 1;
} else {
/* Assert nTRST (active low) */
- trst = 0;
+ value = 0;
}
- (void)xds_set_trst(trst);
+ success = xds_set_trst(value);
+ if (!success)
+ retval = ERROR_FAIL;
}
- if (cmd->cmd.reset->srst != -1) {
- if (cmd->cmd.reset->srst == 0) {
+ if (srst != -1) {
+ if (srst == 0) {
/* Deassert nSRST (active low) */
- srst = 1;
+ value = 1;
} else {
/* Assert nSRST (active low) */
- srst = 0;
+ value = 0;
}
- (void)xds_set_srst(srst);
+ success = xds_set_srst(value);
+ if (!success)
+ retval = ERROR_FAIL;
/* Toggle TCK to trigger HIB on CC13x/CC26x devices */
- (void)xds_cycle_tck(60000);
+ if (success && !xds110.is_swd_mode) {
+ /* Toggle TCK for about 50 ms */
+ success = xds_cycle_tck(xds110.speed * 50);
+ }
+
+ if (!success)
+ retval = ERROR_FAIL;
}
+
+ return retval;
}
static void xds110_execute_sleep(struct jtag_command *cmd)
{
jtag_sleep(cmd->cmd.sleep->us);
- return;
}
static void xds110_execute_tlr_reset(struct jtag_command *cmd)
{
(void)xds_goto_state(XDS_JTAG_STATE_RESET);
-
- return;
}
static void xds110_execute_pathmove(struct jtag_command *cmd)
@@ -1669,8 +1723,6 @@ static void xds110_execute_pathmove(struct jtag_command *cmd)
}
free((void *)path);
-
- return;
}
static void xds110_queue_scan(struct jtag_command *cmd)
@@ -1742,8 +1794,6 @@ static void xds110_queue_scan(struct jtag_command *cmd)
}
xds110.txn_request_size += total_bytes;
xds110.txn_result_size += total_bytes;
-
- return;
}
static void xds110_queue_runtest(struct jtag_command *cmd)
@@ -1763,8 +1813,6 @@ static void xds110_queue_runtest(struct jtag_command *cmd)
xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff;
xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff;
xds110.txn_requests[xds110.txn_request_size++] = end_state;
-
- return;
}
static void xds110_queue_stableclocks(struct jtag_command *cmd)
@@ -1781,17 +1829,11 @@ static void xds110_queue_stableclocks(struct jtag_command *cmd)
xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 8) & 0xff;
xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff;
xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff;
-
- return;
}
static void xds110_execute_command(struct jtag_command *cmd)
{
switch (cmd->type) {
- case JTAG_RESET:
- xds110_flush();
- xds110_execute_reset(cmd);
- break;
case JTAG_SLEEP:
xds110_flush();
xds110_execute_sleep(cmd);
@@ -1837,6 +1879,8 @@ static int xds110_execute_queue(void)
static int xds110_speed(int speed)
{
+ double freq_to_use;
+ uint32_t delay_count;
bool success;
if (speed == 0) {
@@ -1844,61 +1888,110 @@ static int xds110_speed(int speed)
return ERROR_JTAG_NOT_IMPLEMENTED;
}
- if (speed > XDS110_MAX_TCK_SPEED) {
- LOG_INFO("XDS110: reduce speed request: %dkHz to %dkHz maximum",
- speed, XDS110_MAX_TCK_SPEED);
- speed = XDS110_MAX_TCK_SPEED;
- }
-
if (speed < XDS110_MIN_TCK_SPEED) {
- LOG_INFO("XDS110: increase speed request: %dkHz to %dkHz minimum",
+ LOG_INFO("XDS110: increase speed request: %d kHz to %d kHz minimum",
speed, XDS110_MIN_TCK_SPEED);
speed = XDS110_MIN_TCK_SPEED;
}
- /* The default is the maximum frequency the XDS110 can support */
- uint32_t freq_to_use = XDS110_MAX_TCK_SPEED * 1000; /* Hz */
- uint32_t delay_count = 0;
+ /* Older XDS110 firmware had inefficient scan routines and could only */
+ /* achieve a peak TCK frequency of about 2500 kHz */
+ if (xds110.firmware < FAST_TCK_FIRMWARE_VERSION) {
- if (XDS110_MAX_TCK_SPEED != speed) {
- freq_to_use = speed * 1000; /* Hz */
+ /* Check for request for top speed or higher */
+ if (speed >= XDS110_MAX_SLOW_TCK_SPEED) {
- /* Calculate the delay count value */
- double one_giga = 1000000000;
- /* Get the pulse duration for the maximum frequency supported in ns */
- double max_freq_pulse_duration = one_giga /
- (XDS110_MAX_TCK_SPEED * 1000);
+ /* Inform user that speed was adjusted down to max possible */
+ if (speed > XDS110_MAX_SLOW_TCK_SPEED) {
+ LOG_INFO(
+ "XDS110: reduce speed request: %d kHz to %d kHz maximum",
+ speed, XDS110_MAX_SLOW_TCK_SPEED);
+ speed = XDS110_MAX_SLOW_TCK_SPEED;
+ }
+ delay_count = 0;
- /* Convert frequency to pulse duration */
- double freq_to_pulse_width_in_ns = one_giga / freq_to_use;
+ } else {
- /*
- * Start with the pulse duration for the maximum frequency. Keep
- * decrementing the time added by each count value till the requested
- * frequency pulse is less than the calculated value.
- */
- double current_value = max_freq_pulse_duration;
+ const double XDS110_TCK_PULSE_INCREMENT = 66.0;
+ freq_to_use = speed * 1000; /* Hz */
+ delay_count = 0;
- while (current_value < freq_to_pulse_width_in_ns) {
- current_value += XDS110_TCK_PULSE_INCREMENT;
- ++delay_count;
+ /* Calculate the delay count value */
+ double one_giga = 1000000000;
+ /* Get the pulse duration for the max frequency supported in ns */
+ double max_freq_pulse_duration = one_giga /
+ (XDS110_MAX_SLOW_TCK_SPEED * 1000);
+
+ /* Convert frequency to pulse duration */
+ double freq_to_pulse_width_in_ns = one_giga / freq_to_use;
+
+ /*
+ * Start with the pulse duration for the maximum frequency. Keep
+ * decrementing time added by each count value till the requested
+ * frequency pulse is less than the calculated value.
+ */
+ double current_value = max_freq_pulse_duration;
+
+ while (current_value < freq_to_pulse_width_in_ns) {
+ current_value += XDS110_TCK_PULSE_INCREMENT;
+ ++delay_count;
+ }
+
+ /*
+ * Determine which delay count yields the best match.
+ * The one obtained above or one less.
+ */
+ if (delay_count) {
+ double diff_freq_1 = freq_to_use -
+ (one_giga / (max_freq_pulse_duration +
+ (XDS110_TCK_PULSE_INCREMENT * delay_count)));
+ double diff_freq_2 = (one_giga / (max_freq_pulse_duration +
+ (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) -
+ freq_to_use;
+
+ /* One less count value yields a better match */
+ if (diff_freq_1 > diff_freq_2)
+ --delay_count;
+ }
}
- /*
- * Determine which delay count yields the best match.
- * The one obtained above or one less.
- */
- if (delay_count) {
- double diff_freq_1 = freq_to_use -
- (one_giga / (max_freq_pulse_duration +
- (XDS110_TCK_PULSE_INCREMENT * delay_count)));
- double diff_freq_2 = (one_giga / (max_freq_pulse_duration +
- (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) -
- freq_to_use;
+ /* Newer firmware has reworked TCK routines that are much more efficient */
+ /* and can now achieve a peak TCK frequency of 14000 kHz */
+ } else {
- /* One less count value yields a better match */
- if (diff_freq_1 > diff_freq_2)
- --delay_count;
+ if (speed >= XDS110_MAX_FAST_TCK_SPEED) {
+ if (speed > XDS110_MAX_FAST_TCK_SPEED) {
+ LOG_INFO(
+ "XDS110: reduce speed request: %d kHz to %d kHz maximum",
+ speed, XDS110_MAX_FAST_TCK_SPEED);
+ speed = XDS110_MAX_FAST_TCK_SPEED;
+ }
+ delay_count = 0;
+ } else if (speed >= 12000 && xds110.firmware >=
+ FAST_TCK_PLUS_FIRMWARE_VERSION) {
+ delay_count = FAST_TCK_DELAY_12000_KHZ;
+ } else if (speed >= 10000 && xds110.firmware >=
+ FAST_TCK_PLUS_FIRMWARE_VERSION) {
+ delay_count = FAST_TCK_DELAY_10000_KHZ;
+ } else if (speed >= 8500) {
+ delay_count = FAST_TCK_DELAY_8500_KHZ;
+ } else if (speed >= 5500) {
+ delay_count = FAST_TCK_DELAY_5500_KHZ;
+ } else {
+ /* Calculate the delay count to set the frequency */
+ /* Formula determined by measuring the waveform on Saeleae logic */
+ /* analyzer using known values for delay count */
+ const double m = 17100000.0; /* slope */
+ const double b = -1.02; /* y-intercept */
+
+ freq_to_use = speed * 1000; /* Hz */
+ double period = 1.0/freq_to_use;
+ double delay = m * period + b;
+
+ if (delay < 1.0)
+ delay_count = 1;
+ else
+ delay_count = (uint32_t)delay;
}
}
@@ -1953,11 +2046,8 @@ COMMAND_HANDLER(xds110_handle_serial_command)
xds110.serial[i] = (char)serial[i];
xds110.serial[len] = 0;
- } else {
- LOG_ERROR("XDS110: expected exactly one argument to xds110_serial "
- "");
- return ERROR_FAIL;
- }
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
return ERROR_OK;
}
@@ -1978,11 +2068,8 @@ COMMAND_HANDLER(xds110_handle_supply_voltage_command)
return ERROR_FAIL;
}
xds110.voltage = voltage;
- } else {
- LOG_ERROR("XDS110: expected one argument to xds110_supply_voltage "
- "");
- return ERROR_FAIL;
- }
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
return ERROR_OK;
}
@@ -1992,8 +2079,22 @@ static const struct command_registration xds110_subcommand_handlers[] = {
.name = "info",
.handler = &xds110_handle_info_command,
.mode = COMMAND_EXEC,
- .usage = "",
.help = "show XDS110 info",
+ .usage = "",
+ },
+ {
+ .name = "serial",
+ .handler = &xds110_handle_serial_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the XDS110 probe serial number",
+ .usage = "serial_string",
+ },
+ {
+ .name = "supply",
+ .handler = &xds110_handle_supply_voltage_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the XDS110 probe supply voltage",
+ .usage = "voltage_in_millivolts",
},
COMMAND_REGISTRATION_DONE
};
@@ -2003,23 +2104,9 @@ static const struct command_registration xds110_command_handlers[] = {
.name = "xds110",
.mode = COMMAND_ANY,
.help = "perform XDS110 management",
- .usage = "",
+ .usage = "",
.chain = xds110_subcommand_handlers,
},
- {
- .name = "xds110_serial",
- .handler = &xds110_handle_serial_command,
- .mode = COMMAND_CONFIG,
- .help = "set the XDS110 probe serial number",
- .usage = "serial_string",
- },
- {
- .name = "xds110_supply_voltage",
- .handler = &xds110_handle_supply_voltage_command,
- .mode = COMMAND_CONFIG,
- .help = "set the XDS110 probe supply voltage",
- .usage = "supply_voltage (millivolts)",
- },
COMMAND_REGISTRATION_DONE
};
@@ -2033,16 +2120,22 @@ static const struct swd_driver xds110_swd_driver = {
static const char * const xds110_transport[] = { "swd", "jtag", NULL };
-struct jtag_interface xds110_interface = {
- .name = "xds110",
- .commands = xds110_command_handlers,
- .swd = &xds110_swd_driver,
- .transports = xds110_transport,
-
+static struct jtag_interface xds110_interface = {
.execute_queue = xds110_execute_queue,
- .speed = xds110_speed,
- .speed_div = xds110_speed_div,
- .khz = xds110_khz,
+};
+
+struct adapter_driver xds110_adapter_driver = {
+ .name = "xds110",
+ .transports = xds110_transport,
+ .commands = xds110_command_handlers,
+
.init = xds110_init,
.quit = xds110_quit,
+ .reset = xds110_reset,
+ .speed = xds110_speed,
+ .khz = xds110_khz,
+ .speed_div = xds110_speed_div,
+
+ .jtag_ops = &xds110_interface,
+ .swd_ops = &xds110_swd_driver,
};
diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c
new file mode 100644
index 000000000..17438593a
--- /dev/null
+++ b/src/jtag/drivers/xlnx-pcie-xvc.c
@@ -0,0 +1,487 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2019 Google, LLC.
+ * Author: Moritz Fischer
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+/* Available only from kernel v4.10 */
+#ifndef PCI_CFG_SPACE_EXP_SIZE
+#define PCI_CFG_SPACE_EXP_SIZE 4096
+#endif
+
+#define PCIE_EXT_CAP_LST 0x100
+
+#define XLNX_XVC_EXT_CAP 0x00
+#define XLNX_XVC_VSEC_HDR 0x04
+#define XLNX_XVC_LEN_REG 0x0C
+#define XLNX_XVC_TMS_REG 0x10
+#define XLNX_XVC_TDx_REG 0x14
+
+#define XLNX_XVC_CAP_SIZE 0x20
+#define XLNX_XVC_VSEC_ID 0x8
+#define XLNX_XVC_MAX_BITS 0x20
+
+struct xlnx_pcie_xvc {
+ int fd;
+ unsigned offset;
+ char *device;
+};
+
+static struct xlnx_pcie_xvc xlnx_pcie_xvc_state;
+static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state;
+
+static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val)
+{
+ uint32_t res;
+ int err;
+
+ /* Note: This should be ok endianess-wise because by going
+ * through sysfs the kernel does the conversion in the config
+ * space accessor functions
+ */
+ err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res),
+ xlnx_pcie_xvc->offset + offset);
+ if (err != sizeof(res)) {
+ LOG_ERROR("Failed to read offset %x", offset);
+ return ERROR_JTAG_DEVICE_ERROR;
+ }
+
+ if (val)
+ *val = res;
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val)
+{
+ int err;
+
+ /* Note: This should be ok endianess-wise because by going
+ * through sysfs the kernel does the conversion in the config
+ * space accessor functions
+ */
+ err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val),
+ xlnx_pcie_xvc->offset + offset);
+ if (err != sizeof(val)) {
+ LOG_ERROR("Failed to write offset: %x with value: %x",
+ offset, val);
+ return ERROR_JTAG_DEVICE_ERROR;
+ }
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi,
+ uint32_t *tdo)
+{
+ int err;
+
+ err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits);
+ if (err != ERROR_OK)
+ return err;
+
+ err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms);
+ if (err != ERROR_OK)
+ return err;
+
+ err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDx_REG, tdi);
+ if (err != ERROR_OK)
+ return err;
+
+ err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDx_REG, tdo);
+ if (err != ERROR_OK)
+ return err;
+
+ if (tdo)
+ LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: %x",
+ num_bits, tms, tdi, *tdo);
+ else
+ LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: ",
+ num_bits, tms, tdi);
+ return ERROR_OK;
+}
+
+int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd)
+{
+ int tms = tap_get_state() == TAP_RESET ? 1 : 0;
+ size_t left = cmd->cmd.stableclocks->num_cycles;
+ size_t write;
+ int err;
+
+ LOG_DEBUG("stableclocks %i cycles", cmd->cmd.runtest->num_cycles);
+
+ while (left) {
+ write = MIN(XLNX_XVC_MAX_BITS, left);
+ err = xlnx_pcie_xvc_transact(write, tms, 0, NULL);
+ if (err != ERROR_OK)
+ return err;
+ left -= write;
+ };
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_execute_statemove(size_t skip)
+{
+ uint8_t tms_scan = tap_get_tms_path(tap_get_state(),
+ tap_get_end_state());
+ int tms_count = tap_get_tms_path_len(tap_get_state(),
+ tap_get_end_state());
+ int err;
+
+ LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip,
+ tap_state_name(tap_get_state()),
+ tap_state_name(tap_get_end_state()));
+
+
+ err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL);
+ if (err != ERROR_OK)
+ return err;
+
+ tap_set_state(tap_get_end_state());
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd)
+{
+ int err = ERROR_OK;
+
+ LOG_DEBUG("runtest %i cycles, end in %i",
+ cmd->cmd.runtest->num_cycles,
+ cmd->cmd.runtest->end_state);
+
+ tap_state_t tmp_state = tap_get_end_state();
+
+ if (tap_get_state() != TAP_IDLE) {
+ tap_set_end_state(TAP_IDLE);
+ err = xlnx_pcie_xvc_execute_statemove(0);
+ if (err != ERROR_OK)
+ return err;
+ };
+
+ size_t left = cmd->cmd.runtest->num_cycles;
+ size_t write;
+
+ while (left) {
+ write = MIN(XLNX_XVC_MAX_BITS, left);
+ err = xlnx_pcie_xvc_transact(write, 0, 0, NULL);
+ if (err != ERROR_OK)
+ return err;
+ left -= write;
+ };
+
+ tap_set_end_state(tmp_state);
+ if (tap_get_state() != tap_get_end_state())
+ err = xlnx_pcie_xvc_execute_statemove(0);
+
+ return err;
+}
+
+static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd)
+{
+ size_t num_states = cmd->cmd.pathmove->num_states;
+ tap_state_t *path = cmd->cmd.pathmove->path;
+ int err = ERROR_OK;
+ size_t i;
+
+ LOG_DEBUG("pathmove: %i states, end in %i",
+ cmd->cmd.pathmove->num_states,
+ cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
+
+ for (i = 0; i < num_states; i++) {
+ if (path[i] == tap_state_transition(tap_get_state(), false)) {
+ err = xlnx_pcie_xvc_transact(1, 1, 0, NULL);
+ } else if (path[i] == tap_state_transition(tap_get_state(), true)) {
+ err = xlnx_pcie_xvc_transact(1, 0, 0, NULL);
+ } else {
+ LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.",
+ tap_state_name(tap_get_state()),
+ tap_state_name(path[i]));
+ err = ERROR_JTAG_QUEUE_FAILED;
+ }
+ if (err != ERROR_OK)
+ return err;
+ tap_set_state(path[i]);
+ }
+
+ tap_set_end_state(tap_get_state());
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd)
+{
+ enum scan_type type = jtag_scan_type(cmd->cmd.scan);
+ tap_state_t saved_end_state = cmd->cmd.scan->end_state;
+ bool ir_scan = cmd->cmd.scan->ir_scan;
+ uint32_t tdi, tms, tdo;
+ uint8_t *buf, *rd_ptr;
+ int err, scan_size;
+ size_t write;
+ size_t left;
+
+ scan_size = jtag_build_buffer(cmd->cmd.scan, &buf);
+ rd_ptr = buf;
+ LOG_DEBUG("%s scan type %d %d bits; starts in %s end in %s",
+ (cmd->cmd.scan->ir_scan) ? "IR" : "DR", type, scan_size,
+ tap_state_name(tap_get_state()),
+ tap_state_name(cmd->cmd.scan->end_state));
+
+ /* If we're in TAP_DR_SHIFT state but need to do a IR_SCAN or
+ * vice-versa, do a statemove to corresponding other state, then restore
+ * end state
+ */
+ if (ir_scan && tap_get_state() != TAP_IRSHIFT) {
+ tap_set_end_state(TAP_IRSHIFT);
+ err = xlnx_pcie_xvc_execute_statemove(0);
+ if (err != ERROR_OK)
+ goto out_err;
+ tap_set_end_state(saved_end_state);
+ } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) {
+ tap_set_end_state(TAP_DRSHIFT);
+ err = xlnx_pcie_xvc_execute_statemove(0);
+ if (err != ERROR_OK)
+ goto out_err;
+ tap_set_end_state(saved_end_state);
+ }
+
+ left = scan_size;
+ while (left) {
+ write = MIN(XLNX_XVC_MAX_BITS, left);
+ /* the last TMS should be a 1, to leave the state */
+ tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0;
+ tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0;
+ err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ?
+ &tdo : NULL);
+ if (err != ERROR_OK)
+ goto out_err;
+ left -= write;
+ if (type != SCAN_OUT)
+ buf_set_u32(rd_ptr, 0, write, tdo);
+ rd_ptr += sizeof(uint32_t);
+ };
+
+ err = jtag_read_buffer(buf, cmd->cmd.scan);
+ if (buf)
+ free(buf);
+
+ if (tap_get_state() != tap_get_end_state())
+ err = xlnx_pcie_xvc_execute_statemove(1);
+
+ return err;
+
+out_err:
+ if (buf)
+ free(buf);
+ return err;
+}
+
+static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd)
+{
+ LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst,
+ cmd->cmd.reset->srst);
+}
+
+static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd)
+{
+ LOG_DEBUG("sleep %" PRIi32 "", cmd->cmd.sleep->us);
+ usleep(cmd->cmd.sleep->us);
+}
+
+static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd)
+{
+ const size_t num_bits = cmd->cmd.tms->num_bits;
+ const uint8_t *bits = cmd->cmd.tms->bits;
+ size_t left, write;
+ uint32_t tms;
+ int err;
+
+ LOG_DEBUG("execute tms %zu", num_bits);
+
+ left = num_bits;
+ while (left) {
+ write = MIN(XLNX_XVC_MAX_BITS, left);
+ tms = buf_get_u32(bits, 0, write);
+ err = xlnx_pcie_xvc_transact(write, tms, 0, NULL);
+ if (err != ERROR_OK)
+ return err;
+ left -= write;
+ bits += 4;
+ };
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd)
+{
+ LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type);
+ switch (cmd->type) {
+ case JTAG_STABLECLOCKS:
+ return xlnx_pcie_xvc_execute_stableclocks(cmd);
+ case JTAG_RUNTEST:
+ return xlnx_pcie_xvc_execute_runtest(cmd);
+ case JTAG_TLR_RESET:
+ tap_set_end_state(cmd->cmd.statemove->end_state);
+ return xlnx_pcie_xvc_execute_statemove(0);
+ case JTAG_PATHMOVE:
+ return xlnx_pcie_xvc_execute_pathmove(cmd);
+ case JTAG_SCAN:
+ return xlnx_pcie_xvc_execute_scan(cmd);
+ case JTAG_RESET:
+ xlnx_pcie_xvc_execute_reset(cmd);
+ break;
+ case JTAG_SLEEP:
+ xlnx_pcie_xvc_execute_sleep(cmd);
+ break;
+ case JTAG_TMS:
+ return xlnx_pcie_xvc_execute_tms(cmd);
+ default:
+ LOG_ERROR("BUG: Unknown JTAG command type encountered.");
+ return ERROR_JTAG_QUEUE_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_execute_queue(void)
+{
+ struct jtag_command *cmd = jtag_command_queue;
+ int ret;
+
+ while (cmd) {
+ ret = xlnx_pcie_xvc_execute_command(cmd);
+
+ if (ret != ERROR_OK)
+ return ret;
+
+ cmd = cmd->next;
+ }
+
+ return ERROR_OK;
+}
+
+
+static int xlnx_pcie_xvc_init(void)
+{
+ char filename[PATH_MAX];
+ uint32_t cap, vh;
+ int err;
+
+ snprintf(filename, PATH_MAX, "/sys/bus/pci/devices/%s/config",
+ xlnx_pcie_xvc->device);
+ xlnx_pcie_xvc->fd = open(filename, O_RDWR | O_SYNC);
+ if (xlnx_pcie_xvc->fd < 0) {
+ LOG_ERROR("Failed to open device: %s", filename);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ LOG_INFO("Scanning PCIe device %s's for Xilinx XVC/PCIe ...",
+ xlnx_pcie_xvc->device);
+ /* Parse the PCIe extended capability list and try to find
+ * vendor specific header */
+ xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST;
+ while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) &&
+ xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) {
+ err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap);
+ if (err != ERROR_OK)
+ return err;
+ LOG_DEBUG("Checking capability at 0x%x; id=0x%04x version=0x%x next=0x%x",
+ xlnx_pcie_xvc->offset,
+ PCI_EXT_CAP_ID(cap),
+ PCI_EXT_CAP_VER(cap),
+ PCI_EXT_CAP_NEXT(cap));
+ if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) {
+ err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh);
+ if (err != ERROR_OK)
+ return err;
+ LOG_DEBUG("Checking possible match at 0x%x; id: 0x%x; rev: 0x%x; length: 0x%x",
+ xlnx_pcie_xvc->offset,
+ PCI_VNDR_HEADER_ID(vh),
+ PCI_VNDR_HEADER_REV(vh),
+ PCI_VNDR_HEADER_LEN(vh));
+ if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) &&
+ (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE))
+ break;
+ }
+ xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap);
+ }
+ if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) ||
+ xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) {
+ close(xlnx_pcie_xvc->fd);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ LOG_INFO("Found Xilinx XVC/PCIe capability at offset: 0x%x", xlnx_pcie_xvc->offset);
+
+ return ERROR_OK;
+}
+
+static int xlnx_pcie_xvc_quit(void)
+{
+ int err;
+
+ err = close(xlnx_pcie_xvc->fd);
+ if (err)
+ return err;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command)
+{
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* we can't really free this in a safe manner, so at least
+ * limit the memory we're leaking by freeing the old one first
+ * before allocating a new one ...
+ */
+ if (xlnx_pcie_xvc->device)
+ free(xlnx_pcie_xvc->device);
+
+ xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]);
+ return ERROR_OK;
+}
+
+static const struct command_registration xlnx_pcie_xvc_command_handlers[] = {
+ {
+ .name = "xlnx_pcie_xvc_config",
+ .handler = xlnx_pcie_xvc_handle_config_command,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure XVC/PCIe JTAG adapter",
+ .usage = "device",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static struct jtag_interface xlnx_pcie_xvc_interface = {
+ .execute_queue = &xlnx_pcie_xvc_execute_queue,
+};
+
+struct adapter_driver xlnx_pcie_xvc_adapter_driver = {
+ .name = "xlnx_pcie_xvc",
+ .transports = jtag_only,
+ .commands = xlnx_pcie_xvc_command_handlers,
+
+ .init = &xlnx_pcie_xvc_init,
+ .quit = &xlnx_pcie_xvc_quit,
+
+ .jtag_ops = &xlnx_pcie_xvc_interface,
+};
diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c
index 2abed210d..6d5cdc5e7 100644
--- a/src/jtag/hla/hla_interface.c
+++ b/src/jtag/hla/hla_interface.c
@@ -35,7 +35,7 @@
#include
-static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 };
+static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 };
int hl_interface_open(enum hl_transports tr)
{
@@ -127,22 +127,19 @@ static int hl_interface_quit(void)
return ERROR_OK;
}
-static int hl_interface_execute_queue(void)
+static int hl_interface_reset(int req_trst, int req_srst)
{
- LOG_DEBUG("hl_interface_execute_queue: ignored");
-
- return ERROR_OK;
+ return hl_if.layout->api->assert_srst(hl_if.handle, req_srst ? 0 : 1);
}
int hl_interface_init_reset(void)
{
- /* incase the adapter has not already handled asserting srst
+ /* in case the adapter has not already handled asserting srst
* we will attempt it again */
if (hl_if.param.connect_under_reset) {
- jtag_add_reset(0, 1);
- hl_if.layout->api->assert_srst(hl_if.handle, 0);
+ adapter_assert_reset();
} else {
- jtag_add_reset(0, 0);
+ adapter_deassert_reset();
}
return ERROR_OK;
@@ -192,11 +189,12 @@ int hl_interface_override_target(const char **targetname)
}
int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler)
{
if (hl_if.layout->api->config_trace)
- return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol,
- port_size, trace_freq);
+ return hl_if.layout->api->config_trace(hl_if.handle, enabled,
+ pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler);
else if (enabled) {
LOG_ERROR("The selected interface does not support tracing");
return ERROR_FAIL;
@@ -348,17 +346,19 @@ static const struct command_registration hl_interface_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct jtag_interface hl_interface = {
+struct adapter_driver hl_adapter_driver = {
.name = "hla",
- .supported = 0,
- .commands = hl_interface_command_handlers,
.transports = hl_transports,
+ .commands = hl_interface_command_handlers,
+
.init = hl_interface_init,
.quit = hl_interface_quit,
- .execute_queue = hl_interface_execute_queue,
+ .reset = hl_interface_reset,
.speed = &hl_interface_speed,
.khz = &hl_interface_khz,
.speed_div = &hl_interface_speed_div,
.config_trace = &hl_interface_config_trace,
.poll_trace = &hl_interface_poll_trace,
+
+ /* no ops for HLA, targets hla_target and stm8 intercept them all */
};
diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h
index 262025e98..b6e4a8b92 100644
--- a/src/jtag/hla/hla_interface.h
+++ b/src/jtag/hla/hla_interface.h
@@ -41,8 +41,6 @@ struct hl_interface_param_s {
/** List of recognised PIDs */
uint16_t pid[HLA_MAX_USB_IDS + 1];
/** */
- unsigned api;
- /** */
enum hl_transports transport;
/** */
bool connect_under_reset;
diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h
index 9f41b59a4..1d759e17d 100644
--- a/src/jtag/hla/hla_layout.h
+++ b/src/jtag/hla/hla_layout.h
@@ -91,8 +91,10 @@ struct hl_layout_api_s {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
- int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq);
+ int (*config_trace)(void *handle, bool enabled,
+ enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+ unsigned int *trace_freq, unsigned int traceclkin_freq,
+ uint16_t *prescaler);
/**
* Poll for new trace data
*
diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c
index ddacea36a..fbdddfd65 100644
--- a/src/jtag/hla/hla_transport.c
+++ b/src/jtag/hla/hla_transport.c
@@ -175,8 +175,6 @@ static int hl_transport_init(struct command_context *cmd_ctx)
tr = HL_TRANSPORT_SWD;
else if (strcmp(transport->name, "hla_jtag") == 0)
tr = HL_TRANSPORT_JTAG;
- else if (strcmp(transport->name, "stlink_swim") == 0)
- tr = HL_TRANSPORT_SWIM;
int retval = hl_interface_open(tr);
@@ -218,26 +216,18 @@ static struct transport hl_jtag_transport = {
.override_target = hl_interface_override_target,
};
-static struct transport stlink_swim_transport = {
- .name = "stlink_swim",
- .select = hl_transport_select,
- .init = hl_transport_init,
-};
-
-const char *hl_transports[] = { "hla_swd", "hla_jtag", "stlink_swim", NULL };
+const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL };
static void hl_constructor(void) __attribute__ ((constructor));
static void hl_constructor(void)
{
transport_register(&hl_swd_transport);
transport_register(&hl_jtag_transport);
- transport_register(&stlink_swim_transport);
}
bool transport_is_hla(void)
{
struct transport *t;
t = get_current_transport();
- return t == &hl_swd_transport || t == &hl_jtag_transport
- || t == &stlink_swim_transport;
+ return t == &hl_swd_transport || t == &hl_jtag_transport;
}
diff --git a/src/jtag/hla/hla_transport.h b/src/jtag/hla/hla_transport.h
index 07eb751e2..0e0bea25f 100644
--- a/src/jtag/hla/hla_transport.h
+++ b/src/jtag/hla/hla_transport.h
@@ -26,7 +26,6 @@ enum hl_transports {
HL_TRANSPORT_UNKNOWN = 0,
HL_TRANSPORT_SWD,
HL_TRANSPORT_JTAG,
- HL_TRANSPORT_SWIM
};
#endif /* OPENOCD_JTAG_HLA_HLA_TRANSPORT_H */
diff --git a/src/jtag/interface.c b/src/jtag/interface.c
index de132bbe8..56bbf6e51 100644
--- a/src/jtag/interface.c
+++ b/src/jtag/interface.c
@@ -45,7 +45,7 @@ void tap_set_state_impl(tap_state_t new_state)
state_follower = new_state;
}
-tap_state_t tap_get_state()
+tap_state_t tap_get_state(void)
{
return state_follower;
}
@@ -64,7 +64,7 @@ void tap_set_end_state(tap_state_t new_end_state)
end_state_follower = new_end_state;
}
-tap_state_t tap_get_end_state()
+tap_state_t tap_get_end_state(void)
{
return end_state_follower;
}
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index 905f1eb62..42598c1ae 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -26,6 +26,7 @@
#define OPENOCD_JTAG_INTERFACE_H
#include
+#include
#include
/* @file
@@ -192,32 +193,34 @@ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf,
* debugging interface.
*/
struct jtag_interface {
- /** The name of the JTAG interface driver. */
- const char * const name;
-
/**
* Bit vector listing capabilities exposed by this driver.
*/
unsigned supported;
#define DEBUG_CAP_TMS_SEQ (1 << 0)
- /** transports supported in C code (NULL terminated vector) */
- const char * const *transports;
-
- const struct swd_driver *swd;
-
/**
* Execute queued commands.
* @returns ERROR_OK on success, or an error code on failure.
*/
int (*execute_queue)(void);
+};
- /**
- * Set the interface speed.
- * @param speed The new interface speed setting.
- * @returns ERROR_OK on success, or an error code on failure.
- */
- int (*speed)(int speed);
+/**
+ * Represents a driver for a debugging interface
+ *
+ * @todo We need a per-instance structure too, and changes to pass
+ * that structure to the driver. Instances can for example be in
+ * either SWD or JTAG modes. This will help remove globals, and
+ * eventually to cope with systems which have more than one such
+ * debugging interface.
+ */
+struct adapter_driver {
+ /** The name of the interface driver. */
+ const char * const name;
+
+ /** transports supported in C code (NULL terminated vector) */
+ const char * const *transports;
/**
* The interface driver may register additional commands to expose
@@ -246,6 +249,29 @@ struct jtag_interface {
*/
int (*quit)(void);
+ /**
+ * Control (assert/deassert) the signals SRST and TRST on the interface.
+ * This function is synchronous and should be called after the adapter
+ * queue has been properly flushed.
+ * This function is optional.
+ * Adapters that don't support resets can either not define this function
+ * or return an error code.
+ * Adapters that don't support one of the two reset should ignore the
+ * request to assert the missing signal and eventually log an error.
+ *
+ * @param srst 1 to assert SRST, 0 to deassert SRST.
+ * @param trst 1 to assert TRST, 0 to deassert TRST.
+ * @returns ERROR_OK on success, or an error code on failure.
+ */
+ int (*reset)(int srst, int trst);
+
+ /**
+ * Set the interface speed.
+ * @param speed The new interface speed setting.
+ * @returns ERROR_OK on success, or an error code on failure.
+ */
+ int (*speed)(int speed);
+
/**
* Returns JTAG maxium speed for KHz. 0 = RTCK. The function returns
* a failure if it can't support the KHz/RTCK.
@@ -303,10 +329,14 @@ struct jtag_interface {
* @param trace_freq A pointer to the configured trace
* frequency; if it points to 0, the adapter driver must write
* its maximum supported rate there
+ * @param traceclkin_freq TRACECLKIN frequency provided to the TPIU in Hz
+ * @param prescaler Pointer to the SWO prescaler calculated by the
+ * adapter
* @returns ERROR_OK on success, an error code on failure.
*/
int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq);
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler);
/**
* Poll for new trace data
@@ -318,14 +348,31 @@ struct jtag_interface {
* @returns ERROR_OK on success, an error code on failure.
*/
int (*poll_trace)(uint8_t *buf, size_t *size);
+
+ /** Low-level JTAG APIs */
+ struct jtag_interface *jtag_ops;
+
+ /** Low-level SWD APIs */
+ const struct swd_driver *swd_ops;
+
+ /* DAP APIs over JTAG transport */
+ const struct dap_ops *dap_jtag_ops;
+
+ /* DAP APIs over SWD transport */
+ const struct dap_ops *dap_swd_ops;
+
+ /* SWIM APIs */
+ const struct swim_driver *swim_ops;
};
extern const char * const jtag_only[];
-void adapter_assert_reset(void);
-void adapter_deassert_reset(void);
+int adapter_resets(int assert_trst, int assert_srst);
+int adapter_assert_reset(void);
+int adapter_deassert_reset(void);
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq);
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler);
int adapter_poll_trace(uint8_t *buf, size_t *size);
#endif /* OPENOCD_JTAG_INTERFACE_H */
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 286a73ac6..7d3f8a8ca 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -34,106 +34,115 @@
/** @file
* This file includes declarations for all built-in jtag interfaces,
- * which are then listed in the jtag_interfaces array.
+ * which are then listed in the adapter_drivers array.
*
* Dynamic loading can be implemented be searching for shared libraries
- * that contain a jtag_interface structure that can added to this list.
+ * that contain an adapter_driver structure that can added to this list.
*/
#if BUILD_ZY1000 == 1
-extern struct jtag_interface zy1000_interface;
+extern struct adapter_driver zy1000_adapter_driver;
#elif defined(BUILD_MINIDRIVER_DUMMY)
-extern struct jtag_interface minidummy_interface;
+extern struct adapter_driver minidummy_adapter_driver;
#else /* standard drivers */
#if BUILD_PARPORT == 1
-extern struct jtag_interface parport_interface;
+extern struct adapter_driver parport_adapter_driver;
#endif
#if BUILD_DUMMY == 1
-extern struct jtag_interface dummy_interface;
+extern struct adapter_driver dummy_adapter_driver;
#endif
#if BUILD_FTDI == 1
-extern struct jtag_interface ftdi_interface;
+extern struct adapter_driver ftdi_adapter_driver;
#endif
#if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1
-extern struct jtag_interface usb_blaster_interface;
+extern struct adapter_driver usb_blaster_adapter_driver;
#endif
#if BUILD_JTAG_VPI == 1
-extern struct jtag_interface jtag_vpi_interface;
+extern struct adapter_driver jtag_vpi_adapter_driver;
#endif
#if BUILD_FT232R == 1
-extern struct jtag_interface ft232r_interface;
+extern struct adapter_driver ft232r_adapter_driver;
#endif
#if BUILD_AMTJTAGACCEL == 1
-extern struct jtag_interface amt_jtagaccel_interface;
+extern struct adapter_driver amt_jtagaccel_adapter_driver;
#endif
#if BUILD_EP93XX == 1
-extern struct jtag_interface ep93xx_interface;
+extern struct adapter_driver ep93xx_adapter_driver;
#endif
#if BUILD_AT91RM9200 == 1
-extern struct jtag_interface at91rm9200_interface;
+extern struct adapter_driver at91rm9200_adapter_driver;
#endif
#if BUILD_GW16012 == 1
-extern struct jtag_interface gw16012_interface;
+extern struct adapter_driver gw16012_adapter_driver;
#endif
#if BUILD_PRESTO
-extern struct jtag_interface presto_interface;
+extern struct adapter_driver presto_adapter_driver;
#endif
#if BUILD_USBPROG == 1
-extern struct jtag_interface usbprog_interface;
+extern struct adapter_driver usbprog_adapter_driver;
#endif
#if BUILD_OPENJTAG == 1
-extern struct jtag_interface openjtag_interface;
+extern struct adapter_driver openjtag_adapter_driver;
#endif
#if BUILD_JLINK == 1
-extern struct jtag_interface jlink_interface;
+extern struct adapter_driver jlink_adapter_driver;
#endif
#if BUILD_VSLLINK == 1
-extern struct jtag_interface vsllink_interface;
+extern struct adapter_driver vsllink_adapter_driver;
#endif
#if BUILD_RLINK == 1
-extern struct jtag_interface rlink_interface;
+extern struct adapter_driver rlink_adapter_driver;
#endif
#if BUILD_ULINK == 1
-extern struct jtag_interface ulink_interface;
+extern struct adapter_driver ulink_adapter_driver;
#endif
#if BUILD_ARMJTAGEW == 1
-extern struct jtag_interface armjtagew_interface;
+extern struct adapter_driver armjtagew_adapter_driver;
#endif
#if BUILD_BUSPIRATE == 1
-extern struct jtag_interface buspirate_interface;
+extern struct adapter_driver buspirate_adapter_driver;
#endif
#if BUILD_REMOTE_BITBANG == 1
-extern struct jtag_interface remote_bitbang_interface;
+extern struct adapter_driver remote_bitbang_adapter_driver;
#endif
#if BUILD_HLADAPTER == 1
-extern struct jtag_interface hl_interface;
+extern struct adapter_driver hl_adapter_driver;
#endif
#if BUILD_OSBDM == 1
-extern struct jtag_interface osbdm_interface;
+extern struct adapter_driver osbdm_adapter_driver;
#endif
#if BUILD_OPENDOUS == 1
-extern struct jtag_interface opendous_interface;
+extern struct adapter_driver opendous_adapter_driver;
#endif
#if BUILD_SYSFSGPIO == 1
-extern struct jtag_interface sysfsgpio_interface;
+extern struct adapter_driver sysfsgpio_adapter_driver;
+#endif
+#if BUILD_XLNX_PCIE_XVC == 1
+extern struct adapter_driver xlnx_pcie_xvc_adapter_driver;
#endif
#if BUILD_AICE == 1
-extern struct jtag_interface aice_interface;
+extern struct adapter_driver aice_adapter_driver;
#endif
#if BUILD_BCM2835GPIO == 1
-extern struct jtag_interface bcm2835gpio_interface;
+extern struct adapter_driver bcm2835gpio_adapter_driver;
#endif
#if BUILD_CMSIS_DAP == 1
-extern struct jtag_interface cmsis_dap_interface;
+extern struct adapter_driver cmsis_dap_adapter_driver;
#endif
#if BUILD_KITPROG == 1
-extern struct jtag_interface kitprog_interface;
+extern struct adapter_driver kitprog_adapter_driver;
#endif
#if BUILD_IMX_GPIO == 1
-extern struct jtag_interface imx_gpio_interface;
+extern struct adapter_driver imx_gpio_adapter_driver;
#endif
#if BUILD_XDS110 == 1
-extern struct jtag_interface xds110_interface;
+extern struct adapter_driver xds110_adapter_driver;
+#endif
+#if BUILD_HLADAPTER == 1
+extern struct adapter_driver stlink_dap_adapter_driver;
+#endif
+#if BUILD_RSHIM == 1
+extern struct adapter_driver rshim_dap_adapter_driver;
#endif
#endif /* standard drivers */
@@ -144,107 +153,111 @@ extern struct jtag_interface xds110_interface;
* The list should be defined to contain either one minidriver interface
* or some number of standard driver interfaces, never both.
*/
-struct jtag_interface *jtag_interfaces[] = {
+struct adapter_driver *adapter_drivers[] = {
#if BUILD_ZY1000 == 1
- &zy1000_interface,
+ &zy1000_adapter_driver,
#elif defined(BUILD_MINIDRIVER_DUMMY)
- &minidummy_interface,
+ &minidummy_adapter_driver,
#else /* standard drivers */
#if BUILD_PARPORT == 1
- &parport_interface,
+ &parport_adapter_driver,
#endif
#if BUILD_DUMMY == 1
- &dummy_interface,
+ &dummy_adapter_driver,
#endif
#if BUILD_FTDI == 1
- &ftdi_interface,
+ &ftdi_adapter_driver,
#endif
#if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1
- &usb_blaster_interface,
+ &usb_blaster_adapter_driver,
#endif
#if BUILD_JTAG_VPI == 1
- &jtag_vpi_interface,
+ &jtag_vpi_adapter_driver,
#endif
#if BUILD_FT232R == 1
- &ft232r_interface,
+ &ft232r_adapter_driver,
#endif
#if BUILD_AMTJTAGACCEL == 1
- &amt_jtagaccel_interface,
+ &amt_jtagaccel_adapter_driver,
#endif
#if BUILD_EP93XX == 1
- &ep93xx_interface,
+ &ep93xx_adapter_driver,
#endif
#if BUILD_AT91RM9200 == 1
- &at91rm9200_interface,
+ &at91rm9200_adapter_driver,
#endif
#if BUILD_GW16012 == 1
- &gw16012_interface,
+ &gw16012_adapter_driver,
#endif
#if BUILD_PRESTO
- &presto_interface,
+ &presto_adapter_driver,
#endif
#if BUILD_USBPROG == 1
- &usbprog_interface,
+ &usbprog_adapter_driver,
#endif
#if BUILD_OPENJTAG == 1
- &openjtag_interface,
+ &openjtag_adapter_driver,
#endif
#if BUILD_JLINK == 1
- &jlink_interface,
+ &jlink_adapter_driver,
#endif
#if BUILD_VSLLINK == 1
- &vsllink_interface,
+ &vsllink_adapter_driver,
#endif
#if BUILD_RLINK == 1
- &rlink_interface,
+ &rlink_adapter_driver,
#endif
#if BUILD_ULINK == 1
- &ulink_interface,
+ &ulink_adapter_driver,
#endif
#if BUILD_ARMJTAGEW == 1
- &armjtagew_interface,
+ &armjtagew_adapter_driver,
#endif
#if BUILD_BUSPIRATE == 1
- &buspirate_interface,
+ &buspirate_adapter_driver,
#endif
#if BUILD_REMOTE_BITBANG == 1
- &remote_bitbang_interface,
+ &remote_bitbang_adapter_driver,
#endif
#if BUILD_HLADAPTER == 1
- &hl_interface,
+ &hl_adapter_driver,
#endif
#if BUILD_OSBDM == 1
- &osbdm_interface,
+ &osbdm_adapter_driver,
#endif
#if BUILD_OPENDOUS == 1
- &opendous_interface,
+ &opendous_adapter_driver,
#endif
#if BUILD_SYSFSGPIO == 1
- &sysfsgpio_interface,
+ &sysfsgpio_adapter_driver,
+#endif
+#if BUILD_XLNX_PCIE_XVC == 1
+ &xlnx_pcie_xvc_adapter_driver,
#endif
#if BUILD_AICE == 1
- &aice_interface,
+ &aice_adapter_driver,
#endif
#if BUILD_BCM2835GPIO == 1
- &bcm2835gpio_interface,
+ &bcm2835gpio_adapter_driver,
#endif
#if BUILD_CMSIS_DAP == 1
- &cmsis_dap_interface,
+ &cmsis_dap_adapter_driver,
#endif
#if BUILD_KITPROG == 1
- &kitprog_interface,
+ &kitprog_adapter_driver,
#endif
#if BUILD_IMX_GPIO == 1
- &imx_gpio_interface,
+ &imx_gpio_adapter_driver,
#endif
#if BUILD_XDS110 == 1
- &xds110_interface,
+ &xds110_adapter_driver,
+#endif
+#if BUILD_HLADAPTER == 1
+ &stlink_dap_adapter_driver,
+#endif
+#if BUILD_RSHIM == 1
+ &rshim_dap_adapter_driver,
#endif
#endif /* standard drivers */
NULL,
};
-
-void jtag_interface_modules_load(const char *path)
-{
- /* @todo: implement dynamic module loading for JTAG interface drivers */
-}
diff --git a/src/jtag/interfaces.h b/src/jtag/interfaces.h
index 02d201b1f..ddbd73506 100644
--- a/src/jtag/interfaces.h
+++ b/src/jtag/interfaces.h
@@ -36,9 +36,6 @@
#include
-/** Dynamically load all JTAG interface modules from specified directory. */
-void jtag_interface_modules_load(const char *path);
-
-extern struct jtag_interface *jtag_interfaces[];
+extern struct adapter_driver *adapter_drivers[];
#endif /* OPENOCD_JTAG_INTERFACES_H */
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index c93243c47..7f033e0e7 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -76,6 +76,14 @@ typedef enum tap_state {
#endif
} tap_state_t;
+/**
+ * Defines arguments for reset functions
+ */
+#define SRST_DEASSERT 0
+#define SRST_ASSERT 1
+#define TRST_DEASSERT 0
+#define TRST_ASSERT 1
+
/**
* Function tap_state_name
* Returns a string suitable for display representing the JTAG tap_state
@@ -154,8 +162,8 @@ void jtag_tap_free(struct jtag_tap *tap);
struct jtag_tap *jtag_all_taps(void);
const char *jtag_tap_name(const struct jtag_tap *tap);
-struct jtag_tap *jtag_tap_by_string(const char* dotted_name);
-struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp* interp, Jim_Obj *obj);
+struct jtag_tap *jtag_tap_by_string(const char *dotted_name);
+struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *obj);
struct jtag_tap *jtag_tap_by_position(unsigned abs_position);
struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p);
unsigned jtag_tap_count_enabled(void);
diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c
index 2f260040d..7ee206732 100644
--- a/src/jtag/minidummy/minidummy.c
+++ b/src/jtag/minidummy/minidummy.c
@@ -24,18 +24,24 @@
#include
#include
-struct jtag_interface minidummy_interface = {
- .name = "minidummy",
+static struct jtag_interface minidummy_interface = {
.execute_queue = NULL,
- .speed = NULL,
+};
+
+struct adapter_driver minidummy_adapter_driver = {
+ .name = "minidummy",
.transports = jtag_only,
.commands = NULL,
+
.init = NULL,
.quit = NULL,
+ .speed = NULL,
.khz = NULL,
.speed_div = NULL,
.power_dropout = NULL,
.srst_asserted = NULL,
+
+ .jtag_ops = &minidummy_interface,
};
int interface_jtag_execute_queue(void)
@@ -77,7 +83,7 @@ int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits,
return ERROR_OK;
}
-int interface_jtag_add_tlr()
+int interface_jtag_add_tlr(void)
{
/* synchronously do the operation here */
@@ -164,7 +170,7 @@ void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *bu
int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode,
uint32_t *data, size_t count)
{
- int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, \
+ int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap,
uint32_t opcode, uint32_t *data, size_t count);
return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count);
}
diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl
index d57cafb23..f8c4ca0bf 100644
--- a/src/jtag/startup.tcl
+++ b/src/jtag/startup.tcl
@@ -34,16 +34,16 @@ proc init_reset { mode } {
proc power_restore {} {
echo "Sensed power restore, running reset init and halting GDB."
reset init
-
+
# Halt GDB so user can deal with a detected power restore.
#
# After GDB is halted, then output is no longer forwarded
# to the GDB console.
- set targets [target names]
+ set targets [target names]
foreach t $targets {
# New event script.
$t invoke-event arp_halt_gdb
- }
+ }
}
add_help_text power_restore "Overridable procedure run when power restore is detected. Runs 'reset init' by default."
@@ -65,11 +65,11 @@ proc srst_deasserted {} {
#
# After GDB is halted, then output is no longer forwarded
# to the GDB console.
- set targets [target names]
+ set targets [target names]
foreach t $targets {
# New event script.
$t invoke-event arp_halt_gdb
- }
+ }
}
add_help_text srst_deasserted "Overridable procedure run when srst deassert is detected. Runs 'reset init' by default."
@@ -120,18 +120,34 @@ proc jtag_ntrst_assert_width args {
# FIXME phase these aids out after about April 2011
#
proc jtag_khz args {
- echo "DEPRECATED! use 'adapter_khz' not 'jtag_khz'"
- eval adapter_khz $args
+ echo "DEPRECATED! use 'adapter speed' not 'jtag_khz'"
+ eval adapter speed $args
}
proc jtag_nsrst_delay args {
- echo "DEPRECATED! use 'adapter_nsrst_delay' not 'jtag_nsrst_delay'"
- eval adapter_nsrst_delay $args
+ echo "DEPRECATED! use 'adapter srst delay' not 'jtag_nsrst_delay'"
+ eval adapter srst delay $args
}
proc jtag_nsrst_assert_width args {
- echo "DEPRECATED! use 'adapter_nsrst_assert_width' not 'jtag_nsrst_assert_width'"
- eval adapter_nsrst_assert_width $args
+ echo "DEPRECATED! use 'adapter srst pulse_width' not 'jtag_nsrst_assert_width'"
+ eval adapter srst pulse_width $args
+}
+
+proc jtag_reset args {
+ echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'"
+ switch $args {
+ "0 0"
+ {eval adapter deassert trst deassert srst}
+ "0 1"
+ {eval adapter deassert trst assert srst}
+ "1 0"
+ {eval adapter assert trst deassert srst}
+ "1 1"
+ {eval adapter assert trst assert srst}
+ default
+ {return -code 1 -level 1 "jtag_reset: syntax error"}
+ }
}
# stlink migration helpers
@@ -160,4 +176,54 @@ proc stlink args {
eval hla $args
}
+proc adapter_khz args {
+ echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'"
+ eval adapter speed $args
+}
+
+proc adapter_name args {
+ echo "DEPRECATED! use 'adapter name' not 'adapter_name'"
+ eval adapter name $args
+}
+
+proc adapter_nsrst_delay args {
+ echo "DEPRECATED! use 'adapter srst delay' not 'adapter_nsrst_delay'"
+ eval adapter srst delay $args
+}
+
+proc adapter_nsrst_assert_width args {
+ echo "DEPRECATED! use 'adapter srst pulse_width' not 'adapter_nsrst_assert_width'"
+ eval adapter srst pulse_width $args
+}
+
+proc interface args {
+ echo "DEPRECATED! use 'adapter driver' not 'interface'"
+ eval adapter driver $args
+}
+
+proc interface_transports args {
+ echo "DEPRECATED! use 'adapter transports' not 'interface_transports'"
+ eval adapter transports $args
+}
+
+proc interface_list args {
+ echo "DEPRECATED! use 'adapter list' not 'interface_list'"
+ eval adapter list $args
+}
+
+proc ftdi_location args {
+ echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'"
+ eval adapter usb location $args
+}
+
+proc xds110_serial args {
+ echo "DEPRECATED! use 'xds110 serial' not 'xds110_serial'"
+ eval xds110 serial $args
+}
+
+proc xds110_supply_voltage args {
+ echo "DEPRECATED! use 'xds110 supply' not 'xds110_supply_voltage'"
+ eval xds110 supply $args
+}
+
# END MIGRATION AIDS
diff --git a/src/jtag/swd.h b/src/jtag/swd.h
index 0b32105a2..487cb85bf 100644
--- a/src/jtag/swd.h
+++ b/src/jtag/swd.h
@@ -213,14 +213,6 @@ static const uint8_t swd_seq_dormant_to_jtag[] = {
};
static const unsigned swd_seq_dormant_to_jtag_len = 160;
-enum swd_special_seq {
- LINE_RESET,
- JTAG_TO_SWD,
- SWD_TO_JTAG,
- SWD_TO_DORMANT,
- DORMANT_TO_SWD,
-};
-
struct swd_driver {
/**
* Initialize the debug link so it can perform SWD operations.
@@ -285,6 +277,5 @@ struct swd_driver {
};
int swd_init_reset(struct command_context *cmd_ctx);
-void swd_add_reset(int req_srst);
#endif /* OPENOCD_JTAG_SWD_H */
diff --git a/src/jtag/swim.c b/src/jtag/swim.c
new file mode 100644
index 000000000..936268b25
--- /dev/null
+++ b/src/jtag/swim.c
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * Copyright (C) 2020 by Antonio Borneo
+#include
+
+extern struct adapter_driver *adapter_driver;
+
+int swim_system_reset(void)
+{
+ assert(adapter_driver->swim_ops);
+
+ return adapter_driver->swim_ops->srst();
+}
+
+int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count,
+ uint8_t *buffer)
+{
+ assert(adapter_driver->swim_ops);
+
+ return adapter_driver->swim_ops->read_mem(addr, size, count, buffer);
+}
+
+int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count,
+ const uint8_t *buffer)
+{
+ assert(adapter_driver->swim_ops);
+
+ return adapter_driver->swim_ops->write_mem(addr, size, count, buffer);
+}
+
+int swim_reconnect(void)
+{
+ assert(adapter_driver->swim_ops);
+
+ return adapter_driver->swim_ops->reconnect();
+}
+
+COMMAND_HANDLER(handle_swim_newtap_command)
+{
+ struct jtag_tap *tap;
+
+ /*
+ * only need "basename" and "tap_type", but for backward compatibility
+ * ignore extra parameters
+ */
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ tap = calloc(1, sizeof(*tap));
+ if (!tap) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ tap->chip = strdup(CMD_ARGV[0]);
+ tap->tapname = strdup(CMD_ARGV[1]);
+ tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]);
+ if (!tap->chip || !tap->tapname || !tap->dotted_name) {
+ LOG_ERROR("Out of memory");
+ free(tap->dotted_name);
+ free(tap->tapname);
+ free(tap->chip);
+ free(tap);
+ return ERROR_FAIL;
+ }
+
+ LOG_DEBUG("Creating new SWIM \"tap\", Chip: %s, Tap: %s, Dotted: %s",
+ tap->chip, tap->tapname, tap->dotted_name);
+
+ /* default is enabled-after-reset */
+ tap->enabled = true;
+
+ jtag_tap_init(tap);
+ return ERROR_OK;
+}
+
+static const struct command_registration swim_transport_subcommand_handlers[] = {
+ {
+ .name = "newtap",
+ .handler = handle_swim_newtap_command,
+ .mode = COMMAND_CONFIG,
+ .help = "Create a new TAP instance named basename.tap_type, "
+ "and appends it to the scan chain.",
+ .usage = "basename tap_type",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration swim_transport_command_handlers[] = {
+ {
+ .name = "swim",
+ .mode = COMMAND_ANY,
+ .help = "perform swim adapter actions",
+ .usage = "",
+ .chain = swim_transport_subcommand_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static int swim_transport_select(struct command_context *cmd_ctx)
+{
+ LOG_DEBUG(__func__);
+
+ return register_commands(cmd_ctx, NULL, swim_transport_command_handlers);
+}
+
+static int swim_transport_init(struct command_context *cmd_ctx)
+{
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+ LOG_DEBUG(__func__);
+
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING)
+ adapter_assert_reset();
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ } else
+ adapter_deassert_reset();
+
+ return ERROR_OK;
+}
+
+static struct transport swim_transport = {
+ .name = "swim",
+ .select = swim_transport_select,
+ .init = swim_transport_init,
+};
+
+static void swim_constructor(void) __attribute__ ((constructor));
+static void swim_constructor(void)
+{
+ transport_register(&swim_transport);
+}
+
+bool transport_is_swim(void)
+{
+ return get_current_transport() == &swim_transport;
+}
diff --git a/src/jtag/swim.h b/src/jtag/swim.h
new file mode 100644
index 000000000..186e0cc71
--- /dev/null
+++ b/src/jtag/swim.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * Copyright (C) 2020 by Antonio Borneo expected_ids_cnt > 0)
? tap->expected_ids[0]
: 0));
@@ -987,7 +987,7 @@ COMMAND_HANDLER(handle_scan_chain_command)
(unsigned int)(expected_mask));
for (ii = 1; ii < tap->expected_ids_cnt; ii++) {
- snprintf(expected_id, sizeof expected_id, "0x%08x",
+ snprintf(expected_id, sizeof(expected_id), "0x%08x",
(unsigned) tap->expected_ids[ii]);
if (tap->ignore_version)
expected_id[2] = '*';
@@ -1059,34 +1059,6 @@ COMMAND_HANDLER(handle_jtag_rclk_command)
return retval;
}
-COMMAND_HANDLER(handle_jtag_reset_command)
-{
- if (CMD_ARGC != 2)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- int trst = -1;
- if (CMD_ARGV[0][0] == '1')
- trst = 1;
- else if (CMD_ARGV[0][0] == '0')
- trst = 0;
- else
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- int srst = -1;
- if (CMD_ARGV[1][0] == '1')
- srst = 1;
- else if (CMD_ARGV[1][0] == '0')
- srst = 0;
- else
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- if (adapter_init(CMD_CTX) != ERROR_OK)
- return ERROR_JTAG_INIT_FAILED;
-
- jtag_add_reset(trst, srst);
- return jtag_execute_queue();
-}
-
COMMAND_HANDLER(handle_runtest_command)
{
if (CMD_ARGC != 1)
@@ -1157,14 +1129,19 @@ COMMAND_HANDLER(handle_irscan_command)
return ERROR_FAIL;
}
- int field_size = tap->ir_length;
- fields[i].num_bits = field_size;
- uint8_t *v = malloc(DIV_ROUND_UP(field_size, 8));
-
uint64_t value;
retval = parse_u64(CMD_ARGV[i * 2 + 1], &value);
if (ERROR_OK != retval)
goto error_return;
+
+ int field_size = tap->ir_length;
+ fields[i].num_bits = field_size;
+ uint8_t *v = calloc(1, DIV_ROUND_UP(field_size, 8));
+ if (!v) {
+ LOG_ERROR("Out of memory");
+ goto error_return;
+ }
+
buf_set_u64(v, 0, field_size, value);
fields[i].out_value = v;
fields[i].in_value = NULL;
@@ -1331,14 +1308,6 @@ static const struct command_registration jtag_command_handlers[] = {
.help = "print current scan chain configuration",
.usage = ""
},
- {
- .name = "jtag_reset",
- .handler = handle_jtag_reset_command,
- .mode = COMMAND_EXEC,
- .help = "Set reset line values. Value '1' is active, "
- "value '0' is inactive.",
- .usage = "trst_active srst_active",
- },
{
.name = "runtest",
.handler = handle_runtest_command,
@@ -1350,7 +1319,7 @@ static const struct command_registration jtag_command_handlers[] = {
.name = "irscan",
.handler = handle_irscan_command,
.mode = COMMAND_EXEC,
- .help = "Execute Instruction Register (DR) scan. The "
+ .help = "Execute Instruction Register (IR) scan. The "
"specified opcodes are put into each TAP's IR, "
"and other TAPs are put in BYPASS.",
.usage = "[tap_name instruction]* ['-endstate' state_name]",
diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c
index 173498398..37af2f7ae 100644
--- a/src/jtag/zy1000/zy1000.c
+++ b/src/jtag/zy1000/zy1000.c
@@ -486,7 +486,7 @@ int interface_jtag_add_plain_dr_scan(int num_bits,
return ERROR_OK;
}
-int interface_jtag_add_tlr()
+int interface_jtag_add_tlr(void)
{
setCurrentState(TAP_RESET);
return ERROR_OK;
@@ -1237,17 +1237,23 @@ int zy1000_init(void)
return ERROR_OK;
}
-struct jtag_interface zy1000_interface = {
- .name = "ZY1000",
+static struct jtag_interface zy1000_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = NULL,
- .speed = zy1000_speed,
+};
+
+struct adapter_driver zy1000_adapter_driver = {
+ .name = "ZY1000",
.transports = jtag_only,
.commands = zy1000_commands,
+
.init = zy1000_init,
.quit = zy1000_quit,
+ .speed = zy1000_speed,
.khz = zy1000_khz,
.speed_div = zy1000_speed_div,
.power_dropout = zy1000_power_dropout,
.srst_asserted = zy1000_srst_asserted,
+
+ .jtag_ops = &zy1000_interface,
};
diff --git a/src/openocd.c b/src/openocd.c
index 2a9a0b3d4..886228425 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -345,6 +345,8 @@ int openocd_main(int argc, char *argv[])
command_context_mode(cmd_ctx, COMMAND_CONFIG);
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
+ server_host_os_entry();
+
/* Start the executable meat that can evolve into thread in future. */
ret = openocd_thread(argc, argv, cmd_ctx);
@@ -360,6 +362,8 @@ int openocd_main(int argc, char *argv[])
adapter_quit();
+ server_host_os_close();
+
/* Shutdown commandline interface */
command_exit(cmd_ctx);
diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c
index 9d89974cc..c45d9d645 100644
--- a/src/rtos/FreeRTOS.c
+++ b/src/rtos/FreeRTOS.c
@@ -157,7 +157,6 @@ static const struct symbols FreeRTOS_symbol_list[] = {
static int FreeRTOS_update_threads(struct rtos *rtos)
{
- int i = 0;
int retval;
int tasks_found = 0;
const struct FreeRTOS_params *param;
@@ -245,32 +244,40 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around");
return ERROR_FAIL;
}
- int64_t max_used_priority = 0;
+ uint64_t top_used_priority = 0;
+ /* FIXME: endianess error on almost all target_read_buffer(), see also
+ * other rtoses */
retval = target_read_buffer(rtos->target,
rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
param->pointer_width,
- (uint8_t *)&max_used_priority);
+ (uint8_t *)&top_used_priority);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRId64 "\r\n",
+ LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu64 "\r\n",
rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
- max_used_priority);
- if (max_used_priority > FREERTOS_MAX_PRIORITIES) {
- LOG_ERROR("FreeRTOS maximum used priority is unreasonably big, not proceeding: %" PRId64 "",
- max_used_priority);
+ top_used_priority);
+ if (top_used_priority > FREERTOS_MAX_PRIORITIES) {
+ LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu64,
+ top_used_priority);
return ERROR_FAIL;
}
+ /* uxTopUsedPriority was defined as configMAX_PRIORITIES - 1
+ * in old FreeRTOS versions (before V7.5.3)
+ * Use contrib/rtos-helpers/FreeRTOS-openocd.c to get compatible symbol
+ * in newer FreeRTOS versions.
+ * Here we restore the original configMAX_PRIORITIES value */
+ unsigned int config_max_priorities = top_used_priority + 1;
+
symbol_address_t *list_of_lists =
- malloc(sizeof(symbol_address_t) *
- (max_used_priority+1 + 5));
+ malloc(sizeof(symbol_address_t) * (config_max_priorities + 5));
if (!list_of_lists) {
- LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority);
+ LOG_ERROR("Error allocating memory for %u priorities", config_max_priorities);
return ERROR_FAIL;
}
- int num_lists;
- for (num_lists = 0; num_lists <= max_used_priority; num_lists++)
+ unsigned int num_lists;
+ for (num_lists = 0; num_lists < config_max_priorities; num_lists++)
list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address +
num_lists * param->list_width;
@@ -280,7 +287,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address;
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address;
- for (i = 0; i < num_lists; i++) {
+ for (unsigned int i = 0; i < num_lists; i++) {
if (list_of_lists[i] == 0)
continue;
@@ -295,7 +302,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
free(list_of_lists);
return retval;
}
- LOG_DEBUG("FreeRTOS: Read thread count for list %d at 0x%" PRIx64 ", value %" PRId64 "\r\n",
+ LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRId64 "\r\n",
i, list_of_lists[i], list_thread_count);
if (list_thread_count == 0)
@@ -313,7 +320,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
free(list_of_lists);
return retval;
}
- LOG_DEBUG("FreeRTOS: Read first item for list %d at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
+ LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
i, list_of_lists[i] + param->list_next_offset, list_elem_ptr);
while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index b3e14f8c2..8097c303b 100644
--- a/src/rtos/Makefile.am
+++ b/src/rtos/Makefile.am
@@ -11,7 +11,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/ThreadX.c \
%D%/eCos.c \
%D%/linux.c \
- %D%/ChibiOS.c \
+ %D%/chibios.c \
%D%/chromium-ec.c \
%D%/embKernel.c \
%D%/mqx.c \
diff --git a/src/rtos/ChibiOS.c b/src/rtos/chibios.c
similarity index 83%
rename from src/rtos/ChibiOS.c
rename to src/rtos/chibios.c
index 8839acc9a..4d2b1b2d7 100644
--- a/src/rtos/ChibiOS.c
+++ b/src/rtos/chibios.c
@@ -39,7 +39,7 @@
*
* @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT.
*/
-struct ChibiOS_chdebug {
+struct chibios_chdebug {
char ch_identifier[4]; /**< @brief Always set to "main". */
uint8_t ch_zero; /**< @brief Must be zero. */
uint8_t ch_size; /**< @brief Size of this structure. */
@@ -69,26 +69,26 @@ struct ChibiOS_chdebug {
/**
* @brief ChibiOS thread states.
*/
-static const char * const ChibiOS_thread_states[] = { "READY", "CURRENT",
+static const char * const chibios_thread_states[] = { "READY", "CURRENT",
"WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING",
"WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL"
};
-#define CHIBIOS_NUM_STATES (sizeof(ChibiOS_thread_states)/sizeof(char *))
+#define CHIBIOS_NUM_STATES (sizeof(chibios_thread_states)/sizeof(char *))
/* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
* chars ought to be enough.
*/
#define CHIBIOS_THREAD_NAME_STR_SIZE (64)
-struct ChibiOS_params {
+struct chibios_params {
const char *target_name;
- struct ChibiOS_chdebug *signature;
+ struct chibios_chdebug *signature;
const struct rtos_register_stacking *stacking_info;
};
-static struct ChibiOS_params ChibiOS_params_list[] = {
+static struct chibios_params chibios_params_list[] = {
{
"cortex_m", /* target_name */
0,
@@ -100,23 +100,23 @@ static struct ChibiOS_params ChibiOS_params_list[] = {
NULL, /* stacking_info */
}
};
-#define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params)))
+#define CHIBIOS_NUM_PARAMS ((int)(sizeof(chibios_params_list)/sizeof(struct chibios_params)))
-static bool ChibiOS_detect_rtos(struct target *target);
-static int ChibiOS_create(struct target *target);
-static int ChibiOS_update_threads(struct rtos *rtos);
-static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+static bool chibios_detect_rtos(struct target *target);
+static int chibios_create(struct target *target);
+static int chibios_update_threads(struct rtos *rtos);
+static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
-static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
-struct rtos_type ChibiOS_rtos = {
- .name = "ChibiOS",
+struct rtos_type chibios_rtos = {
+ .name = "chibios",
- .detect_rtos = ChibiOS_detect_rtos,
- .create = ChibiOS_create,
- .update_threads = ChibiOS_update_threads,
- .get_thread_reg_list = ChibiOS_get_thread_reg_list,
- .get_symbol_list_to_lookup = ChibiOS_get_symbol_list_to_lookup,
+ .detect_rtos = chibios_detect_rtos,
+ .create = chibios_create,
+ .update_threads = chibios_update_threads,
+ .get_thread_reg_list = chibios_get_thread_reg_list,
+ .get_symbol_list_to_lookup = chibios_get_symbol_list_to_lookup,
};
@@ -125,13 +125,13 @@ struct rtos_type ChibiOS_rtos = {
* use whatever is available.
*/
-enum ChibiOS_symbol_values {
- ChibiOS_VAL_rlist = 0,
- ChibiOS_VAL_ch = 1,
- ChibiOS_VAL_ch_debug = 2
+enum chibios_symbol_values {
+ CHIBIOS_VAL_RLIST = 0,
+ CHIBIOS_VAL_CH = 1,
+ CHIBIOS_VAL_CH_DEBUG = 2
};
-static symbol_table_elem_t ChibiOS_symbol_list[] = {
+static symbol_table_elem_t chibios_symbol_list[] = {
{ "rlist", 0, true}, /* Thread ready list */
{ "ch", 0, true}, /* System data structure */
{ "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */
@@ -141,13 +141,13 @@ static symbol_table_elem_t ChibiOS_symbol_list[] = {
/* Offset of the rlist structure within the system data structure (ch) */
#define CH_RLIST_OFFSET 0x00
-static int ChibiOS_update_memory_signature(struct rtos *rtos)
+static int chibios_update_memory_signature(struct rtos *rtos)
{
int retval;
- struct ChibiOS_params *param;
- struct ChibiOS_chdebug *signature;
+ struct chibios_params *param;
+ struct chibios_chdebug *signature;
- param = (struct ChibiOS_params *) rtos->rtos_specific_params;
+ param = (struct chibios_params *) rtos->rtos_specific_params;
/* Free existing memory description.*/
if (param->signature) {
@@ -162,7 +162,7 @@ static int ChibiOS_update_memory_signature(struct rtos *rtos)
}
retval = target_read_buffer(rtos->target,
- rtos->symbols[ChibiOS_VAL_ch_debug].address,
+ rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address,
sizeof(*signature),
(uint8_t *) signature);
if (retval != ERROR_OK) {
@@ -200,7 +200,7 @@ static int ChibiOS_update_memory_signature(struct rtos *rtos)
/* Currently, we have the inherent assumption that all address pointers
* are 32 bit wide. */
if (signature->ch_ptrsize != sizeof(uint32_t)) {
- LOG_ERROR("ChibiOS/RT target memory signature claims an address"
+ LOG_ERROR("ChibiOS/RT target memory signature claims an address "
"width unequal to 32 bits!");
free(signature);
return -1;
@@ -217,7 +217,7 @@ errfree:
}
-static int ChibiOS_update_stacking(struct rtos *rtos)
+static int chibios_update_stacking(struct rtos *rtos)
{
/* Sometimes the stacking can not be determined only by looking at the
* target name but only a runtime.
@@ -234,15 +234,15 @@ static int ChibiOS_update_stacking(struct rtos *rtos)
* - Since no threads are running during startup, the problem is solved
* by delaying stacking detection until there are more threads
* available than the current execution. In which case
- * ChibiOS_get_thread_reg_list is called.
+ * chibios_get_thread_reg_list is called.
*/
int retval;
if (!rtos->rtos_specific_params)
return -1;
- struct ChibiOS_params *param;
- param = (struct ChibiOS_params *) rtos->rtos_specific_params;
+ struct chibios_params *param;
+ param = (struct chibios_params *) rtos->rtos_specific_params;
/* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
@@ -274,10 +274,10 @@ static int ChibiOS_update_stacking(struct rtos *rtos)
return -1;
}
-static int ChibiOS_update_threads(struct rtos *rtos)
+static int chibios_update_threads(struct rtos *rtos)
{
int retval;
- const struct ChibiOS_params *param;
+ const struct chibios_params *param;
int tasks_found = 0;
int rtos_valid = -1;
@@ -289,10 +289,10 @@ static int ChibiOS_update_threads(struct rtos *rtos)
return -3;
}
- param = (const struct ChibiOS_params *) rtos->rtos_specific_params;
+ param = (const struct chibios_params *) rtos->rtos_specific_params;
/* Update the memory signature saved in the target memory */
if (!param->signature) {
- retval = ChibiOS_update_memory_signature(rtos);
+ retval = chibios_update_memory_signature(rtos);
if (retval != ERROR_OK) {
LOG_ERROR("Reading the memory signature of ChibiOS/RT failed");
return retval;
@@ -305,10 +305,10 @@ static int ChibiOS_update_threads(struct rtos *rtos)
/* ChibiOS does not save the current thread count. We have to first
* parse the double linked thread list to check for errors and the number of
* threads. */
- const uint32_t rlist = rtos->symbols[ChibiOS_VAL_rlist].address ?
- rtos->symbols[ChibiOS_VAL_rlist].address :
- rtos->symbols[ChibiOS_VAL_ch].address + CH_RLIST_OFFSET /* ChibiOS3 */;
- const struct ChibiOS_chdebug *signature = param->signature;
+ const uint32_t rlist = rtos->symbols[CHIBIOS_VAL_RLIST].address ?
+ rtos->symbols[CHIBIOS_VAL_RLIST].address :
+ rtos->symbols[CHIBIOS_VAL_CH].address + CH_RLIST_OFFSET /* ChibiOS3 */;
+ const struct chibios_chdebug *signature = param->signature;
uint32_t current;
uint32_t previous;
uint32_t older;
@@ -426,19 +426,19 @@ static int ChibiOS_update_threads(struct rtos *rtos)
strcpy(curr_thrd_details->thread_name_str, tmp_str);
/* State info */
- uint8_t threadState;
+ uint8_t thread_state;
const char *state_desc;
retval = target_read_u8(rtos->target,
- current + signature->cf_off_state, &threadState);
+ current + signature->cf_off_state, &thread_state);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading thread state from ChibiOS target");
return retval;
}
- if (threadState < CHIBIOS_NUM_STATES)
- state_desc = ChibiOS_thread_states[threadState];
+ if (thread_state < CHIBIOS_NUM_STATES)
+ state_desc = chibios_thread_states[thread_state];
else
state_desc = "Unknown";
@@ -465,25 +465,25 @@ static int ChibiOS_update_threads(struct rtos *rtos)
return 0;
}
-static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs)
{
int retval;
- const struct ChibiOS_params *param;
+ const struct chibios_params *param;
uint32_t stack_ptr = 0;
if ((rtos == NULL) || (thread_id == 0) ||
(rtos->rtos_specific_params == NULL))
return -1;
- param = (const struct ChibiOS_params *) rtos->rtos_specific_params;
+ param = (const struct chibios_params *) rtos->rtos_specific_params;
if (!param->signature)
return -1;
/* Update stacking if it can only be determined from runtime information */
if ((param->stacking_info == 0) &&
- (ChibiOS_update_stacking(rtos) != ERROR_OK)) {
+ (chibios_update_stacking(rtos) != ERROR_OK)) {
LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name);
return -1;
}
@@ -499,24 +499,24 @@ static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
}
-static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
{
- *symbol_list = malloc(sizeof(ChibiOS_symbol_list));
+ *symbol_list = malloc(sizeof(chibios_symbol_list));
if (*symbol_list == NULL)
return ERROR_FAIL;
- memcpy(*symbol_list, ChibiOS_symbol_list, sizeof(ChibiOS_symbol_list));
+ memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list));
return 0;
}
-static bool ChibiOS_detect_rtos(struct target *target)
+static bool chibios_detect_rtos(struct target *target)
{
if ((target->rtos->symbols != NULL) &&
- ((target->rtos->symbols[ChibiOS_VAL_rlist].address != 0) ||
- (target->rtos->symbols[ChibiOS_VAL_ch].address != 0))) {
+ ((target->rtos->symbols[CHIBIOS_VAL_RLIST].address != 0) ||
+ (target->rtos->symbols[CHIBIOS_VAL_CH].address != 0))) {
- if (target->rtos->symbols[ChibiOS_VAL_ch_debug].address == 0) {
+ if (target->rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address == 0) {
LOG_INFO("It looks like the target may be running ChibiOS "
"without ch_debug.");
return false;
@@ -529,11 +529,11 @@ static bool ChibiOS_detect_rtos(struct target *target)
return false;
}
-static int ChibiOS_create(struct target *target)
+static int chibios_create(struct target *target)
{
int i = 0;
while ((i < CHIBIOS_NUM_PARAMS) &&
- (0 != strcmp(ChibiOS_params_list[i].target_name, target->type->name))) {
+ (0 != strcmp(chibios_params_list[i].target_name, target->type->name))) {
i++;
}
if (i >= CHIBIOS_NUM_PARAMS) {
@@ -542,6 +542,6 @@ static int ChibiOS_create(struct target *target)
return -1;
}
- target->rtos->rtos_specific_params = (void *) &ChibiOS_params_list[i];
+ target->rtos->rtos_specific_params = (void *) &chibios_params_list[i];
return 0;
}
diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c
index 8a307f198..2f04963b4 100644
--- a/src/rtos/embKernel.c
+++ b/src/rtos/embKernel.c
@@ -135,7 +135,7 @@ static int embKernel_create(struct target *target)
}
static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param,
- struct thread_detail *details, const char* state_str)
+ struct thread_detail *details, const char *state_str)
{
int64_t task = 0;
int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
@@ -340,4 +340,3 @@ static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[
return 0;
}
-
diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c
index d36336927..cdcf026c3 100644
--- a/src/rtos/hwthread.c
+++ b/src/rtos/hwthread.c
@@ -216,7 +216,7 @@ static int hwthread_smp_init(struct target *target)
return hwthread_update_threads(target->rtos);
}
-static struct target *find_thread(struct target *target, int64_t thread_id)
+static struct target *hwthread_find_thread(struct target *target, int64_t thread_id)
{
/* Find the thread with that thread_id */
if (target == NULL)
@@ -240,7 +240,7 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct target *target = rtos->target;
- struct target *curr = find_thread(target, thread_id);
+ struct target *curr = hwthread_find_thread(target, thread_id);
if (curr == NULL)
return ERROR_FAIL;
@@ -278,7 +278,7 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
struct target *target = rtos->target;
- struct target *curr = find_thread(target, thread_id);
+ struct target *curr = hwthread_find_thread(target, thread_id);
if (curr == NULL) {
LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
return ERROR_FAIL;
@@ -315,7 +315,7 @@ int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
struct target *target = rtos->target;
- struct target *curr = find_thread(target, rtos->current_thread);
+ struct target *curr = hwthread_find_thread(target, rtos->current_thread);
if (curr == NULL)
return ERROR_FAIL;
@@ -338,7 +338,7 @@ static int hwthread_target_for_threadid(struct connection *connection, int64_t t
{
struct target *target = get_target_from_connection(connection);
- struct target *curr = find_thread(target, thread_id);
+ struct target *curr = hwthread_find_thread(target, thread_id);
if (curr == NULL)
return ERROR_FAIL;
diff --git a/src/rtos/linux.c b/src/rtos/linux.c
index 74172b70a..63659bb05 100644
--- a/src/rtos/linux.c
+++ b/src/rtos/linux.c
@@ -621,17 +621,17 @@ struct threads *liste_del_task(struct threads *task_list, struct threads **t,
struct threads *prev)
{
LOG_INFO("del task %" PRId64, (*t)->threadid);
- prev->next = (*t)->next;
-
- if (prev == task_list)
- task_list = prev;
+ if (prev)
+ prev->next = (*t)->next;
+ else
+ task_list = (*t)->next;
/* free content of threads */
if ((*t)->context)
free((*t)->context);
free(*t);
- *t = prev;
+ *t = prev ? prev : task_list;
return task_list;
}
@@ -725,6 +725,7 @@ int linux_get_tasks(struct target *target, int context)
/* check that this thread is not one the current threads already
* created */
+ uint32_t base_addr;
#ifdef PID_CHECK
if (!current_pid(linux_os, t->pid)) {
@@ -745,12 +746,13 @@ int linux_get_tasks(struct target *target, int context)
t->context =
cpu_context_read(target, t->base_addr,
&t->thread_info_addr);
+ base_addr = next_task(target, t);
} else {
/*LOG_INFO("thread %s is a current thread already created",t->name); */
+ base_addr = next_task(target, t);
free(t);
}
- uint32_t base_addr = next_task(target, t);
t = calloc(1, sizeof(struct threads));
t->base_addr = base_addr;
}
@@ -993,10 +995,8 @@ static int linux_task_update(struct target *target, int context)
if (context)
thread_list->context =
cpu_context_read(target,
- thread_list->
- base_addr,
- &thread_list->
- thread_info_addr);
+ thread_list->base_addr,
+ &thread_list->thread_info_addr);
} else {
/* it is a current thread no need to read context */
}
@@ -1178,7 +1178,7 @@ int linux_gdb_T_packet(struct connection *connection,
if (linux_os->threads_needs_update == 0) {
struct threads *temp = linux_os->thread_list;
- struct threads *prev = linux_os->thread_list;
+ struct threads *prev = NULL;
while (temp != NULL) {
if (temp->threadid == threadid) {
@@ -1188,9 +1188,8 @@ int linux_gdb_T_packet(struct connection *connection,
} else {
/* delete item in the list */
linux_os->thread_list =
- liste_del_task(linux_os->
- thread_list, &temp,
- prev);
+ liste_del_task(linux_os->thread_list,
+ &temp, prev);
linux_os->thread_count--;
gdb_put_packet(connection, "E01", 3);
return ERROR_OK;
@@ -1321,9 +1320,7 @@ static int linux_thread_packet(struct connection *connection, char const *packet
if (strncmp(packet, "qSymbol", 7) == 0) {
if (rtos_qsymbol(connection, packet, packet_size) == 1) {
linux_compute_virt2phys(target,
- target->rtos->
- symbols[INIT_TASK].
- address);
+ target->rtos->symbols[INIT_TASK].address);
}
break;
@@ -1374,11 +1371,10 @@ static int linux_thread_packet(struct connection *connection, char const *packet
}
if ((ct != NULL) && (ct->threadid !=
- target->rtos->
- current_threadid)
+ target->rtos->current_threadid)
&& (target->rtos->current_threadid != -1))
- LOG_WARNING("WARNING! current GDB thread do not match" \
- "current thread running." \
+ LOG_WARNING("WARNING! current GDB thread do not match "
+ "current thread running. "
"Switch thread in GDB to threadid %d",
(int)ct->threadid);
@@ -1408,8 +1404,7 @@ static int linux_os_smp_init(struct target *target)
while (head != (struct target_list *)NULL) {
if (head->target->rtos != rtos) {
struct linux_os *smp_os_linux =
- (struct linux_os *)head->target->rtos->
- rtos_specific_params;
+ (struct linux_os *)head->target->rtos->rtos_specific_params;
/* remap smp target on rtos */
free(head->target->rtos);
head->target->rtos = rtos;
diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c
index 6646ad4de..f45c15d23 100644
--- a/src/rtos/mqx.c
+++ b/src/rtos/mqx.c
@@ -106,7 +106,7 @@ static int mqx_valid_address_check(
)
{
enum mqx_arch arch_type = ((struct mqx_params *)rtos->rtos_specific_params)->target_arch;
- const char * targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name;
+ const char *targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name;
/* Cortex-M address range */
if (arch_type == mqx_arch_cortexm) {
diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c
index 8c3076e16..322c7d19b 100644
--- a/src/rtos/nuttx.c
+++ b/src/rtos/nuttx.c
@@ -401,4 +401,3 @@ struct rtos_type nuttx_rtos = {
.get_thread_reg_list = nuttx_get_thread_reg_list,
.get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
};
-
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 6b7c9e2ce..8c849148a 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -31,7 +31,7 @@ extern struct rtos_type FreeRTOS_rtos;
extern struct rtos_type ThreadX_rtos;
extern struct rtos_type eCos_rtos;
extern struct rtos_type Linux_os;
-extern struct rtos_type ChibiOS_rtos;
+extern struct rtos_type chibios_rtos;
extern struct rtos_type chromium_ec_rtos;
extern struct rtos_type embKernel_rtos;
extern struct rtos_type mqx_rtos;
@@ -45,7 +45,7 @@ static struct rtos_type *rtos_types[] = {
&FreeRTOS_rtos,
&eCos_rtos,
&Linux_os,
- &ChibiOS_rtos,
+ &chibios_rtos,
&chromium_ec_rtos,
&embKernel_rtos,
&mqx_rtos,
@@ -124,7 +124,7 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target)
{
int x;
const char *cp;
- struct Jim_Obj *res;
+ Jim_Obj *res;
int e;
if (!goi->isconfigure && goi->argc != 0) {
@@ -162,6 +162,11 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target)
return JIM_ERR;
}
+void rtos_destroy(struct target *target)
+{
+ os_free(target);
+}
+
int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size)
{
struct target *target = get_target_from_connection(connection);
diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h
index ee9d4d4a5..9b43afb14 100644
--- a/src/rtos/rtos.h
+++ b/src/rtos/rtos.h
@@ -126,6 +126,7 @@ struct rtos_register_stacking {
#define GDB_THREAD_PACKET_NOT_CONSUMED (-40)
int rtos_create(Jim_GetOptInfo *goi, struct target *target);
+void rtos_destroy(struct target *target);
int rtos_set_reg(struct connection *connection, int reg_num,
uint8_t *reg_value);
int rtos_generic_stack_read(struct target *target,
diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c
index 4ee79af93..543a8cd2a 100644
--- a/src/rtos/rtos_embkernel_stackings.c
+++ b/src/rtos/rtos_embkernel_stackings.c
@@ -51,5 +51,3 @@ const struct rtos_register_stacking rtos_embkernel_Cortex_M_stacking = {
rtos_generic_stack_align8, /* stack_alignment */
rtos_embkernel_Cortex_M_stack_offsets /* register_offsets */
};
-
-
diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c
index 1a8bdfcc7..d18e59155 100644
--- a/src/rtos/rtos_mqx_stackings.c
+++ b/src/rtos/rtos_mqx_stackings.c
@@ -77,4 +77,3 @@ const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking = {
NULL, /* stack_alignment */
rtos_mqx_arm_v7m_stack_offsets /* register_offsets */
};
-
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 755463c42..4c5f32a31 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include "server.h"
#include
#include "gdb_server.h"
@@ -70,7 +71,7 @@ struct gdb_connection {
char buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for nul-termination */
char *buf_p;
int buf_cnt;
- int ctrl_c;
+ bool ctrl_c;
enum target_state frontend_state;
struct image *vflash_image;
bool closed;
@@ -90,6 +91,8 @@ struct gdb_connection {
* normally we reply with a S reply via gdb_last_signal_packet.
* as a side note this behaviour only effects gdb > 6.8 */
bool attached;
+ /* set when extended protocol is used */
+ bool extended_protocol;
/* temporarily used for target description support */
struct target_desc_format target_desc;
/* temporarily used for thread list support */
@@ -274,9 +277,9 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
gdb_con->buf_cnt--;
*next_char = *(gdb_con->buf_p++);
if (gdb_con->buf_cnt > 0)
- connection->input_pending = 1;
+ connection->input_pending = true;
else
- connection->input_pending = 0;
+ connection->input_pending = false;
#ifdef _DEBUG_GDB_IO_
LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
#endif
@@ -299,9 +302,9 @@ static inline int gdb_get_char_fast(struct connection *connection,
*next_char = **buf_p;
(*buf_p)++;
if (*buf_cnt > 0)
- connection->input_pending = 1;
+ connection->input_pending = true;
else
- connection->input_pending = 0;
+ connection->input_pending = false;
#ifdef _DEBUG_GDB_IO_
LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
@@ -439,7 +442,7 @@ static int gdb_put_packet_inner(struct connection *connection,
log_remove_callback(gdb_log_callback, connection);
LOG_WARNING("negative reply, retrying");
} else if (reply == 0x3) {
- gdb_con->ctrl_c = 1;
+ gdb_con->ctrl_c = true;
retval = gdb_get_char(connection, &reply);
if (retval != ERROR_OK)
return retval;
@@ -644,7 +647,7 @@ static int gdb_get_packet_inner(struct connection *connection,
LOG_WARNING("negative acknowledgment, but no packet pending");
break;
case 0x3:
- gdb_con->ctrl_c = 1;
+ gdb_con->ctrl_c = true;
*len = 0;
return ERROR_OK;
default:
@@ -780,7 +783,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
signal_var, stop_reason, current_thread);
- gdb_connection->ctrl_c = 0;
+ gdb_connection->ctrl_c = false;
}
gdb_put_packet(connection, sig_reply, sig_reply_len);
@@ -797,7 +800,7 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
if (strcmp(target->fileio_info->identifier, "open") == 0)
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
- target->fileio_info->param_2,
+ target->fileio_info->param_2 + 1, /* len + trailing zero */
target->fileio_info->param_3,
target->fileio_info->param_4);
else if (strcmp(target->fileio_info->identifier, "close") == 0)
@@ -821,13 +824,13 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
else if (strcmp(target->fileio_info->identifier, "rename") == 0)
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
- target->fileio_info->param_2,
+ target->fileio_info->param_2 + 1, /* len + trailing zero */
target->fileio_info->param_3,
- target->fileio_info->param_4);
+ target->fileio_info->param_4 + 1); /* len + trailing zero */
else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
- target->fileio_info->param_2);
+ target->fileio_info->param_2 + 1); /* len + trailing zero */
else if (strcmp(target->fileio_info->identifier, "stat") == 0)
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
@@ -847,7 +850,7 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
else if (strcmp(target->fileio_info->identifier, "system") == 0)
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
- target->fileio_info->param_2);
+ target->fileio_info->param_2 + 1); /* len + trailing zero */
else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
/* If target hits exit syscall, report to GDB the program is terminated.
* In addition, let target run its own exit syscall handler. */
@@ -937,7 +940,7 @@ static int gdb_new_connection(struct connection *connection)
/* initialize gdb connection information */
gdb_connection->buf_p = gdb_connection->buffer;
gdb_connection->buf_cnt = 0;
- gdb_connection->ctrl_c = 0;
+ gdb_connection->ctrl_c = false;
gdb_connection->frontend_state = TARGET_HALTED;
gdb_connection->vflash_image = NULL;
gdb_connection->closed = false;
@@ -946,6 +949,7 @@ static int gdb_new_connection(struct connection *connection)
gdb_connection->sync = false;
gdb_connection->mem_write_error = false;
gdb_connection->attached = true;
+ gdb_connection->extended_protocol = false;
gdb_connection->target_desc.tdesc = NULL;
gdb_connection->target_desc.tdesc_length = 0;
gdb_connection->thread_list = NULL;
@@ -998,7 +1002,7 @@ static int gdb_new_connection(struct connection *connection)
continue;
retval = get_flash_bank_by_num(i, &p);
if (retval != ERROR_OK) {
- LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " \
+ LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target "
"to prepare target for GDB connect, or use 'gdb_memory_map disable'.");
return retval;
}
@@ -1739,8 +1743,8 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
/* print out a string and allocate more space as needed,
* mainly used for XML at this point
*/
-static void xml_printf(int *retval, char **xml, int *pos, int *size,
- const char *fmt, ...)
+static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))) void xml_printf(int *retval,
+ char **xml, int *pos, int *size, const char *fmt, ...)
{
if (*retval != ERROR_OK)
return;
@@ -1881,7 +1885,7 @@ static int gdb_memory_map(struct connection *connection,
if (ram_start < p->base)
xml_printf(&retval, &xml, &pos, &size,
"\n",
+ "length=\"" TARGET_ADDR_FMT "\"/>\n",
ram_start, p->base - ram_start);
/* Report adjacent groups of same-size sectors. So for
@@ -2038,7 +2042,7 @@ static int lookup_add_arch_defined_types(char const **arch_defined_types_list[],
static int gdb_generate_reg_type_description(struct target *target,
char **tdesc, int *pos, int *size, struct reg_data_type *type,
- char const **arch_defined_types_list[], int * num_arch_defined_types)
+ char const **arch_defined_types_list[], int *num_arch_defined_types)
{
int retval = ERROR_OK;
@@ -2288,14 +2292,11 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
int reg_list_size;
char const *architecture;
char const **features = NULL;
- char const **arch_defined_types = NULL;
int feature_list_size = 0;
- int num_arch_defined_types = 0;
char *tdesc = NULL;
int pos = 0;
int size = 0;
- arch_defined_types = calloc(1, sizeof(char *));
retval = smp_reg_list_noread(target, ®_list, ®_list_size,
REG_CLASS_ALL);
@@ -2337,7 +2338,10 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
/* generate target description according to register list */
if (features != NULL) {
while (features[current_feature]) {
+ char const **arch_defined_types = NULL;
+ int num_arch_defined_types = 0;
+ arch_defined_types = calloc(1, sizeof(char *));
xml_printf(&retval, &tdesc, &pos, &size,
"\n",
features[current_feature]);
@@ -2402,6 +2406,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
"\n");
current_feature++;
+ free(arch_defined_types);
}
}
@@ -2411,7 +2416,6 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
error:
free(features);
free(reg_list);
- free(arch_defined_types);
if (retval == ERROR_OK)
*tdesc_out = tdesc;
@@ -2552,7 +2556,7 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou
xml_printf(&retval, &thread_list, &pos, &size,
", ");
xml_printf(&retval, &thread_list, &pos, &size,
- thread_detail->extra_info_str);
+ "%s", thread_detail->extra_info_str);
}
xml_printf(&retval, &thread_list, &pos, &size,
@@ -2947,7 +2951,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
if (gdb_connection->sync) {
gdb_connection->sync = false;
if (ct->state == TARGET_HALTED) {
- LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \
+ LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
"from the target.");
gdb_sig_halted(connection);
log_remove_callback(gdb_log_callback, connection);
@@ -2981,6 +2985,96 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
return false;
}
+static char *next_hex_encoded_field(const char **str, char sep)
+{
+ size_t hexlen;
+ const char *hex = *str;
+ if (hex[0] == '\0')
+ return NULL;
+
+ const char *end = strchr(hex, sep);
+ if (end == NULL)
+ hexlen = strlen(hex);
+ else
+ hexlen = end - hex;
+ *str = hex + hexlen + 1;
+
+ if (hexlen % 2 != 0) {
+ /* Malformed hex data */
+ return NULL;
+ }
+
+ size_t count = hexlen / 2;
+ char *decoded = malloc(count + 1);
+ if (decoded == NULL)
+ return NULL;
+
+ size_t converted = unhexify((void *)decoded, hex, count);
+ if (converted != count) {
+ free(decoded);
+ return NULL;
+ }
+
+ decoded[count] = '\0';
+ return decoded;
+}
+
+/* handle extended restart packet */
+static void gdb_restart_inferior(struct connection *connection, const char *packet, int packet_size)
+{
+ struct gdb_connection *gdb_con = connection->priv;
+ struct target *target = get_target_from_connection(connection);
+
+ breakpoint_clear_target(target);
+ watchpoint_clear_target(target);
+ command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s",
+ target_name(target));
+ /* set connection as attached after reset */
+ gdb_con->attached = true;
+ /* info rtos parts */
+ gdb_thread_packet(connection, packet, packet_size);
+}
+
+static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size)
+{
+ struct target *target = get_target_from_connection(connection);
+ const char *parse = packet;
+
+ /* Skip "vRun" */
+ parse += 4;
+
+ if (parse[0] != ';')
+ return false;
+ parse++;
+
+ /* Skip first field "filename"; don't know what to do with it. */
+ free(next_hex_encoded_field(&parse, ';'));
+
+ char *cmdline = next_hex_encoded_field(&parse, ';');
+ char *arg;
+ while (cmdline != NULL && (arg = next_hex_encoded_field(&parse, ';')) != NULL) {
+ char *new_cmdline = alloc_printf("%s %s", cmdline, arg);
+ free(cmdline);
+ free(arg);
+ cmdline = new_cmdline;
+ }
+
+ if (cmdline != NULL) {
+ if (target->semihosting != NULL) {
+ LOG_INFO("GDB set inferior command line to '%s'", cmdline);
+ free(target->semihosting->cmdline);
+ target->semihosting->cmdline = cmdline;
+ } else {
+ LOG_INFO("GDB set inferior command line to '%s' but semihosting is unavailable", cmdline);
+ free(cmdline);
+ }
+ }
+
+ gdb_restart_inferior(connection, packet, packet_size);
+ gdb_put_packet(connection, "S00", 3);
+ return true;
+}
+
static int gdb_v_packet(struct connection *connection,
char const *packet, int packet_size)
{
@@ -3007,6 +3101,16 @@ static int gdb_v_packet(struct connection *connection,
return ERROR_OK;
}
+ if (strncmp(packet, "vRun", 4) == 0) {
+ bool handled;
+
+ handled = gdb_handle_vrun_packet(connection, packet, packet_size);
+ if (!handled)
+ gdb_put_packet(connection, "", 0);
+
+ return ERROR_OK;
+ }
+
/* if flash programming disabled - send a empty reply */
if (gdb_flash_program == 0) {
@@ -3226,7 +3330,6 @@ static int gdb_input_inner(struct connection *connection)
int packet_size;
int retval;
struct gdb_connection *gdb_con = connection->priv;
- static int extended_protocol;
target = get_target_from_connection(connection);
@@ -3333,7 +3436,7 @@ static int gdb_input_inner(struct connection *connection)
"Waiting for target to halt.");
already_running = true;
} else if (target->state != TARGET_HALTED) {
- LOG_WARNING("The target is not in the halted nor running stated, " \
+ LOG_WARNING("The target is not in the halted nor running stated, "
"stepi/continue ignored.");
nostep = true;
} else if ((packet[0] == 's') && gdb_con->sync) {
@@ -3342,7 +3445,7 @@ static int gdb_input_inner(struct connection *connection)
* make only the single stepping have the sync feature...
*/
nostep = true;
- LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \
+ LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
"from the target.");
}
gdb_con->sync = false;
@@ -3385,7 +3488,6 @@ static int gdb_input_inner(struct connection *connection)
break;
case 'D':
retval = gdb_detach(connection);
- extended_protocol = 0;
break;
case 'X':
retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
@@ -3393,7 +3495,7 @@ static int gdb_input_inner(struct connection *connection)
return retval;
break;
case 'k':
- if (extended_protocol != 0) {
+ if (gdb_con->extended_protocol) {
gdb_con->attached = false;
break;
}
@@ -3401,19 +3503,12 @@ static int gdb_input_inner(struct connection *connection)
return ERROR_SERVER_REMOTE_CLOSED;
case '!':
/* handle extended remote protocol */
- extended_protocol = 1;
+ gdb_con->extended_protocol = true;
gdb_put_packet(connection, "OK", 2);
break;
case 'R':
/* handle extended restart packet */
- breakpoint_clear_target(target);
- watchpoint_clear_target(target);
- command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s",
- target_name(target));
- /* set connection as attached after reset */
- gdb_con->attached = true;
- /* info rtos parts */
- gdb_thread_packet(connection, packet, packet_size);
+ gdb_restart_inferior(connection, packet, packet_size);
break;
case 'j':
@@ -3464,7 +3559,7 @@ static int gdb_input_inner(struct connection *connection)
retval = target_poll(t);
if (retval != ERROR_OK)
target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
- gdb_con->ctrl_c = 0;
+ gdb_con->ctrl_c = false;
} else {
LOG_INFO("The target is not running when halt was requested, stopping GDB.");
target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
@@ -3500,7 +3595,7 @@ static int gdb_target_start(struct target *target, const char *port)
if (NULL == gdb_service)
return -ENOMEM;
- LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port);
+ LOG_INFO("starting gdb server for %s on %s", target_name(target), port);
gdb_service->target = target;
gdb_service->core[0] = -1;
@@ -3567,7 +3662,7 @@ static int gdb_target_add_one(struct target *target)
if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) {
free(gdb_port_next);
if (portnumber) {
- gdb_port_next = alloc_printf("%d", portnumber+1);
+ gdb_port_next = alloc_printf("%ld", portnumber+1);
} else {
/* Don't increment if gdb_port is 0, since we're just
* trying to allocate an unused port. */
@@ -3750,7 +3845,7 @@ static const struct command_registration gdb_command_handlers[] = {
{
.name = "gdb_port",
.handler = handle_gdb_port_command,
- .mode = COMMAND_ANY,
+ .mode = COMMAND_CONFIG,
.help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB "
"server listens for the next port number after the "
"base port number specified. "
diff --git a/src/server/server.c b/src/server/server.c
index 9e63f74f4..23a15ef9a 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -76,7 +76,7 @@ static int add_connection(struct service *service, struct command_context *cmd_c
memset(&c->sin, 0, sizeof(c->sin));
c->cmd_ctx = copy_command_context(cmd_ctx);
c->service = service;
- c->input_pending = 0;
+ c->input_pending = false;
c->priv = NULL;
c->next = NULL;
@@ -562,7 +562,7 @@ int server_loop(struct command_context *command_context)
struct connection *c;
for (c = service->connections; c; ) {
- if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
+ if ((c->fd >= 0 && FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
retval = service->input(c);
if (retval != ERROR_OK) {
struct connection *next = c->next;
@@ -631,7 +631,7 @@ static void sigkey_handler(int sig)
#endif
-int server_preinit(void)
+int server_host_os_entry(void)
{
/* this currently only calls WSAStartup on native win32 systems
* before any socket operations are performed.
@@ -647,7 +647,21 @@ int server_preinit(void)
LOG_ERROR("Failed to Open Winsock");
return ERROR_FAIL;
}
+#endif
+ return ERROR_OK;
+}
+int server_host_os_close(void)
+{
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ return ERROR_OK;
+}
+
+int server_preinit(void)
+{
+#ifdef _WIN32
/* register ctrl-c handler */
SetConsoleCtrlHandler(ControlHandler, TRUE);
@@ -688,7 +702,6 @@ int server_quit(void)
target_quit();
#ifdef _WIN32
- WSACleanup();
SetConsoleCtrlHandler(ControlHandler, FALSE);
return ERROR_OK;
@@ -799,7 +812,7 @@ static const struct command_registration server_command_handlers[] = {
{
.name = "bindto",
.handler = &handle_bindto_command,
- .mode = COMMAND_ANY,
+ .mode = COMMAND_CONFIG,
.usage = "[name]",
.help = "Specify address by name on which to listen for "
"incoming TCP/IP connections",
diff --git a/src/server/server.h b/src/server/server.h
index 96e0b48ef..f4cc39d3a 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -49,7 +49,7 @@ struct connection {
struct sockaddr_in sin;
struct command_context *cmd_ctx;
struct service *service;
- int input_pending;
+ bool input_pending;
void *priv;
struct connection *next;
};
@@ -80,6 +80,9 @@ int add_service(char *name, const char *port,
void *priv);
int remove_service(const char *name, const char *port);
+int server_host_os_entry(void);
+int server_host_os_close(void);
+
int server_preinit(void);
int server_init(struct command_context *cmd_ctx);
int server_quit(void);
diff --git a/src/server/startup.tcl b/src/server/startup.tcl
index 64ace4079..dd1b31e41 100644
--- a/src/server/startup.tcl
+++ b/src/server/startup.tcl
@@ -8,3 +8,14 @@ proc ocd_gdb_restart {target_id} {
# one target
reset halt
}
+
+proc prevent_cps {} {
+ echo "Possible SECURITY ATTACK detected."
+ echo "It looks like somebody is sending POST or Host: commands to OpenOCD."
+ echo "This is likely due to an attacker attempting to use Cross Protocol Scripting"
+ echo "to compromise your OpenOCD instance. Connection aborted."
+ exit
+}
+
+proc POST {args} { prevent_cps }
+proc Host: {args} { prevent_cps }
diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c
index 1ec45ffbb..1ecb827a1 100644
--- a/src/server/tcl_server.c
+++ b/src/server/tcl_server.c
@@ -199,7 +199,7 @@ static int tcl_input(struct connection *connection)
for (i = 0; i < rlen; i++) {
/* buffer the data */
tclc->tc_line[tclc->tc_lineoffset] = in[i];
- if (tclc->tc_lineoffset < tclc->tc_line_size) {
+ if (tclc->tc_lineoffset + 1 < tclc->tc_line_size) {
tclc->tc_lineoffset++;
} else if (tclc->tc_line_size >= TCL_LINE_MAX) {
/* maximum line size reached, drop line */
@@ -331,7 +331,7 @@ static const struct command_registration tcl_command_handlers[] = {
{
.name = "tcl_port",
.handler = handle_tcl_port_command,
- .mode = COMMAND_ANY,
+ .mode = COMMAND_CONFIG,
.help = "Specify port on which to listen "
"for incoming Tcl syntax. "
"Read help on 'gdb_port'.",
diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c
index a864f5fd2..d0583a9b3 100644
--- a/src/server/telnet_server.c
+++ b/src/server/telnet_server.c
@@ -312,6 +312,36 @@ static void telnet_history_down(struct connection *connection)
telnet_history_go(connection, next_history);
}
+static int telnet_history_print(struct connection *connection)
+{
+ struct telnet_connection *tc;
+
+ tc = connection->priv;
+
+ for (size_t i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) {
+ char *line;
+
+ /*
+ * The tc->next_history line contains empty string (unless NULL), thus
+ * it is not printed.
+ */
+ line = tc->history[(tc->next_history + i) % TELNET_LINE_HISTORY_SIZE];
+
+ if (line) {
+ telnet_write(connection, line, strlen(line));
+ telnet_write(connection, "\r\n\x00", 3);
+ }
+ }
+
+ tc->line_size = 0;
+ tc->line_cursor = 0;
+
+ /* The prompt is always placed at the line beginning. */
+ telnet_write(connection, "\r", 1);
+
+ return telnet_prompt(connection);
+}
+
static void telnet_move_cursor(struct connection *connection, size_t pos)
{
struct telnet_connection *tc;
@@ -407,21 +437,11 @@ static int telnet_input(struct connection *connection)
telnet_write(connection, "\r\n\x00", 3);
if (strcmp(t_con->line, "history") == 0) {
- size_t i;
- for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) {
- /* the t_con->next_history line contains empty string
- * (unless NULL), thus it is not printed */
- char *history_line = t_con->history[(t_con->
- next_history + i) %
- TELNET_LINE_HISTORY_SIZE];
- if (history_line) {
- telnet_write(connection, history_line,
- strlen(history_line));
- telnet_write(connection, "\r\n\x00", 3);
- }
- }
- t_con->line_size = 0;
- t_con->line_cursor = 0;
+ retval = telnet_history_print(connection);
+
+ if (retval != ERROR_OK)
+ return retval;
+
continue;
}
@@ -705,7 +725,7 @@ static const struct command_registration telnet_command_handlers[] = {
{
.name = "telnet_port",
.handler = handle_telnet_port_command,
- .mode = COMMAND_ANY,
+ .mode = COMMAND_CONFIG,
.help = "Specify port on which to listen "
"for incoming telnet connections. "
"Read help on 'gdb_port'.",
diff --git a/src/svf/svf.c b/src/svf/svf.c
index 759ba5263..fd27417e0 100644
--- a/src/svf/svf.c
+++ b/src/svf/svf.c
@@ -990,7 +990,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str)
/* TODO: set jtag speed to */
if (svf_para.frequency > 0) {
command_run_linef(cmd_ctx,
- "adapter_khz %d",
+ "adapter speed %d",
(int)svf_para.frequency / 1000);
LOG_DEBUG("\tfrequency = %f", svf_para.frequency);
}
@@ -1310,7 +1310,6 @@ XXR_common:
case PIOMAP:
LOG_ERROR("PIO and PIOMAP are not supported");
return ERROR_FAIL;
- break;
case RUNTEST:
/* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time
* SEC]] [ENDSTATE end_state] */
@@ -1532,7 +1531,6 @@ XXR_common:
default:
LOG_ERROR("invalid svf command: %s", argus[0]);
return ERROR_FAIL;
- break;
}
if (!svf_quiet) {
@@ -1542,8 +1540,8 @@ XXR_common:
if (debug_level >= LOG_LVL_DEBUG) {
/* for convenient debugging, execute tap if possible */
- if ((svf_buffer_index > 0) && \
- (((command != STATE) && (command != RUNTEST)) || \
+ if ((svf_buffer_index > 0) &&
+ (((command != STATE) && (command != RUNTEST)) ||
((command == STATE) && (num_of_argu == 2)))) {
if (ERROR_OK != svf_execute_tap())
return ERROR_FAIL;
@@ -1557,8 +1555,8 @@ XXR_common:
/* for fast executing, execute tap if necessary */
/* half of the buffer is for the next command */
if (((svf_buffer_index >= SVF_MAX_BUFFER_SIZE_TO_COMMIT) ||
- (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE / 2)) && \
- (((command != STATE) && (command != RUNTEST)) || \
+ (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE / 2)) &&
+ (((command != STATE) && (command != RUNTEST)) ||
((command == STATE) && (num_of_argu == 2))))
return svf_execute_tap();
}
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index afa5f49b6..42d809d01 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -24,15 +24,14 @@ noinst_LTLIBRARIES += %D%/libtarget.la
$(STM8_SRC) \
$(INTEL_IA32_SRC) \
$(ESIRISC_SRC) \
+ $(ARC_SRC) \
%D%/avrt.c \
%D%/dsp563xx.c \
%D%/dsp563xx_once.c \
%D%/dsp5680xx.c \
- %D%/hla_target.c
-
-if TARGET64
-%C%_libtarget_la_SOURCES +=$(ARMV8_SRC)
-endif
+ %D%/hla_target.c \
+ $(ARMV8_SRC) \
+ $(MIPS64_SRC)
TARGET_CORE_SRC = \
%D%/algorithm.c \
@@ -97,6 +96,7 @@ ARM_DEBUG_SRC = \
%D%/arm_dap.c \
%D%/armv7a_cache.c \
%D%/armv7a_cache_l2x.c \
+ %D%/adi_v5_dapdirect.c \
%D%/adi_v5_jtag.c \
%D%/adi_v5_swd.c \
%D%/embeddedice.c \
@@ -120,6 +120,14 @@ MIPS32_SRC = \
%D%/mips32_dmaacc.c \
%D%/mips_ejtag.c
+MIPS64_SRC = \
+ %D%/mips64.c \
+ %D%/mips32_pracc.c \
+ %D%/mips64_pracc.c \
+ %D%/mips_mips64.c \
+ %D%/trace.c \
+ %D%/mips_ejtag.c
+
NDS32_SRC = \
%D%/nds32.c \
%D%/nds32_reg.c \
@@ -146,6 +154,12 @@ ESIRISC_SRC = \
%D%/esirisc_jtag.c \
%D%/esirisc_trace.c
+ARC_SRC = \
+ %D%/arc.c \
+ %D%/arc_cmd.c \
+ %D%/arc_jtag.c \
+ %D%/arc_mem.c
+
%C%_libtarget_la_SOURCES += \
%D%/algorithm.h \
%D%/arm.h \
@@ -193,10 +207,13 @@ ESIRISC_SRC = \
%D%/etm_dummy.h \
%D%/image.h \
%D%/mips32.h \
+ %D%/mips64.h \
%D%/mips_m4k.h \
+ %D%/mips_mips64.h \
%D%/mips_ejtag.h \
%D%/mips32_pracc.h \
%D%/mips32_dmaacc.h \
+ %D%/mips64_pracc.h \
%D%/oocd_trace.h \
%D%/register.h \
%D%/target.h \
@@ -230,7 +247,11 @@ ESIRISC_SRC = \
%D%/esirisc.h \
%D%/esirisc_jtag.h \
%D%/esirisc_regs.h \
- %D%/esirisc_trace.h
+ %D%/esirisc_trace.h \
+ %D%/arc.h \
+ %D%/arc_cmd.h \
+ %D%/arc_jtag.h \
+ %D%/arc_mem.h
include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index 7acb4726a..87176f638 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -1176,7 +1176,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
if (saved_retval != ERROR_OK)
return saved_retval;
- return aarch64_poll(target);
+ return ERROR_OK;
}
static int aarch64_restore_context(struct target *target, bool bpwp)
@@ -1263,9 +1263,32 @@ static int aarch64_set_breakpoint(struct target *target,
brp_list[brp_i].value);
} else if (breakpoint->type == BKPT_SOFT) {
+ uint32_t opcode;
uint8_t code[4];
- buf_set_u32(code, 0, 32, armv8_opcode(armv8, ARMV8_OPC_HLT));
+ if (armv8_dpm_get_core_state(&armv8->dpm) == ARM_STATE_AARCH64) {
+ opcode = ARMV8_HLT(11);
+
+ if (breakpoint->length != 4)
+ LOG_ERROR("bug: breakpoint length should be 4 in AArch64 mode");
+ } else {
+ /**
+ * core_state is ARM_STATE_ARM
+ * in that case the opcode depends on breakpoint length:
+ * - if length == 4 => A32 opcode
+ * - if length == 2 => T32 opcode
+ * - if length == 3 => T32 opcode (refer to gdb doc : ARM-Breakpoint-Kinds)
+ * in that case the length should be changed from 3 to 4 bytes
+ **/
+ opcode = (breakpoint->length == 4) ? ARMV8_HLT_A1(11) :
+ (uint32_t) (ARMV8_HLT_T1(11) | ARMV8_HLT_T1(11) << 16);
+
+ if (breakpoint->length == 3)
+ breakpoint->length = 4;
+ }
+
+ buf_set_u32(code, 0, 32, opcode);
+
retval = target_read_memory(target,
breakpoint->address & 0xFFFFFFFFFFFFFFFE,
breakpoint->length, 1,
@@ -2759,7 +2782,16 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
+extern const struct command_registration semihosting_common_handlers[];
+
static const struct command_registration aarch64_command_handlers[] = {
+ {
+ .name = "arm",
+ .mode = COMMAND_ANY,
+ .help = "ARM Command Group",
+ .usage = "",
+ .chain = semihosting_common_handlers
+ },
{
.chain = armv8_command_handlers,
},
diff --git a/src/target/adi_v5_dapdirect.c b/src/target/adi_v5_dapdirect.c
new file mode 100644
index 000000000..c0deee165
--- /dev/null
+++ b/src/target/adi_v5_dapdirect.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ * Author(s): Antonio Borneo for STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Utilities to support in-circuit debuggers that provide APIs to access
+ * directly ARM DAP, hiding the access to the underlining transport used
+ * for the physical connection (either JTAG or SWD).
+ * E.g. STMicroelectronics ST-Link/V2 (from version V2J24) and STLINK-V3.
+ *
+ * Single-DAP support only.
+ *
+ * For details, see "ARM IHI 0031A"
+ * ARM Debug Interface v5 Architecture Specification
+ *
+ * FIXME: in JTAG mode, trst is not managed
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+
+COMMAND_HANDLER(dapdirect_jtag_empty_command)
+{
+ LOG_DEBUG("dapdirect_jtag_empty_command(\"%s\")", CMD_NAME);
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(dapdirect_jtag_reset_command)
+{
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+ /*
+ * in case the adapter has not already handled asserting srst
+ * we will attempt it again
+ */
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING) {
+ adapter_assert_reset();
+ return ERROR_OK;
+ }
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ }
+ adapter_deassert_reset();
+ return ERROR_OK;
+}
+
+static const struct command_registration dapdirect_jtag_subcommand_handlers[] = {
+ {
+ .name = "newtap",
+ .mode = COMMAND_CONFIG,
+ .jim_handler = jim_jtag_newtap,
+ .help = "declare a new TAP"
+ },
+ {
+ .name = "init",
+ .mode = COMMAND_ANY,
+ .handler = dapdirect_jtag_empty_command,
+ .usage = ""
+ },
+ {
+ .name = "arp_init",
+ .mode = COMMAND_ANY,
+ .handler = dapdirect_jtag_empty_command,
+ .usage = ""
+ },
+ {
+ .name = "arp_init-reset",
+ .mode = COMMAND_ANY,
+ .handler = dapdirect_jtag_reset_command,
+ .usage = ""
+ },
+ {
+ .name = "tapisenabled",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_jtag_tap_enabler,
+ },
+ {
+ .name = "tapenable",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_jtag_tap_enabler,
+ },
+ {
+ .name = "tapdisable",
+ .mode = COMMAND_EXEC,
+ .handler = dapdirect_jtag_empty_command,
+ .usage = "",
+ },
+ {
+ .name = "configure",
+ .mode = COMMAND_ANY,
+ .handler = dapdirect_jtag_empty_command,
+ .usage = "",
+ },
+ {
+ .name = "cget",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_jtag_configure,
+ },
+ {
+ .name = "names",
+ .mode = COMMAND_ANY,
+ .handler = dapdirect_jtag_empty_command,
+ .usage = "",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration dapdirect_jtag_handlers[] = {
+ {
+ .name = "jtag",
+ .mode = COMMAND_ANY,
+ .chain = dapdirect_jtag_subcommand_handlers,
+ .usage = "",
+ },
+ {
+ .name = "jtag_ntrst_delay",
+ .mode = COMMAND_ANY,
+ .handler = dapdirect_jtag_empty_command,
+ .usage = "",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration dapdirect_swd_subcommand_handlers[] = {
+ {
+ .name = "newdap",
+ .mode = COMMAND_CONFIG,
+ .jim_handler = jim_jtag_newtap,
+ .help = "declare a new SWD DAP",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration dapdirect_swd_handlers[] = {
+ {
+ .name = "swd",
+ .mode = COMMAND_ANY,
+ .help = "SWD command group",
+ .usage = "",
+ .chain = dapdirect_swd_subcommand_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static int dapdirect_jtag_select(struct command_context *ctx)
+{
+ LOG_DEBUG("dapdirect_jtag_select()");
+
+ return register_commands(ctx, NULL, dapdirect_jtag_handlers);
+}
+
+static int dapdirect_swd_select(struct command_context *ctx)
+{
+ LOG_DEBUG("dapdirect_swd_select()");
+
+ return register_commands(ctx, NULL, dapdirect_swd_handlers);
+}
+
+static int dapdirect_init(struct command_context *ctx)
+{
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+ LOG_DEBUG("dapdirect_init()");
+
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING)
+ adapter_assert_reset();
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ } else
+ adapter_deassert_reset();
+
+ return ERROR_OK;
+}
+
+static struct transport dapdirect_jtag_transport = {
+ .name = "dapdirect_jtag",
+ .select = dapdirect_jtag_select,
+ .init = dapdirect_init,
+};
+
+static struct transport dapdirect_swd_transport = {
+ .name = "dapdirect_swd",
+ .select = dapdirect_swd_select,
+ .init = dapdirect_init,
+};
+
+static void dapdirect_constructor(void) __attribute__((constructor));
+static void dapdirect_constructor(void)
+{
+ transport_register(&dapdirect_jtag_transport);
+ transport_register(&dapdirect_swd_transport);
+}
+
+/**
+ * Returns true if the current debug session
+ * is using JTAG as its transport.
+ */
+bool transport_is_dapdirect_jtag(void)
+{
+ return get_current_transport() == &dapdirect_jtag_transport;
+}
+
+/**
+ * Returns true if the current debug session
+ * is using SWD as its transport.
+ */
+bool transport_is_dapdirect_swd(void)
+{
+ return get_current_transport() == &dapdirect_swd_transport;
+}
diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c
index a3867e191..c2100eb47 100644
--- a/src/target/adi_v5_jtag.c
+++ b/src/target/adi_v5_jtag.c
@@ -38,6 +38,7 @@
#include "arm_adi_v5.h"
#include
#include
+#include
/*#define DEBUG_WAIT*/
@@ -139,6 +140,13 @@ struct dap_cmd {
uint8_t outvalue_buf[4];
};
+#define MAX_DAP_COMMAND_NUM 65536
+
+struct dap_cmd_pool {
+ struct list_head lh;
+ struct dap_cmd cmd;
+} dap_cmd_pool;
+
static void log_dap_cmd(const char *header, struct dap_cmd *el)
{
#ifdef DEBUG_WAIT
@@ -153,32 +161,73 @@ static void log_dap_cmd(const char *header, struct dap_cmd *el)
#endif
}
-static struct dap_cmd *dap_cmd_new(uint8_t instr,
+static int jtag_limit_queue_size(struct adiv5_dap *dap)
+{
+ if (dap->cmd_pool_size < MAX_DAP_COMMAND_NUM)
+ return ERROR_OK;
+
+ return dap_run(dap);
+}
+
+static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr,
uint8_t reg_addr, uint8_t RnW,
uint8_t *outvalue, uint8_t *invalue,
uint32_t memaccess_tck)
{
- struct dap_cmd *cmd;
- cmd = (struct dap_cmd *)calloc(1, sizeof(struct dap_cmd));
- if (cmd != NULL) {
- INIT_LIST_HEAD(&cmd->lh);
- cmd->instr = instr;
- cmd->reg_addr = reg_addr;
- cmd->RnW = RnW;
- if (outvalue != NULL)
- memcpy(cmd->outvalue_buf, outvalue, 4);
- cmd->invalue = (invalue != NULL) ? invalue : cmd->invalue_buf;
- cmd->memaccess_tck = memaccess_tck;
+ struct dap_cmd_pool *pool = NULL;
+
+ if (list_empty(&dap->cmd_pool)) {
+ pool = calloc(1, sizeof(struct dap_cmd_pool));
+ if (pool == NULL)
+ return NULL;
+ } else {
+ pool = list_first_entry(&dap->cmd_pool, struct dap_cmd_pool, lh);
+ list_del(&pool->lh);
}
+ INIT_LIST_HEAD(&pool->lh);
+ dap->cmd_pool_size++;
+
+ struct dap_cmd *cmd = &pool->cmd;
+ INIT_LIST_HEAD(&cmd->lh);
+ cmd->instr = instr;
+ cmd->reg_addr = reg_addr;
+ cmd->RnW = RnW;
+ if (outvalue != NULL)
+ memcpy(cmd->outvalue_buf, outvalue, 4);
+ cmd->invalue = (invalue != NULL) ? invalue : cmd->invalue_buf;
+ cmd->memaccess_tck = memaccess_tck;
+
return cmd;
}
-static void flush_journal(struct list_head *lh)
+static void dap_cmd_release(struct adiv5_dap *dap, struct dap_cmd *cmd)
+{
+ struct dap_cmd_pool *pool = container_of(cmd, struct dap_cmd_pool, cmd);
+ if (dap->cmd_pool_size > MAX_DAP_COMMAND_NUM)
+ free(pool);
+ else
+ list_add(&pool->lh, &dap->cmd_pool);
+
+ dap->cmd_pool_size--;
+}
+
+static void flush_journal(struct adiv5_dap *dap, struct list_head *lh)
{
struct dap_cmd *el, *tmp;
+ list_for_each_entry_safe(el, tmp, lh, lh) {
+ list_del(&el->lh);
+ dap_cmd_release(dap, el);
+ }
+}
+
+static void jtag_quit(struct adiv5_dap *dap)
+{
+ struct dap_cmd_pool *el, *tmp;
+ struct list_head *lh = &dap->cmd_pool;
+
list_for_each_entry_safe(el, tmp, lh, lh) {
list_del(&el->lh);
free(el);
@@ -273,7 +322,7 @@ static int adi_jtag_dp_scan(struct adiv5_dap *dap,
struct dap_cmd *cmd;
int retval;
- cmd = dap_cmd_new(instr, reg_addr, RnW, outvalue, invalue, memaccess_tck);
+ cmd = dap_cmd_new(dap, instr, reg_addr, RnW, outvalue, invalue, memaccess_tck);
if (cmd != NULL)
cmd->dp_select = dap->select;
else
@@ -415,7 +464,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
* To complete the READ, we just keep polling RDBUFF
* until the WAIT condition clears
*/
- tmp = dap_cmd_new(JTAG_DP_DPACC,
+ tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
DP_RDBUFF, DPAP_READ, NULL, NULL, 0);
if (tmp == NULL) {
retval = ERROR_JTAG_DEVICE_ERROR;
@@ -459,7 +508,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
}
/* we're done with this command, release it */
- free(tmp);
+ dap_cmd_release(dap, tmp);
if (retval != ERROR_OK)
goto done;
@@ -479,7 +528,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
}
/* we're done with the journal, flush it */
- flush_journal(&dap->cmd_journal);
+ flush_journal(dap, &dap->cmd_journal);
/* check for overrun condition in the last batch of transactions */
if (found_wait) {
@@ -494,7 +543,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
/* restore SELECT register first */
if (!list_empty(&replay_list)) {
el = list_first_entry(&replay_list, struct dap_cmd, lh);
- tmp = dap_cmd_new(JTAG_DP_DPACC,
+ tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
DP_SELECT, DPAP_WRITE, (uint8_t *)&el->dp_select, NULL, 0);
if (tmp == NULL) {
retval = ERROR_JTAG_DEVICE_ERROR;
@@ -545,8 +594,8 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
}
done:
- flush_journal(&replay_list);
- flush_journal(&dap->cmd_journal);
+ flush_journal(dap, &replay_list);
+ flush_journal(dap, &dap->cmd_journal);
return retval;
}
@@ -595,7 +644,7 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
}
done:
- flush_journal(&dap->cmd_journal);
+ flush_journal(dap, &dap->cmd_journal);
return retval;
}
@@ -615,10 +664,36 @@ static int jtag_check_reconnect(struct adiv5_dap *dap)
return ERROR_OK;
}
+static int jtag_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+ int retval;
+
+ switch (seq) {
+ case JTAG_TO_SWD:
+ retval = jtag_add_tms_seq(swd_seq_jtag_to_swd_len,
+ swd_seq_jtag_to_swd, TAP_INVALID);
+ break;
+ case SWD_TO_JTAG:
+ retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len,
+ swd_seq_swd_to_jtag, TAP_RESET);
+ break;
+ default:
+ LOG_ERROR("Sequence %d not supported", seq);
+ return ERROR_FAIL;
+ }
+ if (retval == ERROR_OK)
+ retval = jtag_execute_queue();
+ return retval;
+}
+
static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
uint32_t *data)
{
- int retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg,
+ int retval = jtag_limit_queue_size(dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg,
DPAP_READ, 0, dap->last_read, 0, NULL);
dap->last_read = data;
return retval;
@@ -627,7 +702,11 @@ static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg,
uint32_t data)
{
- int retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
+ int retval = jtag_limit_queue_size(dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
reg, DPAP_WRITE, data, dap->last_read, 0, NULL);
dap->last_read = NULL;
return retval;
@@ -650,7 +729,11 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg)
static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
uint32_t *data)
{
- int retval = jtag_check_reconnect(ap->dap);
+ int retval = jtag_limit_queue_size(ap->dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = jtag_check_reconnect(ap->dap);
if (retval != ERROR_OK)
return retval;
@@ -668,7 +751,11 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg,
uint32_t data)
{
- int retval = jtag_check_reconnect(ap->dap);
+ int retval = jtag_limit_queue_size(ap->dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = jtag_check_reconnect(ap->dap);
if (retval != ERROR_OK)
return retval;
@@ -718,6 +805,7 @@ static int jtag_dp_sync(struct adiv5_dap *dap)
*/
const struct dap_ops jtag_dp_ops = {
.connect = jtag_connect,
+ .send_sequence = jtag_send_sequence,
.queue_dp_read = jtag_dp_q_read,
.queue_dp_write = jtag_dp_q_write,
.queue_ap_read = jtag_ap_q_read,
@@ -725,4 +813,5 @@ const struct dap_ops jtag_dp_ops = {
.queue_ap_abort = jtag_ap_q_abort,
.run = jtag_dp_run,
.sync = jtag_dp_sync,
+ .quit = jtag_quit,
};
diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c
index 594b5081f..ee30ff7ba 100644
--- a/src/target/adi_v5_swd.c
+++ b/src/target/adi_v5_swd.c
@@ -96,7 +96,7 @@ static int swd_run_inner(struct adiv5_dap *dap)
static int swd_connect(struct adiv5_dap *dap)
{
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
- uint32_t dpidr;
+ uint32_t dpidr = 0xdeadbeef;
int status;
/* FIXME validate transport config ... is the
@@ -112,7 +112,7 @@ static int swd_connect(struct adiv5_dap *dap)
if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
if (jtag_reset_config & RESET_SRST_NO_GATING)
- swd_add_reset(1);
+ adapter_assert_reset();
else
LOG_WARNING("\'srst_nogate\' reset_config option is required");
}
@@ -142,6 +142,14 @@ static int swd_connect(struct adiv5_dap *dap)
return status;
}
+static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+ const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
+ assert(swd);
+
+ return swd->switch_seq(seq);
+}
+
static inline int check_sync(struct adiv5_dap *dap)
{
return do_sync ? swd_run_inner(dap) : ERROR_OK;
@@ -320,6 +328,7 @@ static void swd_quit(struct adiv5_dap *dap)
const struct dap_ops swd_dap_ops = {
.connect = swd_connect,
+ .send_sequence = swd_send_sequence,
.queue_dp_read = swd_queue_dp_read,
.queue_dp_write = swd_queue_dp_write,
.queue_ap_read = swd_queue_ap_read,
@@ -359,9 +368,9 @@ static const struct command_registration swd_handlers[] = {
static int swd_select(struct command_context *ctx)
{
- /* FIXME: only place where global 'jtag_interface' is still needed */
- extern struct jtag_interface *jtag_interface;
- const struct swd_driver *swd = jtag_interface->swd;
+ /* FIXME: only place where global 'adapter_driver' is still needed */
+ extern struct adapter_driver *adapter_driver;
+ const struct swd_driver *swd = adapter_driver->swd_ops;
int retval;
retval = register_commands(ctx, NULL, swd_handlers);
diff --git a/src/target/arc.c b/src/target/arc.c
new file mode 100644
index 000000000..6cf0ec7af
--- /dev/null
+++ b/src/target/arc.c
@@ -0,0 +1,1652 @@
+/***************************************************************************
+ * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+
+
+/*
+ * ARC architecture specific details.
+ *
+ * ARC has two types of registers:
+ * 1) core registers(e.g. r0,r1..) [is_core = true]
+ * 2) Auxiliary registers [is_core = false]..
+ *
+ * Auxiliary registers at the same time can be divided into
+ * read-only BCR(build configuration regs, e.g. isa_config, mpu_build) and
+ * R/RW non-BCR ("control" register, e.g. pc, status32_t, debug).
+ *
+ * The way of accessing to Core and AUX registers differs on Jtag level.
+ * BCR/non-BCR describes if the register is immutable and that reading
+ * unexisting register is safe RAZ, rather then an error.
+ * Note, core registers cannot be BCR.
+ *
+ * In arc/cpu/ tcl files all regiters are defined as core, non-BCR aux
+ * and BCR aux, in "add-reg" command they are passed to three lists
+ * respectively: core_reg_descriptions, aux_reg_descriptions,
+ * bcr_reg_descriptions.
+ *
+ * Due to the specifics of accessing to BCR/non-BCR registers there are two
+ * register caches:
+ * 1) core_and_aux_cache - includes registers described in
+ * core_reg_descriptions and aux_reg_descriptions lists.
+ * Used during save/restore context step.
+ * 2) bcr_cache - includes registers described bcr_reg_descriptions.
+ * Currently used internally during configure step.
+ */
+
+
+
+void arc_reg_data_type_add(struct target *target,
+ struct arc_reg_data_type *data_type)
+{
+ LOG_DEBUG("Adding %s reg_data_type", data_type->data_type.id);
+ struct arc_common *arc = target_to_arc(target);
+ assert(arc);
+
+ list_add_tail(&data_type->list, &arc->reg_data_types);
+}
+
+/**
+ * Private implementation of register_get_by_name() for ARC that
+ * doesn't skip not [yet] existing registers. Used in many places
+ * for iteration through registers and even for marking required registers as
+ * existing.
+ */
+struct reg *arc_reg_get_by_name(struct reg_cache *first,
+ const char *name, bool search_all)
+{
+ unsigned int i;
+ struct reg_cache *cache = first;
+
+ while (cache) {
+ for (i = 0; i < cache->num_regs; i++) {
+ if (!strcmp(cache->reg_list[i].name, name))
+ return &(cache->reg_list[i]);
+ }
+
+ if (search_all)
+ cache = cache->next;
+ else
+ break;
+ }
+
+ return NULL;
+}
+
+
+/* Initialize arc_common structure, which passes to openocd target instance */
+static int arc_init_arch_info(struct target *target, struct arc_common *arc,
+ struct jtag_tap *tap)
+{
+ arc->common_magic = ARC_COMMON_MAGIC;
+ target->arch_info = arc;
+
+ arc->jtag_info.tap = tap;
+
+ /* The only allowed ir_length is 4 for ARC jtag. */
+ if (tap->ir_length != 4) {
+ LOG_ERROR("ARC jtag instruction length should be equal to 4");
+ return ERROR_FAIL;
+ }
+
+ /* Add standard GDB data types */
+ INIT_LIST_HEAD(&arc->reg_data_types);
+ struct arc_reg_data_type *std_types = calloc(ARRAY_SIZE(standard_gdb_types),
+ sizeof(*std_types));
+
+ if (!std_types) {
+ LOG_ERROR("Unable to allocate memory");
+ return ERROR_FAIL;
+ }
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(standard_gdb_types); i++) {
+ std_types[i].data_type.type = standard_gdb_types[i].type;
+ std_types[i].data_type.id = standard_gdb_types[i].id;
+ arc_reg_data_type_add(target, &(std_types[i]));
+ }
+
+ /* Fields related to target descriptions */
+ INIT_LIST_HEAD(&arc->core_reg_descriptions);
+ INIT_LIST_HEAD(&arc->aux_reg_descriptions);
+ INIT_LIST_HEAD(&arc->bcr_reg_descriptions);
+ arc->num_regs = 0;
+ arc->num_core_regs = 0;
+ arc->num_aux_regs = 0;
+ arc->num_bcr_regs = 0;
+ arc->last_general_reg = ULONG_MAX;
+ arc->pc_index_in_cache = ULONG_MAX;
+ arc->debug_index_in_cache = ULONG_MAX;
+
+ return ERROR_OK;
+}
+
+int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg,
+ const char * const type_name, const size_t type_name_len)
+{
+ assert(target);
+ assert(arc_reg);
+
+ struct arc_common *arc = target_to_arc(target);
+ assert(arc);
+
+ /* Find register type */
+ {
+ struct arc_reg_data_type *type;
+ list_for_each_entry(type, &arc->reg_data_types, list)
+ if (!strncmp(type->data_type.id, type_name, type_name_len)) {
+ arc_reg->data_type = &(type->data_type);
+ break;
+ }
+
+ if (!arc_reg->data_type)
+ return ERROR_ARC_REGTYPE_NOT_FOUND;
+ }
+
+ if (arc_reg->is_core) {
+ list_add_tail(&arc_reg->list, &arc->core_reg_descriptions);
+ arc->num_core_regs += 1;
+ } else if (arc_reg->is_bcr) {
+ list_add_tail(&arc_reg->list, &arc->bcr_reg_descriptions);
+ arc->num_bcr_regs += 1;
+ } else {
+ list_add_tail(&arc_reg->list, &arc->aux_reg_descriptions);
+ arc->num_aux_regs += 1;
+ }
+ arc->num_regs += 1;
+
+ LOG_DEBUG(
+ "added register {name=%s, num=0x%x, type=%s%s%s%s}",
+ arc_reg->name, arc_reg->arch_num, arc_reg->data_type->id,
+ arc_reg->is_core ? ", core" : "", arc_reg->is_bcr ? ", bcr" : "",
+ arc_reg->is_general ? ", general" : ""
+ );
+
+ return ERROR_OK;
+}
+
+/* Reading core or aux register */
+static int arc_get_register(struct reg *reg)
+{
+ assert(reg);
+
+ struct arc_reg_desc *desc = reg->arch_info;
+ struct target *target = desc->target;
+ struct arc_common *arc = target_to_arc(target);
+
+ uint32_t value;
+
+ if (reg->valid) {
+ LOG_DEBUG("Get register (cached) gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32,
+ reg->number, desc->name, target_buffer_get_u32(target, reg->value));
+ return ERROR_OK;
+ }
+
+ if (desc->is_core) {
+ /* Accessing to R61/R62 registers causes Jtag hang */
+ if (desc->arch_num == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) {
+ LOG_ERROR("It is forbidden to read core registers 61 and 62.");
+ return ERROR_FAIL;
+ }
+ CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, desc->arch_num,
+ &value));
+ } else {
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, desc->arch_num,
+ &value));
+ }
+
+ target_buffer_set_u32(target, reg->value, value);
+
+ /* If target is unhalted all register reads should be uncached. */
+ if (target->state == TARGET_HALTED)
+ reg->valid = true;
+ else
+ reg->valid = false;
+
+ reg->dirty = false;
+
+ LOG_DEBUG("Get register gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32,
+ reg->number , desc->name, value);
+
+
+ return ERROR_OK;
+}
+
+/* Writing core or aux register */
+static int arc_set_register(struct reg *reg, uint8_t *buf)
+{
+ struct arc_reg_desc *desc = reg->arch_info;
+ struct target *target = desc->target;
+ uint32_t value = target_buffer_get_u32(target, buf);
+ /* Unlike "get" function "set" is supported only if target
+ * is in halt mode. Async writes are not supported yet. */
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ /* Accessing to R61/R62 registers causes Jtag hang */
+ if (desc->is_core && (desc->arch_num == CORE_R61_NUM ||
+ desc->arch_num == CORE_R62_NUM)) {
+ LOG_ERROR("It is forbidden to write core registers 61 and 62.");
+ return ERROR_FAIL;
+ }
+ target_buffer_set_u32(target, reg->value, value);
+
+ LOG_DEBUG("Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+ reg->number, desc->name, value);
+
+ reg->valid = true;
+ reg->dirty = true;
+
+ return ERROR_OK;
+}
+
+const struct reg_arch_type arc_reg_type = {
+ .get = arc_get_register,
+ .set = arc_set_register,
+};
+
+/* GDB register groups. For now we suport only general and "empty" */
+static const char * const reg_group_general = "general";
+static const char * const reg_group_other = "";
+
+/* Common code to initialize `struct reg` for different registers: core, aux, bcr. */
+static int arc_init_reg(struct target *target, struct reg *reg,
+ struct arc_reg_desc *reg_desc, unsigned long number)
+{
+ assert(target);
+ assert(reg);
+ assert(reg_desc);
+
+ struct arc_common *arc = target_to_arc(target);
+
+ /* Initialize struct reg */
+ reg->name = reg_desc->name;
+ reg->size = 32; /* All register in ARC are 32-bit */
+ reg->value = ®_desc->reg_value;
+ reg->type = &arc_reg_type;
+ reg->arch_info = reg_desc;
+ reg->caller_save = true; /* @todo should be configurable. */
+ reg->reg_data_type = reg_desc->data_type;
+ reg->feature = ®_desc->feature;
+
+ reg->feature->name = reg_desc->gdb_xml_feature;
+
+ /* reg->number is used by OpenOCD as value for @regnum. Thus when setting
+ * value of a register GDB will use it as a number of register in
+ * P-packet. OpenOCD gdbserver will then use number of register in
+ * P-packet as an array index in the reg_list returned by
+ * arc_regs_get_gdb_reg_list. So to ensure that registers are assigned
+ * correctly it would be required to either sort registers in
+ * arc_regs_get_gdb_reg_list or to assign numbers sequentially here and
+ * according to how registers will be sorted in
+ * arc_regs_get_gdb_reg_list. Second options is much more simpler. */
+ reg->number = number;
+
+ if (reg_desc->is_general) {
+ arc->last_general_reg = reg->number;
+ reg->group = reg_group_general;
+ } else {
+ reg->group = reg_group_other;
+ }
+
+ return ERROR_OK;
+}
+
+/* Building aux/core reg_cache */
+static int arc_build_reg_cache(struct target *target)
+{
+ unsigned long i = 0;
+ struct arc_reg_desc *reg_desc;
+ /* get pointers to arch-specific information */
+ struct arc_common *arc = target_to_arc(target);
+ const unsigned long num_regs = arc->num_core_regs + arc->num_aux_regs;
+ struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
+ struct reg_cache *cache = calloc(1, sizeof(*cache));
+ struct reg *reg_list = calloc(num_regs, sizeof(*reg_list));
+
+ if (!cache || !reg_list) {
+ LOG_ERROR("Not enough memory");
+ goto fail;
+ }
+
+ /* Build the process context cache */
+ cache->name = "arc registers";
+ cache->next = NULL;
+ cache->reg_list = reg_list;
+ cache->num_regs = num_regs;
+ arc->core_and_aux_cache = cache;
+ (*cache_p) = cache;
+
+ if (list_empty(&arc->core_reg_descriptions)) {
+ LOG_ERROR("No core registers were defined");
+ goto fail;
+ }
+
+ list_for_each_entry(reg_desc, &arc->core_reg_descriptions, list) {
+ CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i));
+
+ LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i,
+ reg_list[i].name, reg_list[i].group,
+ reg_list[i].feature->name);
+
+ i += 1;
+ }
+
+ if (list_empty(&arc->aux_reg_descriptions)) {
+ LOG_ERROR("No aux registers were defined");
+ goto fail;
+ }
+
+ list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) {
+ CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i));
+
+ LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i,
+ reg_list[i].name, reg_list[i].group,
+ reg_list[i].feature->name);
+
+ /* PC and DEBUG are essential so we search for them. */
+ if (!strcmp("pc", reg_desc->name)) {
+ if (arc->pc_index_in_cache != ULONG_MAX) {
+ LOG_ERROR("Double definition of PC in configuration");
+ goto fail;
+ }
+ arc->pc_index_in_cache = i;
+ } else if (!strcmp("debug", reg_desc->name)) {
+ if (arc->debug_index_in_cache != ULONG_MAX) {
+ LOG_ERROR("Double definition of DEBUG in configuration");
+ goto fail;
+ }
+ arc->debug_index_in_cache = i;
+ }
+ i += 1;
+ }
+
+ if (arc->pc_index_in_cache == ULONG_MAX
+ || arc->debug_index_in_cache == ULONG_MAX) {
+ LOG_ERROR("`pc' and `debug' registers must be present in target description.");
+ goto fail;
+ }
+
+ assert(i == (arc->num_core_regs + arc->num_aux_regs));
+
+ arc->core_aux_cache_built = true;
+
+ return ERROR_OK;
+
+fail:
+ free(cache);
+ free(reg_list);
+
+ return ERROR_FAIL;
+}
+
+/* Build bcr reg_cache.
+ * This function must be called only after arc_build_reg_cache */
+static int arc_build_bcr_reg_cache(struct target *target)
+{
+ /* get pointers to arch-specific information */
+ struct arc_common *arc = target_to_arc(target);
+ const unsigned long num_regs = arc->num_bcr_regs;
+ struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
+ struct reg_cache *cache = malloc(sizeof(*cache));
+ struct reg *reg_list = calloc(num_regs, sizeof(*reg_list));
+
+ struct arc_reg_desc *reg_desc;
+ unsigned long i = 0;
+ unsigned long gdb_regnum = arc->core_and_aux_cache->num_regs;
+
+ if (!cache || !reg_list) {
+ LOG_ERROR("Unable to allocate memory");
+ goto fail;
+ }
+
+ /* Build the process context cache */
+ cache->name = "arc.bcr";
+ cache->next = NULL;
+ cache->reg_list = reg_list;
+ cache->num_regs = num_regs;
+ arc->bcr_cache = cache;
+ (*cache_p) = cache;
+
+ if (list_empty(&arc->bcr_reg_descriptions)) {
+ LOG_ERROR("No BCR registers are defined");
+ goto fail;
+ }
+
+ list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) {
+ CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum));
+ /* BCRs always semantically, they are just read-as-zero, if there is
+ * not real register. */
+ reg_list[i].exist = true;
+
+ LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i,
+ reg_list[i].name, reg_list[i].group,
+ reg_list[i].feature->name);
+ i += 1;
+ gdb_regnum += 1;
+ }
+
+ assert(i == arc->num_bcr_regs);
+
+ arc->bcr_cache_built = true;
+
+
+ return ERROR_OK;
+fail:
+ free(cache);
+ free(reg_list);
+
+ return ERROR_FAIL;
+}
+
+
+static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
+{
+ assert(target->reg_cache);
+ struct arc_common *arc = target_to_arc(target);
+
+ /* get pointers to arch-specific information storage */
+ *reg_list_size = arc->num_regs;
+ *reg_list = calloc(*reg_list_size, sizeof(struct reg *));
+
+ if (!*reg_list) {
+ LOG_ERROR("Unable to allocate memory");
+ return ERROR_FAIL;
+ }
+
+ /* OpenOCD gdb_server API seems to be inconsistent here: when it generates
+ * XML tdesc it filters out !exist registers, however when creating a
+ * g-packet it doesn't do so. REG_CLASS_ALL is used in first case, and
+ * REG_CLASS_GENERAL used in the latter one. Due to this we had to filter
+ * out !exist register for "general", but not for "all". Attempts to filter out
+ * !exist for "all" as well will cause a failed check in OpenOCD GDB
+ * server. */
+ if (reg_class == REG_CLASS_ALL) {
+ unsigned long i = 0;
+ struct reg_cache *reg_cache = target->reg_cache;
+ while (reg_cache) {
+ for (unsigned j = 0; j < reg_cache->num_regs; j++, i++)
+ (*reg_list)[i] = ®_cache->reg_list[j];
+ reg_cache = reg_cache->next;
+ }
+ assert(i == arc->num_regs);
+ LOG_DEBUG("REG_CLASS_ALL: number of regs=%i", *reg_list_size);
+ } else {
+ unsigned long i = 0;
+ unsigned long gdb_reg_number = 0;
+ struct reg_cache *reg_cache = target->reg_cache;
+ while (reg_cache) {
+ for (unsigned j = 0;
+ j < reg_cache->num_regs && gdb_reg_number <= arc->last_general_reg;
+ j++) {
+ if (reg_cache->reg_list[j].exist) {
+ (*reg_list)[i] = ®_cache->reg_list[j];
+ i++;
+ }
+ gdb_reg_number += 1;
+ }
+ reg_cache = reg_cache->next;
+ }
+ *reg_list_size = i;
+ LOG_DEBUG("REG_CLASS_GENERAL: number of regs=%i", *reg_list_size);
+ }
+
+ return ERROR_OK;
+}
+
+/* Reading field of struct_type register */
+int arc_reg_get_field(struct target *target, const char *reg_name,
+ const char *field_name, uint32_t *value_ptr)
+{
+ struct reg_data_type_struct_field *field;
+
+ LOG_DEBUG("getting register field (reg_name=%s, field_name=%s)", reg_name, field_name);
+
+ /* Get register */
+ struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true);
+
+ if (!reg) {
+ LOG_ERROR("Requested register `%s' doens't exist.", reg_name);
+ return ERROR_ARC_REGISTER_NOT_FOUND;
+ }
+
+ if (reg->reg_data_type->type != REG_TYPE_ARCH_DEFINED
+ || reg->reg_data_type->type_class != REG_TYPE_CLASS_STRUCT)
+ return ERROR_ARC_REGISTER_IS_NOT_STRUCT;
+
+ /* Get field in a register */
+ struct reg_data_type_struct *reg_struct =
+ reg->reg_data_type->reg_type_struct;
+ for (field = reg_struct->fields;
+ field;
+ field = field->next) {
+ if (!strcmp(field->name, field_name))
+ break;
+ }
+
+ if (!field)
+ return ERROR_ARC_REGISTER_FIELD_NOT_FOUND;
+
+ if (!field->use_bitfields)
+ return ERROR_ARC_FIELD_IS_NOT_BITFIELD;
+
+ if (!reg->valid)
+ CHECK_RETVAL(reg->type->get(reg));
+
+ /* First do endiannes-safe read of register value
+ * then convert it to binary buffer for further
+ * field extraction */
+
+ *value_ptr = buf_get_u32(reg->value, field->bitfield->start,
+ field->bitfield->end - field->bitfield->start + 1);
+
+ return ERROR_OK;
+}
+
+static int arc_get_register_value(struct target *target, const char *reg_name,
+ uint32_t *value_ptr)
+{
+ LOG_DEBUG("reg_name=%s", reg_name);
+
+ struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true);
+
+ if (!reg)
+ return ERROR_ARC_REGISTER_NOT_FOUND;
+
+ if (!reg->valid)
+ CHECK_RETVAL(reg->type->get(reg));
+
+ *value_ptr = target_buffer_get_u32(target, reg->value);
+
+ return ERROR_OK;
+}
+
+
+/* Configure DCCM's */
+static int arc_configure_dccm(struct target *target)
+{
+ struct arc_common *arc = target_to_arc(target);
+
+ uint32_t dccm_build_version, dccm_build_size0, dccm_build_size1;
+ CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "version",
+ &dccm_build_version));
+ CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size0",
+ &dccm_build_size0));
+ CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size1",
+ &dccm_build_size1));
+ /* There is no yet support of configurable number of cycles,
+ * So there is no difference between v3 and v4 */
+ if ((dccm_build_version == 3 || dccm_build_version == 4) && dccm_build_size0 > 0) {
+ CHECK_RETVAL(arc_get_register_value(target, "aux_dccm", &(arc->dccm_start)));
+ uint32_t dccm_size = 0x100;
+ dccm_size <<= dccm_build_size0;
+ if (dccm_build_size0 == 0xF)
+ dccm_size <<= dccm_build_size1;
+ arc->dccm_end = arc->dccm_start + dccm_size;
+ LOG_DEBUG("DCCM detected start=0x%" PRIx32 " end=0x%" PRIx32,
+ arc->dccm_start, arc->dccm_end);
+
+ }
+ return ERROR_OK;
+}
+
+
+/* Configure ICCM's */
+
+static int arc_configure_iccm(struct target *target)
+{
+ struct arc_common *arc = target_to_arc(target);
+
+ /* ICCM0 */
+ uint32_t iccm_build_version, iccm_build_size00, iccm_build_size01;
+ uint32_t aux_iccm = 0;
+ CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "version",
+ &iccm_build_version));
+ CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size0",
+ &iccm_build_size00));
+ CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size1",
+ &iccm_build_size01));
+ if (iccm_build_version == 4 && iccm_build_size00 > 0) {
+ CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm));
+ uint32_t iccm0_size = 0x100;
+ iccm0_size <<= iccm_build_size00;
+ if (iccm_build_size00 == 0xF)
+ iccm0_size <<= iccm_build_size01;
+ /* iccm0 start is located in highest 4 bits of aux_iccm */
+ arc->iccm0_start = aux_iccm & 0xF0000000;
+ arc->iccm0_end = arc->iccm0_start + iccm0_size;
+ LOG_DEBUG("ICCM0 detected start=0x%" PRIx32 " end=0x%" PRIx32,
+ arc->iccm0_start, arc->iccm0_end);
+ }
+
+ /* ICCM1 */
+ uint32_t iccm_build_size10, iccm_build_size11;
+ CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size0",
+ &iccm_build_size10));
+ CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size1",
+ &iccm_build_size11));
+ if (iccm_build_version == 4 && iccm_build_size10 > 0) {
+ /* Use value read for ICCM0 */
+ if (!aux_iccm)
+ CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm));
+ uint32_t iccm1_size = 0x100;
+ iccm1_size <<= iccm_build_size10;
+ if (iccm_build_size10 == 0xF)
+ iccm1_size <<= iccm_build_size11;
+ arc->iccm1_start = aux_iccm & 0x0F000000;
+ arc->iccm1_end = arc->iccm1_start + iccm1_size;
+ LOG_DEBUG("ICCM1 detected start=0x%" PRIx32 " end=0x%" PRIx32,
+ arc->iccm1_start, arc->iccm1_end);
+ }
+ return ERROR_OK;
+}
+
+/* Configure some core features, depending on BCRs. */
+static int arc_configure(struct target *target)
+{
+ LOG_DEBUG("Configuring ARC ICCM and DCCM");
+
+ /* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */
+ if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) &&
+ arc_reg_get_by_name(target->reg_cache, "aux_dccm", true))
+ CHECK_RETVAL(arc_configure_dccm(target));
+
+ /* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */
+ if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) &&
+ arc_reg_get_by_name(target->reg_cache, "aux_iccm", true))
+ CHECK_RETVAL(arc_configure_iccm(target));
+
+ return ERROR_OK;
+}
+
+/* arc_examine is function, which is used for all arc targets*/
+static int arc_examine(struct target *target)
+{
+ uint32_t status;
+ struct arc_common *arc = target_to_arc(target);
+
+ CHECK_RETVAL(arc_jtag_startup(&arc->jtag_info));
+
+ if (!target_was_examined(target)) {
+ CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status));
+ if (status & ARC_JTAG_STAT_RU)
+ target->state = TARGET_RUNNING;
+ else
+ target->state = TARGET_HALTED;
+
+ /* Read BCRs and configure optional registers. */
+ CHECK_RETVAL(arc_configure(target));
+
+ target_set_examined(target);
+ }
+
+ return ERROR_OK;
+}
+
+static int arc_halt(struct target *target)
+{
+ uint32_t value, irq_state;
+ struct arc_common *arc = target_to_arc(target);
+
+ LOG_DEBUG("target->state: %s", target_state_name(target));
+
+ if (target->state == TARGET_HALTED) {
+ LOG_DEBUG("target was already halted");
+ return ERROR_OK;
+ }
+
+ if (target->state == TARGET_UNKNOWN)
+ LOG_WARNING("target was in unknown state when halt was requested");
+
+ if (target->state == TARGET_RESET) {
+ if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) {
+ LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
+ return ERROR_TARGET_FAILURE;
+ } else {
+ target->debug_reason = DBG_REASON_DBGRQ;
+ }
+ }
+
+ /* Break (stop) processor.
+ * Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally.
+ * We do not use here arc_get/set_core_reg functions here because they imply
+ * that the processor is already halted. */
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value));
+ value |= SET_CORE_FORCE_HALT; /* set the HALT bit */
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value));
+ alive_sleep(1);
+
+ /* Save current IRQ state */
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &irq_state));
+
+ if (irq_state & AUX_STATUS32_REG_IE_BIT)
+ arc->irq_state = 1;
+ else
+ arc->irq_state = 0;
+
+ /* update state and notify gdb*/
+ target->state = TARGET_HALTED;
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
+
+ /* some more debug information */
+ if (debug_level >= LOG_LVL_DEBUG) {
+ LOG_DEBUG("core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value);
+ CHECK_RETVAL(arc_get_register_value(target, "status32", &value));
+ LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value);
+ }
+
+ return ERROR_OK;
+}
+
+/**
+ * Read registers that are used in GDB g-packet. We don't read them one-by-one,
+ * but do that in one batch operation to improve speed. Calls to JTAG layer are
+ * expensive so it is better to make one big call that reads all necessary
+ * registers, instead of many calls, one for one register.
+ */
+static int arc_save_context(struct target *target)
+{
+ int retval = ERROR_OK;
+ unsigned int i;
+ struct arc_common *arc = target_to_arc(target);
+ struct reg *reg_list = arc->core_and_aux_cache->reg_list;
+
+ LOG_DEBUG("Saving aux and core registers values");
+ assert(reg_list);
+
+ /* It is assumed that there is at least one AUX register in the list, for
+ * example PC. */
+ const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t);
+ /* last_general_reg is inclusive number. To get count of registers it is
+ * required to do +1. */
+ const uint32_t regs_to_scan =
+ MIN(arc->last_general_reg + 1, arc->num_regs);
+ const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t);
+ uint32_t *core_values = malloc(core_regs_size);
+ uint32_t *aux_values = malloc(aux_regs_size);
+ uint32_t *core_addrs = malloc(core_regs_size);
+ uint32_t *aux_addrs = malloc(aux_regs_size);
+ unsigned int core_cnt = 0;
+ unsigned int aux_cnt = 0;
+
+ if (!core_values || !core_addrs || !aux_values || !aux_addrs) {
+ LOG_ERROR("Unable to allocate memory");
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+
+ memset(core_values, 0xff, core_regs_size);
+ memset(core_addrs, 0xff, core_regs_size);
+ memset(aux_values, 0xff, aux_regs_size);
+ memset(aux_addrs, 0xff, aux_regs_size);
+
+ for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) {
+ struct reg *reg = &(reg_list[i]);
+ struct arc_reg_desc *arc_reg = reg->arch_info;
+ if (!reg->valid && reg->exist) {
+ core_addrs[core_cnt] = arc_reg->arch_num;
+ core_cnt += 1;
+ }
+ }
+
+ for (i = arc->num_core_regs; i < regs_to_scan; i++) {
+ struct reg *reg = &(reg_list[i]);
+ struct arc_reg_desc *arc_reg = reg->arch_info;
+ if (!reg->valid && reg->exist) {
+ aux_addrs[aux_cnt] = arc_reg->arch_num;
+ aux_cnt += 1;
+ }
+ }
+
+ /* Read data from target. */
+ if (core_cnt > 0) {
+ retval = arc_jtag_read_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Attempt to read core registers failed.");
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+ }
+ if (aux_cnt > 0) {
+ retval = arc_jtag_read_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Attempt to read aux registers failed.");
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+ }
+
+ /* Parse core regs */
+ core_cnt = 0;
+ for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) {
+ struct reg *reg = &(reg_list[i]);
+ struct arc_reg_desc *arc_reg = reg->arch_info;
+ if (!reg->valid && reg->exist) {
+ target_buffer_set_u32(target, reg->value, core_values[core_cnt]);
+ core_cnt += 1;
+ reg->valid = true;
+ reg->dirty = false;
+ LOG_DEBUG("Get core register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+ i, arc_reg->name, core_values[core_cnt]);
+ }
+ }
+
+ /* Parse aux regs */
+ aux_cnt = 0;
+ for (i = arc->num_core_regs; i < regs_to_scan; i++) {
+ struct reg *reg = &(reg_list[i]);
+ struct arc_reg_desc *arc_reg = reg->arch_info;
+ if (!reg->valid && reg->exist) {
+ target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]);
+ aux_cnt += 1;
+ reg->valid = true;
+ reg->dirty = false;
+ LOG_DEBUG("Get aux register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+ i , arc_reg->name, aux_values[aux_cnt]);
+ }
+ }
+
+exit:
+ free(core_values);
+ free(core_addrs);
+ free(aux_values);
+ free(aux_addrs);
+
+ return retval;
+}
+
+static int arc_examine_debug_reason(struct target *target)
+{
+ uint32_t debug_bh;
+
+ /* Only check for reason if don't know it already. */
+ /* BTW After singlestep at this point core is not marked as halted, so
+ * reading from memory to get current instruction wouldn't work anyway. */
+ if (target->debug_reason == DBG_REASON_DBGRQ ||
+ target->debug_reason == DBG_REASON_SINGLESTEP) {
+ return ERROR_OK;
+ }
+
+ CHECK_RETVAL(arc_reg_get_field(target, "debug", "bh",
+ &debug_bh));
+
+ if (debug_bh) {
+ /* DEBUG.BH is set if core halted due to BRK instruction. */
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ } else {
+ /* TODO: Add Actionpoint check when AP support will be introduced*/
+ LOG_WARNING("Unknown debug reason");
+ }
+
+ return ERROR_OK;
+}
+
+static int arc_debug_entry(struct target *target)
+{
+ CHECK_RETVAL(arc_save_context(target));
+
+ /* TODO: reset internal indicators of caches states, otherwise D$/I$
+ * will not be flushed/invalidated when required. */
+ CHECK_RETVAL(arc_examine_debug_reason(target));
+
+ return ERROR_OK;
+}
+
+static int arc_poll(struct target *target)
+{
+ uint32_t status, value;
+ struct arc_common *arc = target_to_arc(target);
+
+ /* gdb calls continuously through this arc_poll() function */
+ CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status));
+
+ /* check for processor halted */
+ if (status & ARC_JTAG_STAT_RU) {
+ if (target->state != TARGET_RUNNING) {
+ LOG_WARNING("target is still running!");
+ target->state = TARGET_RUNNING;
+ }
+ return ERROR_OK;
+ }
+ /* In some cases JTAG status register indicates that
+ * processor is in halt mode, but processor is still running.
+ * We check halt bit of AUX STATUS32 register for setting correct state. */
+ if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) {
+ CHECK_RETVAL(arc_get_register_value(target, "status32", &value));
+ if (value & AUX_STATUS32_REG_HALT_BIT) {
+ LOG_DEBUG("ARC core in halt or reset state.");
+ /* Save context if target was not in reset state */
+ if (target->state == TARGET_RUNNING)
+ CHECK_RETVAL(arc_debug_entry(target));
+ target->state = TARGET_HALTED;
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
+ } else {
+ LOG_DEBUG("Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, "
+ "target is still running");
+ }
+
+ } else if (target->state == TARGET_DEBUG_RUNNING) {
+
+ target->state = TARGET_HALTED;
+ LOG_DEBUG("ARC core is in debug running mode");
+
+ CHECK_RETVAL(arc_debug_entry(target));
+
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED));
+ }
+
+ return ERROR_OK;
+}
+
+static int arc_assert_reset(struct target *target)
+{
+ struct arc_common *arc = target_to_arc(target);
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+ bool srst_asserted = false;
+
+ LOG_DEBUG("target->state: %s", target_state_name(target));
+
+ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
+ /* allow scripts to override the reset event */
+
+ target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
+ register_cache_invalidate(arc->core_and_aux_cache);
+ /* An ARC target might be in halt state after reset, so
+ * if script requested processor to resume, then it must
+ * be manually started to ensure that this request
+ * is satisfied. */
+ if (target->state == TARGET_HALTED && !target->reset_halt) {
+ /* Resume the target and continue from the current
+ * PC register value. */
+ LOG_DEBUG("Starting CPU execution after reset");
+ CHECK_RETVAL(target_resume(target, 1, 0, 0, 0));
+ }
+ target->state = TARGET_RESET;
+
+ return ERROR_OK;
+ }
+
+ /* some cores support connecting while srst is asserted
+ * use that mode if it has been configured */
+ if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) &&
+ (jtag_reset_config & RESET_SRST_NO_GATING)) {
+ jtag_add_reset(0, 1);
+ srst_asserted = true;
+ }
+
+ if (jtag_reset_config & RESET_HAS_SRST) {
+ /* should issue a srst only, but we may have to assert trst as well */
+ if (jtag_reset_config & RESET_SRST_PULLS_TRST)
+ jtag_add_reset(1, 1);
+ else if (!srst_asserted)
+ jtag_add_reset(0, 1);
+ }
+
+ target->state = TARGET_RESET;
+ jtag_add_sleep(50000);
+
+ register_cache_invalidate(arc->core_and_aux_cache);
+
+ if (target->reset_halt)
+ CHECK_RETVAL(target_halt(target));
+
+ return ERROR_OK;
+}
+
+static int arc_deassert_reset(struct target *target)
+{
+ LOG_DEBUG("target->state: %s", target_state_name(target));
+
+ /* deassert reset lines */
+ jtag_add_reset(0, 0);
+
+ return ERROR_OK;
+}
+
+static int arc_arch_state(struct target *target)
+{
+ uint32_t pc_value;
+
+ if (debug_level < LOG_LVL_DEBUG)
+ return ERROR_OK;
+
+ CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value));
+
+ LOG_DEBUG("target state: %s; PC at: 0x%08" PRIx32,
+ target_state_name(target),
+ pc_value);
+
+ return ERROR_OK;
+}
+
+/**
+ * See arc_save_context() for reason why we want to dump all regs at once.
+ * This however means that if there are dependencies between registers they
+ * will not be observable until target will be resumed.
+ */
+static int arc_restore_context(struct target *target)
+{
+ int retval = ERROR_OK;
+ unsigned int i;
+ struct arc_common *arc = target_to_arc(target);
+ struct reg *reg_list = arc->core_and_aux_cache->reg_list;
+
+ LOG_DEBUG("Restoring registers values");
+ assert(reg_list);
+
+ const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t);
+ const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t);
+ uint32_t *core_values = malloc(core_regs_size);
+ uint32_t *aux_values = malloc(aux_regs_size);
+ uint32_t *core_addrs = malloc(core_regs_size);
+ uint32_t *aux_addrs = malloc(aux_regs_size);
+ unsigned int core_cnt = 0;
+ unsigned int aux_cnt = 0;
+
+ if (!core_values || !core_addrs || !aux_values || !aux_addrs) {
+ LOG_ERROR("Unable to allocate memory");
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+
+ memset(core_values, 0xff, core_regs_size);
+ memset(core_addrs, 0xff, core_regs_size);
+ memset(aux_values, 0xff, aux_regs_size);
+ memset(aux_addrs, 0xff, aux_regs_size);
+
+ for (i = 0; i < arc->num_core_regs; i++) {
+ struct reg *reg = &(reg_list[i]);
+ struct arc_reg_desc *arc_reg = reg->arch_info;
+ if (reg->valid && reg->exist && reg->dirty) {
+ LOG_DEBUG("Will write regnum=%u", i);
+ core_addrs[core_cnt] = arc_reg->arch_num;
+ core_values[core_cnt] = target_buffer_get_u32(target, reg->value);
+ core_cnt += 1;
+ }
+ }
+
+ for (i = 0; i < arc->num_aux_regs; i++) {
+ struct reg *reg = &(reg_list[arc->num_core_regs + i]);
+ struct arc_reg_desc *arc_reg = reg->arch_info;
+ if (reg->valid && reg->exist && reg->dirty) {
+ LOG_DEBUG("Will write regnum=%lu", arc->num_core_regs + i);
+ aux_addrs[aux_cnt] = arc_reg->arch_num;
+ aux_values[aux_cnt] = target_buffer_get_u32(target, reg->value);
+ aux_cnt += 1;
+ }
+ }
+
+ /* Write data to target.
+ * Check before write, if aux and core count is greater than 0. */
+ if (core_cnt > 0) {
+ retval = arc_jtag_write_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Attempt to write to core registers failed.");
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+ }
+
+ if (aux_cnt > 0) {
+ retval = arc_jtag_write_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Attempt to write to aux registers failed.");
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+ }
+
+exit:
+ free(core_values);
+ free(core_addrs);
+ free(aux_values);
+ free(aux_addrs);
+
+ return retval;
+}
+
+static int arc_enable_interrupts(struct target *target, int enable)
+{
+ uint32_t value;
+
+ struct arc_common *arc = target_to_arc(target);
+
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value));
+
+ if (enable) {
+ /* enable interrupts */
+ value |= SET_CORE_ENABLE_INTERRUPTS;
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value));
+ LOG_DEBUG("interrupts enabled");
+ } else {
+ /* disable interrupts */
+ value &= ~SET_CORE_ENABLE_INTERRUPTS;
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value));
+ LOG_DEBUG("interrupts disabled");
+ }
+
+ return ERROR_OK;
+}
+
+static int arc_resume(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints, int debug_execution)
+{
+ struct arc_common *arc = target_to_arc(target);
+ uint32_t resume_pc = 0;
+ uint32_t value;
+ struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache];
+
+ LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i,"
+ " debug_execution:%i", current, address, handle_breakpoints, debug_execution);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* current = 1: continue on current PC, otherwise continue at */
+ if (!current) {
+ target_buffer_set_u32(target, pc->value, address);
+ pc->dirty = 1;
+ pc->valid = 1;
+ LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address);
+ }
+
+ if (!current)
+ resume_pc = address;
+ else
+ resume_pc = target_buffer_get_u32(target, pc->value);
+
+ CHECK_RETVAL(arc_restore_context(target));
+
+ LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i",
+ resume_pc, pc->dirty, pc->valid);
+
+ /* check if GDB tells to set our PC where to continue from */
+ if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) {
+ value = target_buffer_get_u32(target, pc->value);
+ LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value);
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value));
+ }
+
+ /* Restore IRQ state if not in debug_execution*/
+ if (!debug_execution)
+ CHECK_RETVAL(arc_enable_interrupts(target, arc->irq_state));
+ else
+ CHECK_RETVAL(arc_enable_interrupts(target, !debug_execution));
+
+ target->debug_reason = DBG_REASON_NOTHALTED;
+
+ /* ready to get us going again */
+ target->state = TARGET_RUNNING;
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value));
+ value &= ~SET_CORE_HALT_BIT; /* clear the HALT bit */
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value));
+ LOG_DEBUG("Core started to run");
+
+ /* registers are now invalid */
+ register_cache_invalidate(arc->core_and_aux_cache);
+
+ if (!debug_execution) {
+ target->state = TARGET_RUNNING;
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
+ LOG_DEBUG("target resumed at 0x%08" PRIx32, resume_pc);
+ } else {
+ target->state = TARGET_DEBUG_RUNNING;
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED));
+ LOG_DEBUG("target debug resumed at 0x%08" PRIx32, resume_pc);
+ }
+
+ return ERROR_OK;
+}
+
+static int arc_init_target(struct command_context *cmd_ctx, struct target *target)
+{
+ CHECK_RETVAL(arc_build_reg_cache(target));
+ CHECK_RETVAL(arc_build_bcr_reg_cache(target));
+ target->debug_reason = DBG_REASON_DBGRQ;
+ return ERROR_OK;
+}
+
+static void arc_free_reg_cache(struct reg_cache *cache)
+{
+ free(cache->reg_list);
+ free(cache);
+}
+
+static void arc_deinit_target(struct target *target)
+{
+ struct arc_common *arc = target_to_arc(target);
+
+ LOG_DEBUG("deinitialization of target");
+ if (arc->core_aux_cache_built)
+ arc_free_reg_cache(arc->core_and_aux_cache);
+ if (arc->bcr_cache_built)
+ arc_free_reg_cache(arc->bcr_cache);
+
+ struct arc_reg_data_type *type, *n;
+ struct arc_reg_desc *desc, *k;
+
+ /* Free arc-specific reg_data_types allocations*/
+ list_for_each_entry_safe_reverse(type, n, &arc->reg_data_types, list) {
+ if (type->data_type.type_class == REG_TYPE_CLASS_STRUCT) {
+ free(type->reg_type_struct_field);
+ free(type->bitfields);
+ free(type);
+ } else if (type->data_type.type_class == REG_TYPE_CLASS_FLAGS) {
+ free(type->reg_type_flags_field);
+ free(type->bitfields);
+ free(type);
+ }
+ }
+
+ /* Free standard_gdb_types reg_data_types allocations */
+ type = list_first_entry(&arc->reg_data_types, struct arc_reg_data_type, list);
+ free(type);
+
+ list_for_each_entry_safe(desc, k, &arc->aux_reg_descriptions, list)
+ free_reg_desc(desc);
+
+ list_for_each_entry_safe(desc, k, &arc->core_reg_descriptions, list)
+ free_reg_desc(desc);
+
+ list_for_each_entry_safe(desc, k, &arc->bcr_reg_descriptions, list)
+ free_reg_desc(desc);
+
+ free(arc);
+}
+
+
+static int arc_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct arc_common *arc = calloc(1, sizeof(*arc));
+
+ if (!arc) {
+ LOG_ERROR("Unable to allocate memory");
+ return ERROR_FAIL;
+ }
+
+ LOG_DEBUG("Entering");
+ CHECK_RETVAL(arc_init_arch_info(target, arc, target->tap));
+
+ return ERROR_OK;
+}
+
+/**
+ * Write 4-byte instruction to memory. This is like target_write_u32, however
+ * in case of little endian ARC instructions are in middle endian format, not
+ * little endian, so different type of conversion should be done.
+ * Middle endinan: instruction "aabbccdd", stored as "bbaaddcc"
+ */
+int arc_write_instruction_u32(struct target *target, uint32_t address,
+ uint32_t instr)
+{
+ uint8_t value_buf[4];
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+
+ LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address,
+ instr);
+
+ if (target->endianness == TARGET_LITTLE_ENDIAN)
+ arc_h_u32_to_me(value_buf, instr);
+ else
+ h_u32_to_be(value_buf, instr);
+
+ CHECK_RETVAL(target_write_buffer(target, address, 4, value_buf));
+
+ return ERROR_OK;
+}
+
+/**
+ * Read 32-bit instruction from memory. It is like target_read_u32, however in
+ * case of little endian ARC instructions are in middle endian format, so
+ * different type of conversion should be done.
+ */
+int arc_read_instruction_u32(struct target *target, uint32_t address,
+ uint32_t *value)
+{
+ uint8_t value_buf[4];
+
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+
+ *value = 0;
+ CHECK_RETVAL(target_read_buffer(target, address, 4, value_buf));
+
+ if (target->endianness == TARGET_LITTLE_ENDIAN)
+ *value = arc_me_to_h_u32(value_buf);
+ else
+ *value = be_to_h_u32(value_buf);
+
+ LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address,
+ *value);
+
+ return ERROR_OK;
+}
+
+static int arc_set_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+
+ if (breakpoint->set) {
+ LOG_WARNING("breakpoint already set");
+ return ERROR_OK;
+ }
+
+ if (breakpoint->type == BKPT_SOFT) {
+ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
+
+ if (breakpoint->length == 4) {
+ uint32_t verify = 0xffffffff;
+
+ CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length,
+ breakpoint->orig_instr));
+
+ CHECK_RETVAL(arc_write_instruction_u32(target, breakpoint->address,
+ ARC_SDBBP_32));
+
+ CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &verify));
+
+ if (verify != ARC_SDBBP_32) {
+ LOG_ERROR("Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR
+ " - check that memory is read/writable", breakpoint->address);
+ return ERROR_FAIL;
+ }
+ } else if (breakpoint->length == 2) {
+ uint16_t verify = 0xffff;
+
+ CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length,
+ breakpoint->orig_instr));
+ CHECK_RETVAL(target_write_u16(target, breakpoint->address, ARC_SDBBP_16));
+
+ CHECK_RETVAL(target_read_u16(target, breakpoint->address, &verify));
+ if (verify != ARC_SDBBP_16) {
+ LOG_ERROR("Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR
+ " - check that memory is read/writable", breakpoint->address);
+ return ERROR_FAIL;
+ }
+ } else {
+ LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ breakpoint->set = 64; /* Any nice value but 0 */
+ } else if (breakpoint->type == BKPT_HARD) {
+ LOG_DEBUG("Hardware breakpoints are not supported yet!");
+ return ERROR_FAIL;
+ } else {
+ LOG_DEBUG("ERROR: setting unknown breakpoint type");
+ return ERROR_FAIL;
+ }
+ /* core instruction cache is now invalid,
+ * TODO: add cache invalidation function here (when implemented). */
+
+ return ERROR_OK;
+}
+
+static int arc_unset_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ int retval = ERROR_OK;
+
+ if (!breakpoint->set) {
+ LOG_WARNING("breakpoint not set");
+ return ERROR_OK;
+ }
+
+ if (breakpoint->type == BKPT_SOFT) {
+ /* restore original instruction (kept in target endianness) */
+ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
+ if (breakpoint->length == 4) {
+ uint32_t current_instr;
+
+ /* check that user program has not modified breakpoint instruction */
+ CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, ¤t_instr));
+
+ if (current_instr == ARC_SDBBP_32) {
+ retval = target_write_buffer(target, breakpoint->address,
+ breakpoint->length, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+ } else {
+ LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR
+ " has been overwritten outside of debugger."
+ "Expected: @0x%" PRIx32 ", got: @0x%" PRIx32,
+ breakpoint->address, ARC_SDBBP_32, current_instr);
+ }
+ } else if (breakpoint->length == 2) {
+ uint16_t current_instr;
+
+ /* check that user program has not modified breakpoint instruction */
+ CHECK_RETVAL(target_read_u16(target, breakpoint->address, ¤t_instr));
+ if (current_instr == ARC_SDBBP_16) {
+ retval = target_write_buffer(target, breakpoint->address,
+ breakpoint->length, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+ } else {
+ LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR
+ " has been overwritten outside of debugger. "
+ "Expected: 0x%04x, got: 0x%04" PRIx16,
+ breakpoint->address, ARC_SDBBP_16, current_instr);
+ }
+ } else {
+ LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ breakpoint->set = 0;
+
+ } else if (breakpoint->type == BKPT_HARD) {
+ LOG_WARNING("Hardware breakpoints are not supported yet!");
+ return ERROR_FAIL;
+ } else {
+ LOG_DEBUG("ERROR: unsetting unknown breakpoint type");
+ return ERROR_FAIL;
+ }
+
+ /* core instruction cache is now invalid.
+ * TODO: Add cache invalidation function */
+
+ return retval;
+}
+
+
+static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ if (target->state == TARGET_HALTED) {
+ return arc_set_breakpoint(target, breakpoint);
+
+ } else {
+ LOG_WARNING(" > core was not halted, please try again.");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+}
+
+static int arc_remove_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ if (target->state == TARGET_HALTED) {
+ if (breakpoint->set)
+ CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint));
+ } else {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ return ERROR_OK;
+}
+
+/* Helper function which swiches core to single_step mode by
+ * doing aux r/w operations. */
+int arc_config_step(struct target *target, int enable_step)
+{
+ uint32_t value;
+
+ struct arc_common *arc = target_to_arc(target);
+
+ /* enable core debug step mode */
+ if (enable_step) {
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG,
+ &value));
+ value &= ~SET_CORE_AE_BIT; /* clear the AE bit */
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG,
+ value));
+ LOG_DEBUG(" [status32:0x%08" PRIx32 "]", value);
+
+ /* Doing read-modify-write, because DEBUG might contain manually set
+ * bits like UB or ED, which should be preserved. */
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info,
+ AUX_DEBUG_REG, &value));
+ value |= SET_CORE_SINGLE_INSTR_STEP; /* set the IS bit */
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG,
+ value));
+ LOG_DEBUG("core debug step mode enabled [debug-reg:0x%08" PRIx32 "]", value);
+
+ } else { /* disable core debug step mode */
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG,
+ &value));
+ value &= ~SET_CORE_SINGLE_INSTR_STEP; /* clear the IS bit */
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG,
+ value));
+ LOG_DEBUG("core debug step mode disabled");
+ }
+
+ return ERROR_OK;
+}
+
+int arc_step(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints)
+{
+ /* get pointers to arch-specific information */
+ struct arc_common *arc = target_to_arc(target);
+ struct breakpoint *breakpoint = NULL;
+ struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* current = 1: continue on current pc, otherwise continue at */
+ if (!current) {
+ buf_set_u32(pc->value, 0, 32, address);
+ pc->dirty = 1;
+ pc->valid = 1;
+ }
+
+ LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32,
+ buf_get_u32(pc->value, 0, 32));
+
+ /* the front-end may request us not to handle breakpoints */
+ if (handle_breakpoints) {
+ breakpoint = breakpoint_find(target, buf_get_u32(pc->value, 0, 32));
+ if (breakpoint)
+ CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint));
+ }
+
+ /* restore context */
+ CHECK_RETVAL(arc_restore_context(target));
+
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
+
+ /* disable interrupts while stepping */
+ CHECK_RETVAL(arc_enable_interrupts(target, 0));
+
+ /* do a single step */
+ CHECK_RETVAL(arc_config_step(target, 1));
+
+ /* make sure we done our step */
+ alive_sleep(1);
+
+ /* registers are now invalid */
+ register_cache_invalidate(arc->core_and_aux_cache);
+
+ if (breakpoint)
+ CHECK_RETVAL(arc_set_breakpoint(target, breakpoint));
+
+ LOG_DEBUG("target stepped ");
+
+ target->state = TARGET_HALTED;
+
+ /* Saving context */
+ CHECK_RETVAL(arc_debug_entry(target));
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
+
+ return ERROR_OK;
+}
+
+
+
+/* ARC v2 target */
+struct target_type arcv2_target = {
+ .name = "arcv2",
+
+ .poll = arc_poll,
+
+ .arch_state = arc_arch_state,
+
+ /* TODO That seems like something similiar to metaware hostlink, so perhaps
+ * we can exploit this in the future. */
+ .target_request_data = NULL,
+
+ .halt = arc_halt,
+ .resume = arc_resume,
+ .step = arc_step,
+
+ .assert_reset = arc_assert_reset,
+ .deassert_reset = arc_deassert_reset,
+
+ /* TODO Implement soft_reset_halt */
+ .soft_reset_halt = NULL,
+
+ .get_gdb_reg_list = arc_get_gdb_reg_list,
+
+ .read_memory = arc_mem_read,
+ .write_memory = arc_mem_write,
+ .checksum_memory = NULL,
+ .blank_check_memory = NULL,
+
+ .add_breakpoint = arc_add_breakpoint,
+ .add_context_breakpoint = NULL,
+ .add_hybrid_breakpoint = NULL,
+ .remove_breakpoint = arc_remove_breakpoint,
+ .add_watchpoint = NULL,
+ .remove_watchpoint = NULL,
+ .hit_watchpoint = NULL,
+
+ .run_algorithm = NULL,
+ .start_algorithm = NULL,
+ .wait_algorithm = NULL,
+
+ .commands = arc_monitor_command_handlers,
+
+ .target_create = arc_target_create,
+ .init_target = arc_init_target,
+ .deinit_target = arc_deinit_target,
+ .examine = arc_examine,
+
+ .virt2phys = NULL,
+ .read_phys_memory = NULL,
+ .write_phys_memory = NULL,
+ .mmu = NULL,
+};
diff --git a/src/target/arc.h b/src/target/arc.h
new file mode 100644
index 000000000..defa3fa97
--- /dev/null
+++ b/src/target/arc.h
@@ -0,0 +1,250 @@
+/***************************************************************************
+ * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_H
+#define OPENOCD_TARGET_ARC_H
+
+#include
+#include
+
+#include "algorithm.h"
+#include "breakpoints.h"
+#include "jtag/interface.h"
+#include "register.h"
+#include "target.h"
+#include "target_request.h"
+#include "target_type.h"
+#include "helper/bits.h"
+
+#include "arc_jtag.h"
+#include "arc_cmd.h"
+#include "arc_mem.h"
+
+#define ARC_COMMON_MAGIC 0xB32EB324 /* just a unique number */
+
+#define AUX_DEBUG_REG 0x5
+#define AUX_PC_REG 0x6
+#define AUX_STATUS32_REG 0xA
+
+
+#define SET_CORE_FORCE_HALT BIT(1)
+#define SET_CORE_HALT_BIT BIT(0) /* STATUS32[0] = H field */
+#define SET_CORE_ENABLE_INTERRUPTS BIT(31)
+/* STATUS32[5] or AE bit indicates if the processor is in exception state */
+#define SET_CORE_AE_BIT BIT(5)
+/* Single instruction step bit in Debug register */
+#define SET_CORE_SINGLE_INSTR_STEP BIT(11)
+
+#define AUX_STATUS32_REG_HALT_BIT BIT(0)
+#define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */
+
+/* Reserved core registers */
+#define CORE_R61_NUM (61)
+#define CORE_R62_NUM (62)
+
+#define CORE_REG_MAX_NUMBER (63)
+
+/* Limit reg_type/reg_type_field name to 20 symbols */
+#define REG_TYPE_MAX_NAME_LENGTH 20
+
+/* ARC 32bits opcodes */
+#define ARC_SDBBP_32 0x256F003F /* BRK */
+
+/* ARC 16bits opcodes */
+#define ARC_SDBBP_16 0x7FFF /* BRK_S */
+
+struct arc_reg_bitfield {
+ struct reg_data_type_bitfield bitfield;
+ char name[REG_TYPE_MAX_NAME_LENGTH];
+};
+/* Register data type */
+struct arc_reg_data_type {
+ struct list_head list;
+ struct reg_data_type data_type;
+ struct reg_data_type_flags data_type_flags;
+ struct reg_data_type_struct data_type_struct;
+ char data_type_id[REG_TYPE_MAX_NAME_LENGTH];
+ struct arc_reg_bitfield *bitfields;
+ union {
+ struct reg_data_type_struct_field *reg_type_struct_field;
+ struct reg_data_type_flags_field *reg_type_flags_field;
+ };
+};
+
+
+
+/* Standard GDB register types */
+static const struct reg_data_type standard_gdb_types[] = {
+ { .type = REG_TYPE_INT, .id = "int" },
+ { .type = REG_TYPE_INT8, .id = "int8" },
+ { .type = REG_TYPE_INT16, .id = "int16" },
+ { .type = REG_TYPE_INT32, .id = "int32" },
+ { .type = REG_TYPE_INT64, .id = "int64" },
+ { .type = REG_TYPE_INT128, .id = "int128" },
+ { .type = REG_TYPE_UINT8, .id = "uint8" },
+ { .type = REG_TYPE_UINT16, .id = "uint16" },
+ { .type = REG_TYPE_UINT32, .id = "uint32" },
+ { .type = REG_TYPE_UINT64, .id = "uint64" },
+ { .type = REG_TYPE_UINT128, .id = "uint128" },
+ { .type = REG_TYPE_CODE_PTR, .id = "code_ptr" },
+ { .type = REG_TYPE_DATA_PTR, .id = "data_ptr" },
+ { .type = REG_TYPE_FLOAT, .id = "float" },
+ { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" },
+ { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" },
+};
+
+
+struct arc_common {
+ uint32_t common_magic;
+
+ struct arc_jtag jtag_info;
+
+ struct reg_cache *core_and_aux_cache;
+ struct reg_cache *bcr_cache;
+
+ /* Indicate if cach was built (for deinit function) */
+ bool core_aux_cache_built;
+ bool bcr_cache_built;
+ /* Closely Coupled memory(CCM) regions for performance-critical
+ * code (optional). */
+ uint32_t iccm0_start;
+ uint32_t iccm0_end;
+ uint32_t iccm1_start;
+ uint32_t iccm1_end;
+ uint32_t dccm_start;
+ uint32_t dccm_end;
+
+ int irq_state;
+
+ /* Register descriptions */
+ struct list_head reg_data_types;
+ struct list_head core_reg_descriptions;
+ struct list_head aux_reg_descriptions;
+ struct list_head bcr_reg_descriptions;
+ unsigned long num_regs;
+ unsigned long num_core_regs;
+ unsigned long num_aux_regs;
+ unsigned long num_bcr_regs;
+ unsigned long last_general_reg;
+
+ /* PC register location in register cache. */
+ unsigned long pc_index_in_cache;
+ /* DEBUG register location in register cache. */
+ unsigned long debug_index_in_cache;
+};
+
+/* Borrowed from nds32.h */
+#define CHECK_RETVAL(action) \
+ do { \
+ int __retval = (action); \
+ if (__retval != ERROR_OK) { \
+ LOG_DEBUG("error while calling \"%s\"", \
+ # action); \
+ return __retval; \
+ } \
+ } while (0)
+
+#define JIM_CHECK_RETVAL(action) \
+ do { \
+ int __retval = (action); \
+ if (__retval != JIM_OK) { \
+ LOG_DEBUG("error while calling \"%s\"", \
+ # action); \
+ return __retval; \
+ } \
+ } while (0)
+
+static inline struct arc_common *target_to_arc(struct target *target)
+{
+ return target->arch_info;
+}
+
+/* ----- Inlined functions ------------------------------------------------- */
+
+/**
+ * Convert data in host endianness to the middle endian. This is required to
+ * write 4-byte instructions.
+ */
+static inline void arc_h_u32_to_me(uint8_t *buf, int val)
+{
+ buf[1] = (uint8_t) (val >> 24);
+ buf[0] = (uint8_t) (val >> 16);
+ buf[3] = (uint8_t) (val >> 8);
+ buf[2] = (uint8_t) (val >> 0);
+}
+
+/**
+ * Convert data in middle endian to host endian. This is required to read 32-bit
+ * instruction from little endian ARCs.
+ */
+static inline uint32_t arc_me_to_h_u32(const uint8_t *buf)
+{
+ return (uint32_t)(buf[2] | buf[3] << 8 | buf[0] << 16 | buf[1] << 24);
+}
+
+
+/* ARC Register description */
+struct arc_reg_desc {
+
+ struct target *target;
+
+ /* Register name */
+ char *name;
+
+ /* Actual place of storing reg_value */
+ uint8_t reg_value[4];
+
+ /* Actual place of storing register feature */
+ struct reg_feature feature;
+
+ /* GDB XML feature */
+ char *gdb_xml_feature;
+
+ /* Is this a register in g/G-packet? */
+ bool is_general;
+
+ /* Architectural number: core reg num or AUX reg num */
+ uint32_t arch_num;
+
+ /* Core or AUX register? */
+ bool is_core;
+
+ /* Build configuration register? */
+ bool is_bcr;
+
+ /* Data type */
+ struct reg_data_type *data_type;
+
+ struct list_head list;
+};
+
+/* Error codes */
+#define ERROR_ARC_REGISTER_NOT_FOUND (-700)
+#define ERROR_ARC_REGISTER_FIELD_NOT_FOUND (-701)
+#define ERROR_ARC_REGISTER_IS_NOT_STRUCT (-702)
+#define ERROR_ARC_FIELD_IS_NOT_BITFIELD (-703)
+#define ERROR_ARC_REGTYPE_NOT_FOUND (-704)
+
+void free_reg_desc(struct arc_reg_desc *r);
+
+
+void arc_reg_data_type_add(struct target *target,
+ struct arc_reg_data_type *data_type);
+
+int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg,
+ const char * const type_name, const size_t type_name_len);
+
+struct reg *arc_reg_get_by_name(struct reg_cache *first,
+ const char *name, bool search_all);
+
+int arc_reg_get_field(struct target *target, const char *reg_name,
+ const char *field_name, uint32_t *value_ptr);
+
+#endif /* OPENOCD_TARGET_ARC_H */
diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c
new file mode 100644
index 000000000..fad8ca947
--- /dev/null
+++ b/src/target/arc_cmd.c
@@ -0,0 +1,982 @@
+/***************************************************************************
+ * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/* --------------------------------------------------------------------------
+ *
+ * ARC targets expose command interface.
+ * It can be accessed via GDB through the (gdb) monitor command.
+ *
+ * ------------------------------------------------------------------------- */
+
+
+static int arc_cmd_jim_get_uint32(Jim_GetOptInfo *goi, uint32_t *value)
+{
+ jim_wide value_wide;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Wide(goi, &value_wide));
+ *value = (uint32_t)value_wide;
+ return JIM_OK;
+}
+
+enum add_reg_types {
+ CFG_ADD_REG_TYPE_FLAG,
+ CFG_ADD_REG_TYPE_STRUCT,
+};
+/* Add flags register data type */
+enum add_reg_type_flags {
+ CFG_ADD_REG_TYPE_FLAGS_NAME,
+ CFG_ADD_REG_TYPE_FLAGS_FLAG,
+};
+
+static Jim_Nvp nvp_add_reg_type_flags_opts[] = {
+ { .name = "-name", .value = CFG_ADD_REG_TYPE_FLAGS_NAME },
+ { .name = "-flag", .value = CFG_ADD_REG_TYPE_FLAGS_FLAG },
+ { .name = NULL, .value = -1 }
+};
+
+/* Helper function to check if all field required for register
+ * are set up */
+static const char *validate_register(const struct arc_reg_desc * const reg, bool arch_num_set)
+{
+ /* Check that required fields are set */
+ if (!reg->name)
+ return "-name option is required";
+ if (!reg->gdb_xml_feature)
+ return "-feature option is required";
+ if (!arch_num_set)
+ return "-num option is required";
+ if (reg->is_bcr && reg->is_core)
+ return "Register cannot be both -core and -bcr.";
+ return NULL;
+}
+
+/* Helper function to read the name of register type or register from
+ * configure files */
+static int jim_arc_read_reg_name_field(Jim_GetOptInfo *goi,
+ const char **name, int *name_len)
+{
+ int e = JIM_OK;
+
+ if (!goi->argc) {
+ Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-name ...");
+ return JIM_ERR;
+ }
+ e = Jim_GetOpt_String(goi, name, name_len);
+ return e;
+}
+
+/* Helper function to read bitfields/flags of register type. */
+static int jim_arc_read_reg_type_field(Jim_GetOptInfo *goi, const char **field_name, int *field_name_len,
+ struct arc_reg_bitfield *bitfields, int cur_field, int type)
+{
+ jim_wide start_pos, end_pos;
+
+ int e = JIM_OK;
+ if ((type == CFG_ADD_REG_TYPE_STRUCT && goi->argc < 3) ||
+ (type == CFG_ADD_REG_TYPE_FLAG && goi->argc < 2)) {
+ Jim_SetResultFormatted(goi->interp, "Not enough argmunets after -flag/-bitfield");
+ return JIM_ERR;
+ }
+
+ e = Jim_GetOpt_String(goi, field_name, field_name_len);
+ if (e != JIM_OK)
+ return e;
+
+ /* read start position of bitfield/flag */
+ e = Jim_GetOpt_Wide(goi, &start_pos);
+ if (e != JIM_OK)
+ return e;
+
+ end_pos = start_pos;
+
+ /* Check if any argnuments remain,
+ * set bitfields[cur_field].end if flag is multibit */
+ if (goi->argc > 0)
+ /* Check current argv[0], if it is equal to "-flag",
+ * than bitfields[cur_field].end remains start */
+ if ((strcmp(Jim_String(goi->argv[0]), "-flag") && type == CFG_ADD_REG_TYPE_FLAG)
+ || (type == CFG_ADD_REG_TYPE_STRUCT)) {
+ e = Jim_GetOpt_Wide(goi, &end_pos);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi->interp, "Error reading end position");
+ return e;
+ }
+ }
+
+ bitfields[cur_field].bitfield.start = start_pos;
+ bitfields[cur_field].bitfield.end = end_pos;
+ if ((end_pos != start_pos) || (type == CFG_ADD_REG_TYPE_STRUCT))
+ bitfields[cur_field].bitfield.type = REG_TYPE_INT;
+ return e;
+}
+
+static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc,
+ Jim_Obj * const *argv)
+{
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ LOG_DEBUG("-");
+
+ struct command_context *ctx;
+ struct target *target;
+
+ ctx = current_command_context(interp);
+ assert(ctx);
+ target = get_current_target(ctx);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ int e = JIM_OK;
+
+ /* Check if the amount of argnuments is not zero */
+ if (goi.argc <= 0) {
+ Jim_SetResultFormatted(goi.interp, "The command has no argnuments");
+ return JIM_ERR;
+ }
+
+ /* Estimate number of registers as (argc - 2)/3 as each -flag option has 2
+ * arguments while -name is required. */
+ unsigned int fields_sz = (goi.argc - 2) / 3;
+ unsigned int cur_field = 0;
+
+ /* Tha maximum amount of bitfilds is 32 */
+ if (fields_sz > 32) {
+ Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32");
+ return JIM_ERR;
+ }
+
+ struct arc_reg_data_type *type = calloc(1, sizeof(*type));
+ struct reg_data_type_flags *flags = &type->data_type_flags;
+ struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields));
+ type->reg_type_flags_field = fields;
+ struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields));
+ if (!(type && fields && bitfields)) {
+ Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
+ goto fail;
+ }
+
+ /* Initialize type */
+ type->bitfields = bitfields;
+ type->data_type.id = type->data_type_id;
+ type->data_type.type = REG_TYPE_ARCH_DEFINED;
+ type->data_type.type_class = REG_TYPE_CLASS_FLAGS;
+ type->data_type.reg_type_flags = flags;
+ flags->size = 4; /* For now ARC has only 32-bit registers */
+
+ while (goi.argc > 0 && e == JIM_OK) {
+ Jim_Nvp *n;
+ e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_flags_opts, &n);
+ if (e != JIM_OK) {
+ Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_flags_opts, 0);
+ continue;
+ }
+
+ switch (n->value) {
+ case CFG_ADD_REG_TYPE_FLAGS_NAME:
+ {
+ const char *name = NULL;
+ int name_len = 0;
+
+ e = jim_arc_read_reg_name_field(&goi, &name, &name_len);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to read reg name.");
+ goto fail;
+ }
+
+ if (name_len > REG_TYPE_MAX_NAME_LENGTH) {
+ Jim_SetResultFormatted(goi.interp, "Reg type name is too big.");
+ goto fail;
+ }
+
+ strncpy((void *)type->data_type.id, name, name_len);
+ if (!type->data_type.id) {
+ Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name.");
+ goto fail;
+ }
+
+ break;
+ }
+
+ case CFG_ADD_REG_TYPE_FLAGS_FLAG:
+ {
+ const char *field_name = NULL;
+ int field_name_len = 0;
+
+ e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields,
+ cur_field, CFG_ADD_REG_TYPE_FLAG);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_flag field.");
+ goto fail;
+ }
+
+ if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) {
+ Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big.");
+ goto fail;
+ }
+
+ fields[cur_field].name = bitfields[cur_field].name;
+ strncpy(bitfields[cur_field].name, field_name, field_name_len);
+ if (!fields[cur_field].name) {
+ Jim_SetResultFormatted(goi.interp, "Unable to setup field name. ");
+ goto fail;
+ }
+
+ fields[cur_field].bitfield = &(bitfields[cur_field].bitfield);
+ if (cur_field > 0)
+ fields[cur_field - 1].next = &(fields[cur_field]);
+ else
+ flags->fields = fields;
+
+ cur_field += 1;
+ break;
+ }
+ }
+ }
+
+ if (!type->data_type.id) {
+ Jim_SetResultFormatted(goi.interp, "-name is a required option");
+ goto fail;
+ }
+
+ arc_reg_data_type_add(target, type);
+
+ LOG_DEBUG("added flags type {name=%s}", type->data_type.id);
+
+ return JIM_OK;
+fail:
+ free(type);
+ free(fields);
+ free(bitfields);
+
+ return JIM_ERR;
+}
+
+/* Add struct register data type */
+enum add_reg_type_struct {
+ CFG_ADD_REG_TYPE_STRUCT_NAME,
+ CFG_ADD_REG_TYPE_STRUCT_BITFIELD,
+};
+
+static Jim_Nvp nvp_add_reg_type_struct_opts[] = {
+ { .name = "-name", .value = CFG_ADD_REG_TYPE_STRUCT_NAME },
+ { .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD },
+ { .name = NULL, .value = -1 }
+};
+
+static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+
+ struct command_context *context;
+ struct target *target;
+ uint32_t regnum;
+ uint32_t value;
+
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ if (goi.argc != 2) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s ", Jim_GetString(argv[0], NULL));
+ return JIM_ERR;
+ }
+
+ context = current_command_context(interp);
+ assert(context);
+
+ target = get_current_target(context);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ /* Register number */
+ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num));
+
+ /* Register value */
+ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value));
+
+ struct arc_common *arc = target_to_arc(target);
+ assert(arc);
+
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, regnum, value));
+
+ return ERROR_OK;
+}
+
+static int jim_arc_get_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+ struct command_context *context;
+ struct target *target;
+ uint32_t regnum;
+ uint32_t value;
+
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ if (goi.argc != 1) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s ", Jim_GetString(argv[0], NULL));
+ return JIM_ERR;
+ }
+
+ context = current_command_context(interp);
+ assert(context);
+
+ target = get_current_target(context);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ /* Register number */
+ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num));
+
+ struct arc_common *arc = target_to_arc(target);
+ assert(arc);
+
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value));
+ Jim_SetResultInt(interp, value);
+
+ return ERROR_OK;
+}
+
+static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+ struct command_context *context;
+ struct target *target;
+ uint32_t regnum;
+ uint32_t value;
+
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ if (goi.argc != 1) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s ", Jim_GetString(argv[0], NULL));
+ return JIM_ERR;
+ }
+
+ context = current_command_context(interp);
+ assert(context);
+
+ target = get_current_target(context);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ /* Register number */
+ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num));
+ if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
+ Jim_SetResultFormatted(goi.interp, "Core register number %i "
+ "is invalid. Must less then 64 and not 61 and 62.", regnum);
+ return JIM_ERR;
+ }
+
+ struct arc_common *arc = target_to_arc(target);
+ assert(arc);
+
+ /* Read value */
+ CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value));
+ Jim_SetResultInt(interp, value);
+
+ return ERROR_OK;
+}
+
+static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+ struct command_context *context;
+ struct target *target;
+ uint32_t regnum;
+ uint32_t value;
+
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ if (goi.argc != 2) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s ", Jim_GetString(argv[0], NULL));
+ return JIM_ERR;
+ }
+
+ context = current_command_context(interp);
+ assert(context);
+
+ target = get_current_target(context);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ /* Register number */
+ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num));
+ if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
+ Jim_SetResultFormatted(goi.interp, "Core register number %i "
+ "is invalid. Must less then 64 and not 61 and 62.", regnum);
+ return JIM_ERR;
+ }
+
+ /* Register value */
+ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value));
+
+ struct arc_common *arc = target_to_arc(target);
+ assert(arc);
+
+ CHECK_RETVAL(arc_jtag_write_core_reg_one(&arc->jtag_info, regnum, value));
+
+ return ERROR_OK;
+}
+
+static const struct command_registration arc_jtag_command_group[] = {
+ {
+ .name = "get-aux-reg",
+ .jim_handler = jim_arc_get_aux_reg,
+ .mode = COMMAND_EXEC,
+ .help = "Get AUX register by number. This command does a "
+ "raw JTAG request that bypasses OpenOCD register cache "
+ "and thus is unsafe and can have unexpected consequences. "
+ "Use at your own risk.",
+ .usage = "arc jtag get-aux-reg "
+ },
+ {
+ .name = "set-aux-reg",
+ .jim_handler = jim_arc_set_aux_reg,
+ .mode = COMMAND_EXEC,
+ .help = "Set AUX register by number. This command does a "
+ "raw JTAG request that bypasses OpenOCD register cache "
+ "and thus is unsafe and can have unexpected consequences. "
+ "Use at your own risk.",
+ .usage = "arc jtag set-aux-reg "
+ },
+ {
+ .name = "get-core-reg",
+ .jim_handler = jim_arc_get_core_reg,
+ .mode = COMMAND_EXEC,
+ .help = "Get/Set core register by number. This command does a "
+ "raw JTAG request that bypasses OpenOCD register cache "
+ "and thus is unsafe and can have unexpected consequences. "
+ "Use at your own risk.",
+ .usage = "arc jtag get-core-reg []"
+ },
+ {
+ .name = "set-core-reg",
+ .jim_handler = jim_arc_set_core_reg,
+ .mode = COMMAND_EXEC,
+ .help = "Get/Set core register by number. This command does a "
+ "raw JTAG request that bypasses OpenOCD register cache "
+ "and thus is unsafe and can have unexpected consequences. "
+ "Use at your own risk.",
+ .usage = "arc jtag set-core-reg []"
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+
+/* This function supports only bitfields. */
+static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc,
+ Jim_Obj * const *argv)
+{
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ LOG_DEBUG("-");
+
+ struct command_context *ctx;
+ struct target *target;
+
+ ctx = current_command_context(interp);
+ assert(ctx);
+ target = get_current_target(ctx);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ int e = JIM_OK;
+
+ /* Check if the amount of argnuments is not zero */
+ if (goi.argc <= 0) {
+ Jim_SetResultFormatted(goi.interp, "The command has no argnuments");
+ return JIM_ERR;
+ }
+
+ /* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3
+ * arguments while -name is required. */
+ unsigned int fields_sz = (goi.argc - 2) / 4;
+ unsigned int cur_field = 0;
+
+ /* Tha maximum amount of bitfilds is 32 */
+ if (fields_sz > 32) {
+ Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32");
+ return JIM_ERR;
+ }
+
+ struct arc_reg_data_type *type = calloc(1, sizeof(*type));
+ struct reg_data_type_struct *struct_type = &type->data_type_struct;
+ struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields));
+ type->reg_type_struct_field = fields;
+ struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields));
+ if (!(type && fields && bitfields)) {
+ Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
+ goto fail;
+ }
+
+ /* Initialize type */
+ type->data_type.id = type->data_type_id;
+ type->bitfields = bitfields;
+ type->data_type.type = REG_TYPE_ARCH_DEFINED;
+ type->data_type.type_class = REG_TYPE_CLASS_STRUCT;
+ type->data_type.reg_type_struct = struct_type;
+ struct_type->size = 4; /* For now ARC has only 32-bit registers */
+
+ while (goi.argc > 0 && e == JIM_OK) {
+ Jim_Nvp *n;
+ e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_struct_opts, &n);
+ if (e != JIM_OK) {
+ Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_struct_opts, 0);
+ continue;
+ }
+
+ switch (n->value) {
+ case CFG_ADD_REG_TYPE_STRUCT_NAME:
+ {
+ const char *name = NULL;
+ int name_len = 0;
+
+ e = jim_arc_read_reg_name_field(&goi, &name, &name_len);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to read reg name.");
+ goto fail;
+ }
+
+ if (name_len > REG_TYPE_MAX_NAME_LENGTH) {
+ Jim_SetResultFormatted(goi.interp, "Reg type name is too big.");
+ goto fail;
+ }
+
+ strncpy((void *)type->data_type.id, name, name_len);
+ if (!type->data_type.id) {
+ Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name.");
+ goto fail;
+ }
+
+ break;
+ }
+ case CFG_ADD_REG_TYPE_STRUCT_BITFIELD:
+ {
+ const char *field_name = NULL;
+ int field_name_len = 0;
+ e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields,
+ cur_field, CFG_ADD_REG_TYPE_STRUCT);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_struct field.");
+ goto fail;
+ }
+
+ if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) {
+ Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big.");
+ goto fail;
+ }
+
+ fields[cur_field].name = bitfields[cur_field].name;
+ strncpy(bitfields[cur_field].name, field_name, field_name_len);
+ if (!fields[cur_field].name) {
+ Jim_SetResultFormatted(goi.interp, "Unable to setup field name. ");
+ goto fail;
+ }
+
+ fields[cur_field].bitfield = &(bitfields[cur_field].bitfield);
+ fields[cur_field].use_bitfields = true;
+ if (cur_field > 0)
+ fields[cur_field - 1].next = &(fields[cur_field]);
+ else
+ struct_type->fields = fields;
+
+ cur_field += 1;
+
+ break;
+ }
+ }
+ }
+
+ if (!type->data_type.id) {
+ Jim_SetResultFormatted(goi.interp, "-name is a required option");
+ goto fail;
+ }
+
+ arc_reg_data_type_add(target, type);
+ LOG_DEBUG("added struct type {name=%s}", type->data_type.id);
+ return JIM_OK;
+
+fail:
+ free(type);
+ free(fields);
+ free(bitfields);
+
+ return JIM_ERR;
+}
+
+/* Add register */
+enum opts_add_reg {
+ CFG_ADD_REG_NAME,
+ CFG_ADD_REG_ARCH_NUM,
+ CFG_ADD_REG_IS_CORE,
+ CFG_ADD_REG_IS_BCR,
+ CFG_ADD_REG_GDB_FEATURE,
+ CFG_ADD_REG_TYPE,
+ CFG_ADD_REG_GENERAL,
+};
+
+static Jim_Nvp opts_nvp_add_reg[] = {
+ { .name = "-name", .value = CFG_ADD_REG_NAME },
+ { .name = "-num", .value = CFG_ADD_REG_ARCH_NUM },
+ { .name = "-core", .value = CFG_ADD_REG_IS_CORE },
+ { .name = "-bcr", .value = CFG_ADD_REG_IS_BCR },
+ { .name = "-feature", .value = CFG_ADD_REG_GDB_FEATURE },
+ { .name = "-type", .value = CFG_ADD_REG_TYPE },
+ { .name = "-g", .value = CFG_ADD_REG_GENERAL },
+ { .name = NULL, .value = -1 }
+};
+
+void free_reg_desc(struct arc_reg_desc *r)
+{
+ free(r->name);
+ free(r->gdb_xml_feature);
+ free(r);
+}
+
+static int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+ Jim_GetOptInfo goi;
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ struct arc_reg_desc *reg = calloc(1, sizeof(*reg));
+ if (!reg) {
+ Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
+ return JIM_ERR;
+ }
+
+ /* There is no architecture number that we could treat as invalid, so
+ * separate variable requried to ensure that arch num has been set. */
+ bool arch_num_set = false;
+ const char *type_name = "int"; /* Default type */
+ int type_name_len = strlen(type_name);
+ int e = ERROR_OK;
+
+ /* At least we need to specify 4 parameters: name, number and gdb_feature,
+ * which means there should be 6 arguments. Also there can be additional paramters
+ * "-type ", "-g" and "-core" or "-bcr" which makes maximum 10 parameters. */
+ if (goi.argc < 6 || goi.argc > 10) {
+ free_reg_desc(reg);
+ Jim_SetResultFormatted(goi.interp,
+ "Should be at least 6 argnuments and not greater than 10: "
+ " -name -num -feature "
+ " [-type ] [-core|-bcr] [-g].");
+ return JIM_ERR;
+ }
+
+ /* Parse options. */
+ while (goi.argc > 0) {
+ Jim_Nvp *n;
+ e = Jim_GetOpt_Nvp(&goi, opts_nvp_add_reg, &n);
+ if (e != JIM_OK) {
+ Jim_GetOpt_NvpUnknown(&goi, opts_nvp_add_reg, 0);
+ free_reg_desc(reg);
+ return e;
+ }
+
+ switch (n->value) {
+ case CFG_ADD_REG_NAME:
+ {
+ const char *reg_name = NULL;
+ int reg_name_len = 0;
+
+ e = jim_arc_read_reg_name_field(&goi, ®_name, ®_name_len);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to read register name.");
+ free_reg_desc(reg);
+ return e;
+ }
+
+ reg->name = strndup(reg_name, reg_name_len);
+ break;
+ }
+ case CFG_ADD_REG_IS_CORE:
+ reg->is_core = true;
+ break;
+ case CFG_ADD_REG_IS_BCR:
+ reg->is_bcr = true;
+ break;
+ case CFG_ADD_REG_ARCH_NUM:
+ {
+ jim_wide archnum;
+
+ if (!goi.argc) {
+ free_reg_desc(reg);
+ Jim_WrongNumArgs(interp, goi.argc, goi.argv, "-num ...");
+ return JIM_ERR;
+ }
+
+ e = Jim_GetOpt_Wide(&goi, &archnum);
+ if (e != JIM_OK) {
+ free_reg_desc(reg);
+ return e;
+ }
+
+ reg->arch_num = archnum;
+ arch_num_set = true;
+ break;
+ }
+ case CFG_ADD_REG_GDB_FEATURE:
+ {
+ const char *feature = NULL;
+ int feature_len = 0;
+
+ e = jim_arc_read_reg_name_field(&goi, &feature, &feature_len);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to read gdb_feature.");
+ free_reg_desc(reg);
+ return e;
+ }
+
+ reg->gdb_xml_feature = strndup(feature, feature_len);
+ break;
+ }
+ case CFG_ADD_REG_TYPE:
+ e = jim_arc_read_reg_name_field(&goi, &type_name, &type_name_len);
+ if (e != JIM_OK) {
+ Jim_SetResultFormatted(goi.interp, "Unable to read register type.");
+ free_reg_desc(reg);
+ return e;
+ }
+
+ break;
+ case CFG_ADD_REG_GENERAL:
+ reg->is_general = true;
+ break;
+ default:
+ LOG_DEBUG("Error: Unknown parameter");
+ free_reg_desc(reg);
+ return JIM_ERR;
+ }
+ }
+
+ /* Check that required fields are set */
+ const char * const errmsg = validate_register(reg, arch_num_set);
+ if (errmsg) {
+ Jim_SetResultFormatted(goi.interp, errmsg);
+ free_reg_desc(reg);
+ return JIM_ERR;
+ }
+
+ /* Add new register */
+ struct command_context *ctx;
+ struct target *target;
+
+ ctx = current_command_context(interp);
+ assert(ctx);
+ target = get_current_target(ctx);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ free_reg_desc(reg);
+ return JIM_ERR;
+ }
+
+ reg->target = target;
+
+ e = arc_reg_add(target, reg, type_name, type_name_len);
+ if (e == ERROR_ARC_REGTYPE_NOT_FOUND) {
+ Jim_SetResultFormatted(goi.interp,
+ "Cannot find type `%s' for register `%s'.",
+ type_name, reg->name);
+ free_reg_desc(reg);
+ return JIM_ERR;
+ }
+
+ return e;
+}
+
+/* arc set-reg-exists ($reg_name)+
+ * Accepts any amount of register names - will set them as existing in a loop.*/
+COMMAND_HANDLER(arc_set_reg_exists)
+{
+ struct target * const target = get_current_target(CMD_CTX);
+ if (!target) {
+ command_print(CMD, "Unable to get current target.");
+ return JIM_ERR;
+ }
+
+ if (!CMD_ARGC) {
+ command_print(CMD, "At least one register name must be specified.");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ for (unsigned int i = 0; i < CMD_ARGC; i++) {
+ const char * const reg_name = CMD_ARGV[i];
+ struct reg * const r = arc_reg_get_by_name(target->reg_cache, reg_name, true);
+
+ if (!r) {
+ command_print(CMD, "Register `%s' is not found.", reg_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ r->exist = true;
+ }
+
+ return JIM_OK;
+}
+
+/* arc reg-field ($reg_name) ($reg_field)
+ * Reads struct type register field */
+static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+ Jim_GetOptInfo goi;
+ const char *reg_name, *field_name;
+ uint32_t value;
+ int retval;
+
+ JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+ LOG_DEBUG("Reading register field");
+ if (goi.argc != 2) {
+ if (!goi.argc)
+ Jim_WrongNumArgs(interp, goi.argc, goi.argv, " ");
+ else if (goi.argc == 1)
+ Jim_WrongNumArgs(interp, goi.argc, goi.argv, "");
+ else
+ Jim_WrongNumArgs(interp, goi.argc, goi.argv, " ");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, ®_name, NULL));
+ JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, &field_name, NULL));
+ assert(reg_name);
+ assert(field_name);
+
+ struct command_context * const ctx = current_command_context(interp);
+ assert(ctx);
+ struct target * const target = get_current_target(ctx);
+ if (!target) {
+ Jim_SetResultFormatted(goi.interp, "No current target");
+ return JIM_ERR;
+ }
+
+ retval = arc_reg_get_field(target, reg_name, field_name, &value);
+
+ switch (retval) {
+ case ERROR_OK:
+ break;
+ case ERROR_ARC_REGISTER_NOT_FOUND:
+ Jim_SetResultFormatted(goi.interp,
+ "Register `%s' has not been found.", reg_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ case ERROR_ARC_REGISTER_IS_NOT_STRUCT:
+ Jim_SetResultFormatted(goi.interp,
+ "Register `%s' must have 'struct' type.", reg_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ case ERROR_ARC_REGISTER_FIELD_NOT_FOUND:
+ Jim_SetResultFormatted(goi.interp,
+ "Field `%s' has not been found in register `%s'.",
+ field_name, reg_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ case ERROR_ARC_FIELD_IS_NOT_BITFIELD:
+ Jim_SetResultFormatted(goi.interp,
+ "Field `%s' is not a 'bitfield' field in a structure.",
+ field_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ default:
+ /* Pass through other errors. */
+ return retval;
+ }
+
+ Jim_SetResultInt(interp, value);
+
+ return JIM_OK;
+}
+
+/* ----- Exported target commands ------------------------------------------ */
+
+static const struct command_registration arc_core_command_handlers[] = {
+{
+ .name = "add-reg-type-flags",
+ .jim_handler = jim_arc_add_reg_type_flags,
+ .mode = COMMAND_CONFIG,
+ .usage = "arc ardd-reg-type-flags -name -flag "
+ "[-flag ]...",
+ .help = "Add new 'flags' register data type. Only single bit flags "
+ "are supported. Type name is global. Bitsize of register is fixed "
+ "at 32 bits.",
+ },
+ {
+ .name = "add-reg-type-struct",
+ .jim_handler = jim_arc_add_reg_type_struct,
+ .mode = COMMAND_CONFIG,
+ .usage = "arc add-reg-type-struct -name -bitfield "
+ "[-bitfield ]...",
+ .help = "Add new 'struct' register data type. Only bit-fields are "
+ "supported so far, which means that for each bitfield start and end "
+ "position bits must be specified. GDB also support type-fields, "
+ "where common type can be used instead. Type name is global. Bitsize of "
+ "register is fixed at 32 bits.",
+ },
+ {
+ .name = "add-reg",
+ .jim_handler = jim_arc_add_reg,
+ .mode = COMMAND_CONFIG,
+ .usage = "arc add-reg -name -num -feature [-gdbnum ] "
+ "[-core|-bcr] [-type ] [-g]",
+ .help = "Add new register. Name, architectural number and feature name "
+ "are requried options. GDB regnum will default to previous register "
+ "(gdbnum + 1) and shouldn't be specified in most cases. Type "
+ "defaults to default GDB 'int'.",
+ },
+ {
+ .name = "set-reg-exists",
+ .handler = arc_set_reg_exists,
+ .mode = COMMAND_ANY,
+ .usage = "arc set-reg-exists []...",
+ .help = "Set that register exists. Accepts multiple register names as "
+ "arguments.",
+ },
+ {
+ .name = "get-reg-field",
+ .jim_handler = jim_arc_get_reg_field,
+ .mode = COMMAND_ANY,
+ .usage = "arc get-reg-field ",
+ .help = "Returns value of field in a register with 'struct' type.",
+ },
+ {
+ .name = "jtag",
+ .mode = COMMAND_ANY,
+ .help = "ARC JTAG specific commands",
+ .usage = "",
+ .chain = arc_jtag_command_group,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration arc_monitor_command_handlers[] = {
+ {
+ .name = "arc",
+ .mode = COMMAND_ANY,
+ .help = "ARC monitor command group",
+ .usage = "Help info ...",
+ .chain = arc_core_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/arc_cmd.h b/src/target/arc_cmd.h
new file mode 100644
index 000000000..b2264eb94
--- /dev/null
+++ b/src/target/arc_cmd.h
@@ -0,0 +1,16 @@
+/***************************************************************************
+ * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_CMD_H
+#define OPENOCD_TARGET_ARC_CMD_H
+
+extern const struct command_registration arc_monitor_command_handlers[];
+
+#endif /* OPENOCD_TARGET_ARC_CMD_H */
diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c
new file mode 100644
index 000000000..e85167a6f
--- /dev/null
+++ b/src/target/arc_jtag.c
@@ -0,0 +1,541 @@
+/***************************************************************************
+ * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/*
+ * This functions sets instruction register in TAP. TAP end state is always
+ * IRPAUSE.
+ *
+ * @param jtag_info
+ * @param new_instr Instruction to write to instruction register.
+ */
+static void arc_jtag_enque_write_ir(struct arc_jtag *jtag_info, uint32_t
+ new_instr)
+{
+ uint32_t current_instr;
+ struct jtag_tap *tap;
+ uint8_t instr_buffer[sizeof(uint32_t)] = {0};
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ tap = jtag_info->tap;
+
+ /* Do not set instruction if it is the same as current. */
+ current_instr = buf_get_u32(tap->cur_instr, 0, tap->ir_length);
+ if (current_instr == new_instr)
+ return;
+
+ struct scan_field field = {
+ .num_bits = tap->ir_length,
+ .out_value = instr_buffer
+ };
+ buf_set_u32(instr_buffer, 0, field.num_bits, new_instr);
+
+ /* From code in src/jtag/drivers/driver.c it look like that fields are
+ * copied so it is OK that field in this function is allocated in stack and
+ * thus this memory will be repurposed before jtag_execute_queue() will be
+ * invoked. */
+ jtag_add_ir_scan(tap, &field, TAP_IRPAUSE);
+}
+
+/**
+ * Read 4-byte word from data register.
+ *
+ * Unlike arc_jtag_write_data, this function returns byte-buffer, caller must
+ * convert this data to required format himself. This is done, because it is
+ * impossible to convert data before jtag_execute_queue() is invoked, so it
+ * cannot be done inside this function, so it has to operate with
+ * byte-buffers. Write function on the other hand can "write-and-forget", data
+ * is converted to byte-buffer before jtag_execute_queue().
+ *
+ * @param jtag_info
+ * @param data Array of bytes to read into.
+ * @param end_state End state after reading.
+ */
+static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data,
+ tap_state_t end_state)
+{
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ struct scan_field field = {
+ .num_bits = 32,
+ .in_value = data
+ };
+
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
+}
+
+/**
+ * Write 4-byte word to data register.
+ *
+ * @param jtag_info
+ * @param data 4-byte word to write into data register.
+ * @param end_state End state after writing.
+ */
+static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data,
+ tap_state_t end_state)
+{
+ uint8_t out_value[sizeof(uint32_t)] = {0};
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ buf_set_u32(out_value, 0, 32, data);
+
+ struct scan_field field = {
+ .num_bits = 32,
+ .out_value = out_value
+ };
+
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
+}
+
+
+/**
+ * Set transaction in command register. This function sets instruction register
+ * and then transaction register, there is no need to invoke write_ir before
+ * invoking this function.
+ *
+ * @param jtag_info
+ * @param new_trans Transaction to write to transaction command register.
+ * @param end_state End state after writing.
+ */
+static void arc_jtag_enque_set_transaction(struct arc_jtag *jtag_info,
+ uint32_t new_trans, tap_state_t end_state)
+{
+ uint8_t out_value[sizeof(uint32_t)] = {0};
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ /* No need to do anything. */
+ if (jtag_info->cur_trans == new_trans)
+ return;
+
+ /* Set instruction. We used to call write_ir at upper levels, however
+ * write_ir-write_transaction were constantly in pair, so to avoid code
+ * duplication this function does it self. For this reasons it is "set"
+ * instead of "write". */
+ arc_jtag_enque_write_ir(jtag_info, ARC_TRANSACTION_CMD_REG);
+ buf_set_u32(out_value, 0, ARC_TRANSACTION_CMD_REG_LENGTH, new_trans);
+ struct scan_field field = {
+ .num_bits = ARC_TRANSACTION_CMD_REG_LENGTH,
+ .out_value = out_value
+ };
+
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
+ jtag_info->cur_trans = new_trans;
+}
+
+/**
+ * Run reset through transaction set. None of the previous
+ * settings/commands/etc. are used anymore (or no influence).
+ */
+static void arc_jtag_enque_reset_transaction(struct arc_jtag *jtag_info)
+{
+ arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_CMD_NOP, TAP_IDLE);
+}
+
+static void arc_jtag_enque_status_read(struct arc_jtag * const jtag_info,
+ uint8_t * const buffer)
+{
+ assert(jtag_info);
+ assert(jtag_info->tap);
+ assert(buffer);
+
+ /* first writin code(0x8) of jtag status register in IR */
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_STATUS_REG);
+ /* Now reading dr performs jtag status register read */
+ arc_jtag_enque_read_dr(jtag_info, buffer, TAP_IDLE);
+}
+
+/* ----- Exported JTAG functions ------------------------------------------- */
+
+int arc_jtag_startup(struct arc_jtag *jtag_info)
+{
+ assert(jtag_info);
+
+ arc_jtag_enque_reset_transaction(jtag_info);
+
+ return jtag_execute_queue();
+}
+
+/** Read STATUS register. */
+int arc_jtag_status(struct arc_jtag * const jtag_info, uint32_t * const value)
+{
+ uint8_t buffer[sizeof(uint32_t)];
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ /* Fill command queue. */
+ arc_jtag_enque_reset_transaction(jtag_info);
+ arc_jtag_enque_status_read(jtag_info, buffer);
+ arc_jtag_enque_reset_transaction(jtag_info);
+
+ /* Execute queue. */
+ CHECK_RETVAL(jtag_execute_queue());
+
+ /* Parse output. */
+ *value = buf_get_u32(buffer, 0, 32);
+
+ return ERROR_OK;
+}
+/* Helper function: Adding read/write register operation to queue */
+static void arc_jtag_enque_register_rw(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint8_t *read_buffer, const uint32_t *write_buffer, uint32_t count)
+{
+ uint32_t i;
+
+ for (i = 0; i < count; i++) {
+ /* ARC jtag has optimization which is to increment ADDRESS_REG performing
+ * each transaction. Making sequential reads/writes we can set address for
+ * only first register in sequence, and than do read/write in cycle. */
+ if (i == 0 || (addr[i] != addr[i-1] + 1)) {
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
+ /* Going to TAP_IDLE state we initiate jtag transaction.
+ * Reading data we must go to TAP_IDLE, because further
+ * the data would be read. In case of write we go to TAP_DRPAUSE,
+ * because we need to write data to Data register first. */
+ if (write_buffer)
+ arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_DRPAUSE);
+ else
+ arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_IDLE);
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
+ }
+ if (write_buffer)
+ arc_jtag_enque_write_dr(jtag_info, *(write_buffer + i), TAP_IDLE);
+ else
+ arc_jtag_enque_read_dr(jtag_info, read_buffer + i * 4, TAP_IDLE);
+ }
+ /* To prevent pollution of next regiter due to optimization it is necessary *
+ * to reset transaction */
+ arc_jtag_enque_reset_transaction(jtag_info);
+}
+
+/**
+ * Write registers. addr is an array of addresses, and those addresses can be
+ * in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param type Type of registers to write: core or aux.
+ * @param addr Array of registers numbers.
+ * @param count Amount of registers in arrays.
+ * @param values Array of register values.
+ */
+static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type,
+ uint32_t *addr, uint32_t count, const uint32_t *buffer)
+{
+ LOG_DEBUG("Writing to %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32
+ ";buffer[0]=0x%08" PRIx32,
+ (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count, *buffer);
+
+ if (!count) {
+ LOG_ERROR("Trying to write 0 registers");
+ return ERROR_FAIL;
+ }
+
+ arc_jtag_enque_reset_transaction(jtag_info);
+
+ /* What registers are we writing to? */
+ const uint32_t transaction = (type == ARC_JTAG_CORE_REG ?
+ ARC_JTAG_WRITE_TO_CORE_REG : ARC_JTAG_WRITE_TO_AUX_REG);
+ arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
+
+ arc_jtag_enque_register_rw(jtag_info, addr, NULL, buffer, count);
+
+ return jtag_execute_queue();
+}
+
+/**
+ * Read registers. addr is an array of addresses, and those addresses can be in
+ * any order, though it is recommended that they are in sequential order where
+ * possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param type Type of registers to read: core or aux.
+ * @param addr Array of registers numbers.
+ * @param count Amount of registers in arrays.
+ * @param values Array of register values.
+ */
+static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type,
+ uint32_t *addr, uint32_t count, uint32_t *buffer)
+{
+ int retval;
+ uint32_t i;
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ LOG_DEBUG("Reading %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32,
+ (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count);
+
+ if (!count) {
+ LOG_ERROR("Trying to read 0 registers");
+ return ERROR_FAIL;
+ }
+
+ arc_jtag_enque_reset_transaction(jtag_info);
+
+ /* What type of registers we are reading? */
+ const uint32_t transaction = (type == ARC_JTAG_CORE_REG ?
+ ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG);
+ arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
+
+ uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4);
+
+ arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute jtag queue: %d", retval);
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+
+ /* Convert byte-buffers to host /presentation. */
+ for (i = 0; i < count; i++)
+ buffer[i] = buf_get_u32(data_buf + 4 * i, 0, 32);
+
+ LOG_DEBUG("Read from register: buf[0]=0x%" PRIx32, buffer[0]);
+
+exit:
+ free(data_buf);
+
+ return retval;
+}
+
+
+/** Wrapper function to ease writing of one core register. */
+int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t value)
+{
+ return arc_jtag_write_core_reg(jtag_info, &addr, 1, &value);
+}
+
+/**
+ * Write core registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr Array of registers numbers.
+ * @param count Amount of registers in arrays.
+ * @param values Array of register values.
+ */
+int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, const uint32_t *buffer)
+{
+ return arc_jtag_write_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count,
+ buffer);
+}
+
+/** Wrapper function to ease reading of one core register. */
+int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t *value)
+{
+ return arc_jtag_read_core_reg(jtag_info, &addr, 1, value);
+}
+
+/**
+ * Read core registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr Array of core register numbers.
+ * @param count Amount of registers in arrays.
+ * @param values Array of register values.
+ */
+int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, uint32_t *buffer)
+{
+ return arc_jtag_read_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count,
+ buffer);
+}
+
+/** Wrapper function to ease writing of one AUX register. */
+int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t value)
+{
+ return arc_jtag_write_aux_reg(jtag_info, &addr, 1, &value);
+}
+
+/**
+ * Write AUX registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr Array of registers numbers.
+ * @param count Amount of registers in arrays.
+ * @param values Array of register values.
+ */
+int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, const uint32_t *buffer)
+{
+ return arc_jtag_write_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count,
+ buffer);
+}
+
+/** Wrapper function to ease reading of one AUX register. */
+int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t *value)
+{
+ return arc_jtag_read_aux_reg(jtag_info, &addr, 1, value);
+}
+
+/**
+ * Read AUX registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr Array of AUX register numbers.
+ * @param count Amount of registers in arrays.
+ * @param values Array of register values.
+ */
+int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, uint32_t *buffer)
+{
+ return arc_jtag_read_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count,
+ buffer);
+}
+
+/**
+ * Write a sequence of 4-byte words into target memory.
+ *
+ * We can write only 4byte words via JTAG, so any non-word writes should be
+ * handled at higher levels by read-modify-write.
+ *
+ * This function writes directly to the memory, leaving any caches (if there
+ * are any) in inconsistent state. It is responsibility of upper level to
+ * resolve this.
+ *
+ * @param jtag_info
+ * @param addr Address of first word to write into.
+ * @param count Amount of word to write.
+ * @param buffer Array to write into memory.
+ */
+int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t count, const uint32_t *buffer)
+{
+ assert(jtag_info);
+ assert(buffer);
+
+ LOG_DEBUG("Writing to memory: addr=0x%08" PRIx32 ";count=%" PRIu32 ";buffer[0]=0x%08" PRIx32,
+ addr, count, *buffer);
+
+ /* No need to waste time on useless operations. */
+ if (!count)
+ return ERROR_OK;
+
+ /* We do not know where we come from. */
+ arc_jtag_enque_reset_transaction(jtag_info);
+
+ /* We want to write to memory. */
+ arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_WRITE_TO_MEMORY, TAP_DRPAUSE);
+
+ /* Set target memory address of the first word. */
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
+ arc_jtag_enque_write_dr(jtag_info, addr, TAP_DRPAUSE);
+
+ /* Start sending words. Address is auto-incremented on 4bytes by HW. */
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
+
+ uint32_t i;
+ for (i = 0; i < count; i++)
+ arc_jtag_enque_write_dr(jtag_info, *(buffer + i), TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+/**
+ * Read a sequence of 4-byte words from target memory.
+ *
+ * We can read only 4byte words via JTAG.
+ *
+ * This function read directly from the memory, so it can read invalid data if
+ * data cache hasn't been flushed before hand. It is responsibility of upper
+ * level to resolve this.
+ *
+ * @param jtag_info
+ * @param addr Address of first word to read from.
+ * @param count Amount of words to read.
+ * @param buffer Array of words to read into.
+ * @param slow_memory Whether this is a slow memory (DDR) or fast (CCM).
+ */
+int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t count, uint32_t *buffer, bool slow_memory)
+{
+ uint8_t *data_buf;
+ uint32_t i;
+ int retval = ERROR_OK;
+
+
+ assert(jtag_info);
+ assert(jtag_info->tap);
+
+ LOG_DEBUG("Reading memory: addr=0x%" PRIx32 ";count=%" PRIu32 ";slow=%c",
+ addr, count, slow_memory ? 'Y' : 'N');
+
+ if (!count)
+ return ERROR_OK;
+
+ data_buf = calloc(sizeof(uint8_t), count * 4);
+ arc_jtag_enque_reset_transaction(jtag_info);
+
+ /* We are reading from memory. */
+ arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_READ_FROM_MEMORY, TAP_DRPAUSE);
+
+ /* Read data */
+ for (i = 0; i < count; i++) {
+ /* When several words are read at consequent addresses we can
+ * rely on ARC JTAG auto-incrementing address. That means that
+ * address can be set only once, for a first word. However it
+ * has been noted that at least in some cases when reading from
+ * DDR, JTAG returns 0 instead of a real value. To workaround
+ * this issue we need to do totally non-required address
+ * writes, which however resolve a problem by introducing
+ * delay. See STAR 9000832538... */
+ if (slow_memory || i == 0) {
+ /* Set address */
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
+ arc_jtag_enque_write_dr(jtag_info, addr + i * 4, TAP_IDLE);
+
+ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
+ }
+ arc_jtag_enque_read_dr(jtag_info, data_buf + i * 4, TAP_IDLE);
+ }
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute jtag queue: %d", retval);
+ retval = ERROR_FAIL;
+ goto exit;
+ }
+
+ /* Convert byte-buffers to host presentation. */
+ for (i = 0; i < count; i++)
+ buffer[i] = buf_get_u32(data_buf + 4*i, 0, 32);
+
+exit:
+ free(data_buf);
+
+ return retval;
+}
diff --git a/src/target/arc_jtag.h b/src/target/arc_jtag.h
new file mode 100644
index 000000000..99795f56a
--- /dev/null
+++ b/src/target/arc_jtag.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_JTAG_H
+#define OPENOCD_TARGET_ARC_JTAG_H
+
+#define ARC_TRANSACTION_CMD_REG 0x9 /* Command to perform */
+#define ARC_TRANSACTION_CMD_REG_LENGTH 4
+
+/* Jtag status register, value is placed in IR to read jtag status register */
+#define ARC_JTAG_STATUS_REG 0x8
+#define ARC_JTAG_ADDRESS_REG 0xA /* SoC address to access */
+#define ARC_JTAG_DATA_REG 0xB /* Data read/written from SoC */
+
+/* Jtag status register field */
+#define ARC_JTAG_STAT_RU 0x10
+
+/* ARC Jtag transactions */
+#define ARC_JTAG_WRITE_TO_MEMORY 0x0
+#define ARC_JTAG_WRITE_TO_CORE_REG 0x1
+#define ARC_JTAG_WRITE_TO_AUX_REG 0x2
+#define ARC_JTAG_CMD_NOP 0x3
+#define ARC_JTAG_READ_FROM_MEMORY 0x4
+#define ARC_JTAG_READ_FROM_CORE_REG 0x5
+#define ARC_JTAG_READ_FROM_AUX_REG 0x6
+
+#define ARC_JTAG_CORE_REG 0x0
+#define ARC_JTAG_AUX_REG 0x1
+
+
+struct arc_jtag {
+ struct jtag_tap *tap;
+ uint32_t cur_trans;
+};
+
+/* ----- Exported JTAG functions ------------------------------------------- */
+
+int arc_jtag_startup(struct arc_jtag *jtag_info);
+int arc_jtag_status(struct arc_jtag *const jtag_info, uint32_t *const value);
+
+int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, const uint32_t *buffer);
+int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, uint32_t *buffer);
+int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ const uint32_t buffer);
+int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t *buffer);
+
+int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, const uint32_t *buffer);
+int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t value);
+int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+ uint32_t count, uint32_t *buffer);
+int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t *value);
+
+int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t count, const uint32_t *buffer);
+int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
+ uint32_t count, uint32_t *buffer, bool slow_memory);
+#endif /* OPENOCD_TARGET_ARC_JTAG_H */
diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c
new file mode 100644
index 000000000..e80bfb4e4
--- /dev/null
+++ b/src/target/arc_mem.c
@@ -0,0 +1,287 @@
+/***************************************************************************
+ * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Mischa Jonker *
+ * Anton Kolesov *
+ * Evgeniy Didin *
+ * *
+ * SPDX-License-Identifier: GPL-2.0-or-later *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/* ----- Supporting functions ---------------------------------------------- */
+static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr,
+ uint32_t size, uint32_t count)
+{
+ uint32_t addr_end = addr + size * count;
+ /* `_end` field can overflow - it points to the first byte after the end,
+ * therefore if DCCM is right at the end of memory address space, then
+ * dccm_end will be 0. */
+ assert(addr_end >= addr || addr_end == 0);
+
+ return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) ||
+ (addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) ||
+ (addr >= arc->iccm1_start && addr_end <= arc->iccm1_end));
+}
+
+/* Write word at word-aligned address */
+static int arc_mem_write_block32(struct target *target, uint32_t addr,
+ uint32_t count, void *buf)
+{
+ struct arc_common *arc = target_to_arc(target);
+
+ LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
+ addr, count);
+
+ /* Check arguments */
+ assert(!(addr & 3));
+
+ /* No need to flush cache, because we don't read values from memory. */
+ CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
+ (uint32_t *)buf));
+
+ return ERROR_OK;
+}
+
+/* Write half-word at half-word-aligned address */
+static int arc_mem_write_block16(struct target *target, uint32_t addr,
+ uint32_t count, void *buf)
+{
+ struct arc_common *arc = target_to_arc(target);
+ uint32_t i;
+ uint32_t buffer_he;
+ uint8_t buffer_te[sizeof(uint32_t)];
+ uint8_t halfword_te[sizeof(uint16_t)];
+
+ LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
+ addr, count);
+
+ /* Check arguments */
+ assert(!(addr & 1));
+
+ /* non-word writes are less common, than 4-byte writes, so I suppose we can
+ * allowe ourselves to write this in a cycle, instead of calling arc_jtag
+ * with count > 1. */
+ for (i = 0; i < count; i++) {
+ /* We can read only word at word-aligned address. Also *jtag_read_memory
+ * functions return data in host endianness, so host endianness !=
+ * target endianness we have to convert data back to target endianness,
+ * or bytes will be at the wrong places.So:
+ * 1) read word
+ * 2) convert to target endianness
+ * 3) make changes
+ * 4) convert back to host endianness
+ * 5) write word back to target.
+ */
+ bool is_slow_memory = arc_mem_is_slow_memory(arc,
+ (addr + i * sizeof(uint16_t)) & ~3u, 4, 1);
+ CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info,
+ (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he,
+ is_slow_memory));
+ target_buffer_set_u32(target, buffer_te, buffer_he);
+
+ /* buf is in host endianness, convert to target */
+ target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]);
+
+ memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u),
+ halfword_te, sizeof(uint16_t));
+
+ buffer_he = target_buffer_get_u32(target, buffer_te);
+
+ CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info,
+ (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
+ }
+
+ return ERROR_OK;
+}
+
+/* Write byte at address */
+static int arc_mem_write_block8(struct target *target, uint32_t addr,
+ uint32_t count, void *buf)
+{
+ struct arc_common *arc = target_to_arc(target);
+ uint32_t i;
+ uint32_t buffer_he;
+ uint8_t buffer_te[sizeof(uint32_t)];
+
+
+ LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
+ addr, count);
+
+ /* non-word writes are less common, than 4-byte writes, so I suppose we can
+ * allowe ourselves to write this in a cycle, instead of calling arc_jtag
+ * with count > 1. */
+ for (i = 0; i < count; i++) {
+ /* See comment in arc_mem_write_block16 for details. Since it is a byte
+ * there is not need to convert write buffer to target endianness, but
+ * we still have to convert read buffer. */
+ CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he,
+ arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1)));
+ target_buffer_set_u32(target, buffer_te, buffer_he);
+ memcpy(buffer_te + ((addr + i) & 3), (uint8_t *)buf + i, 1);
+ buffer_he = target_buffer_get_u32(target, buffer_te);
+ CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
+ }
+
+ return ERROR_OK;
+}
+
+/* ----- Exported functions ------------------------------------------------ */
+int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
+ uint32_t count, const uint8_t *buffer)
+{
+ int retval = ERROR_OK;
+ void *tunnel = NULL;
+
+ LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32,
+ address, size, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* sanitize arguments */
+ if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
+ /* correct endianess if we have word or hword access */
+ if (size > 1) {
+ /*
+ * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t
+ * in host endianness, but byte array represents target endianness.
+ */
+ tunnel = calloc(1, count * size * sizeof(uint8_t));
+
+ if (!tunnel) {
+ LOG_ERROR("Unable to allocate memory");
+ return ERROR_FAIL;
+ }
+
+ switch (size) {
+ case 4:
+ target_buffer_get_u32_array(target, buffer, count,
+ (uint32_t *)tunnel);
+ break;
+ case 2:
+ target_buffer_get_u16_array(target, buffer, count,
+ (uint16_t *)tunnel);
+ break;
+ }
+ buffer = tunnel;
+ }
+
+ if (size == 4) {
+ retval = arc_mem_write_block32(target, address, count, (void *)buffer);
+ } else if (size == 2) {
+ /* We convert buffer from host endianness to target. But then in
+ * write_block16, we do the reverse. Is there a way to avoid this without
+ * breaking other cases? */
+ retval = arc_mem_write_block16(target, address, count, (void *)buffer);
+ } else {
+ retval = arc_mem_write_block8(target, address, count, (void *)buffer);
+ }
+
+ free(tunnel);
+
+ return retval;
+}
+
+static int arc_mem_read_block(struct target *target, target_addr_t addr,
+ uint32_t size, uint32_t count, void *buf)
+{
+ struct arc_common *arc = target_to_arc(target);
+
+ LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
+ ", count=%" PRIu32, addr, size, count);
+ assert(!(addr & 3));
+ assert(size == 4);
+
+ CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
+ arc_mem_is_slow_memory(arc, addr, size, count)));
+
+ return ERROR_OK;
+}
+
+int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
+ uint32_t count, uint8_t *buffer)
+{
+ int retval = ERROR_OK;
+ void *tunnel_he;
+ uint8_t *tunnel_te;
+ uint32_t words_to_read, bytes_to_read;
+
+
+ LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
+ ", count=%" PRIu32, address, size, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Sanitize arguments */
+ if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
+ /* Reads are word-aligned, so padding might be required if count > 1.
+ * NB: +3 is a padding for the last word (in case it's not aligned;
+ * addr&3 is a padding for the first word (since address can be
+ * unaligned as well). */
+ bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u;
+ words_to_read = bytes_to_read >> 2;
+ tunnel_he = calloc(1, bytes_to_read);
+ tunnel_te = calloc(1, bytes_to_read);
+
+ if (!tunnel_he || !tunnel_te) {
+ LOG_ERROR("Unable to allocate memory");
+ free(tunnel_he);
+ free(tunnel_te);
+ return ERROR_FAIL;
+ }
+
+ /* We can read only word-aligned words. */
+ retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t),
+ words_to_read, tunnel_he);
+
+ /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
+ /* endianness, but byte array should represent target endianness */
+
+ if (ERROR_OK == retval) {
+ switch (size) {
+ case 4:
+ target_buffer_set_u32_array(target, buffer, count,
+ tunnel_he);
+ break;
+ case 2:
+ target_buffer_set_u32_array(target, tunnel_te,
+ words_to_read, tunnel_he);
+ /* Will that work properly with count > 1 and big endian? */
+ memcpy(buffer, tunnel_te + (address & 3u),
+ count * sizeof(uint16_t));
+ break;
+ case 1:
+ target_buffer_set_u32_array(target, tunnel_te,
+ words_to_read, tunnel_he);
+ /* Will that work properly with count > 1 and big endian? */
+ memcpy(buffer, tunnel_te + (address & 3u), count);
+ break;
+ }
+ }
+
+ free(tunnel_he);
+ free(tunnel_te);
+
+ return retval;
+}
diff --git a/src/target/arc_mem.h b/src/target/arc_mem.h
new file mode 100644
index 000000000..06e1c88d1
--- /dev/null
+++ b/src/target/arc_mem.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
+ * Frank Dols *
+ * Anton Kolesov *
+ * Evgeniy Didin