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 * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARC_MEM_H +#define OPENOCD_TARGET_ARC_MEM_H + +/* ----- Exported functions ------------------------------------------------ */ + +int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, + uint32_t count, uint8_t *buffer); +int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, + uint32_t count, const uint8_t *buffer); + + +#endif /* OPENOCD_TARGET_ARC_MEM_H */ diff --git a/src/target/arm.h b/src/target/arm.h index ea83d3867..3450260f0 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -40,6 +40,26 @@ * support has not yet been integrated, affecting Cortex-M parts. */ +/** + * Indicates what registers are in the ARM state core register set. + * + * - ARM_CORE_TYPE_STD indicates the standard set of 37 registers, seen + * on for example ARM7TDMI cores. + * - ARM_CORE_TYPE_SEC_EXT indicates core has security extensions, thus + * three more registers are shadowed for "Secure Monitor" mode. + * - ARM_CORE_TYPE_VIRT_EXT indicates core has virtualization extensions + * and also security extensions. Additional shadowed registers for + * "Secure Monitor" and "Hypervisor" modes. + * - ARM_CORE_TYPE_M_PROFILE indicates a microcontroller profile core, + * which only shadows SP. + */ +enum arm_core_type { + ARM_CORE_TYPE_STD = -1, + ARM_CORE_TYPE_SEC_EXT = 1, + ARM_CORE_TYPE_VIRT_EXT, + ARM_CORE_TYPE_M_PROFILE, +}; + /** * Represent state of an ARM core. * @@ -60,6 +80,7 @@ enum arm_mode { ARM_MODE_SVC = 19, ARM_MODE_MON = 22, ARM_MODE_ABT = 23, + ARM_MODE_HYP = 26, ARM_MODE_UND = 27, ARM_MODE_1176_MON = 28, ARM_MODE_SYS = 31, @@ -161,15 +182,8 @@ struct arm { /** Support for arm_reg_current() */ const int *map; - /** - * Indicates what registers are in the ARM state core register set. - * ARM_MODE_ANY indicates the standard set of 37 registers, - * seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three - * more registers are shadowed, for "Secure Monitor" mode. - * ARM_MODE_THREAD indicates a microcontroller profile core, - * which only shadows SP. - */ - enum arm_mode core_type; + /** Indicates what registers are in the ARM state core register set. */ + enum arm_core_type core_type; /** Record the current core mode: SVC, USR, or some other mode. */ enum arm_mode core_mode; @@ -258,6 +272,8 @@ struct arm_reg { }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); +void arm_free_reg_cache(struct arm *arm); + struct reg_cache *armv8_build_reg_cache(struct target *target); extern const struct command_registration arm_command_handlers[]; diff --git a/src/target/arm11.c b/src/target/arm11.c index 159c30a85..10a1d6de5 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1105,11 +1105,11 @@ static int arm11_target_create(struct target *target, Jim_Interp *interp) return ERROR_COMMAND_SYNTAX_ERROR; } - arm11 = calloc(1, sizeof *arm11); + arm11 = calloc(1, sizeof(*arm11)); if (!arm11) return ERROR_FAIL; - arm11->arm.core_type = ARM_MODE_ANY; + arm11->arm.core_type = ARM_CORE_TYPE_STD; arm_init_arch_info(target, &arm11->arm); arm11->jtag_info.tap = target->tap; @@ -1180,7 +1180,7 @@ static int arm11_examine(struct target *target) type = "ARM1156"; break; case 0x7B76: - arm11->arm.core_type = ARM_MODE_MON; + arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; /* NOTE: could default arm11->hardware_step to true */ type = "ARM1176"; break; diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 2232b3ef6..a758db58f 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -1183,7 +1183,7 @@ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) /* alloc enough to enable all breakpoints and watchpoints at once */ arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp), - sizeof *arm11->bpwp_actions); + sizeof(*arm11->bpwp_actions)); if (!arm11->bpwp_actions) return ERROR_FAIL; diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index b2962d1c4..6a7bf9da5 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -2848,7 +2848,7 @@ int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9) arm7_9->dcc_downloads = false; arm->arch_info = arm7_9; - arm->core_type = ARM_MODE_ANY; + arm->core_type = ARM_CORE_TYPE_STD; arm->read_core_reg = arm7_9_read_core_reg; arm->write_core_reg = arm7_9_write_core_reg; arm->full_context = arm7_9_full_context; diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 2ecf218fd..3ddd19888 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -484,7 +484,7 @@ int arm920t_post_debug_entry(struct target *target) /* EXPORTED to FA256 */ void arm920t_pre_restore_context(struct target *target) { - uint32_t cp15c15; + uint32_t cp15c15 = 0; struct arm920t_common *arm920t = target_to_arm920(target); /* restore i/d fault status and address register */ diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 112631a7c..4ef167a9d 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -267,7 +267,11 @@ uint32_t arm946e_invalidate_whole_dcache(struct target *target) /* Read dtag */ uint32_t dtag; - arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag); + retval = arm946e_read_cp15(target, 0x16, &dtag); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR reading dtag"); + return retval; + } /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) @@ -321,7 +325,7 @@ int arm946e_post_debug_entry(struct target *target) /* See if CACHES are enabled, and save that info * in the context bits, so that arm946e_pre_restore_context() can use them */ - arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg); + arm946e_read_cp15(target, CP15_CTL, &ctr_reg); /* Save control reg in the context */ arm946e->cp15_control_reg = ctr_reg; @@ -362,7 +366,7 @@ void arm946e_pre_restore_context(struct target *target) if (arm946e_preserve_cache) { struct arm946e_common *arm946e = target_to_arm946(target); /* Get the contents of the CTR reg */ - arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg); + arm946e_read_cp15(target, CP15_CTL, &ctr_reg); /** * Read-modify-write CP15 control @@ -410,7 +414,11 @@ uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, } /* Read dtag */ - arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag); + retval = arm946e_read_cp15(target, 0x16, &dtag); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR reading dtag"); + return retval; + } /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) @@ -463,7 +471,11 @@ uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, } /* Read itag */ - arm946e_read_cp15(target, 0x17, (uint32_t *) &itag); + retval = arm946e_read_cp15(target, 0x17, &itag); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR reading itag"); + return retval; + } /* Check cache line VALID bit */ if (!(itag >> 4 & 0x1)) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index d2ec960a8..f19514c85 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -804,26 +804,9 @@ int mem_ap_init(struct adiv5_ap *ap) */ int dap_to_swd(struct adiv5_dap *dap) { - int retval; - LOG_DEBUG("Enter SWD mode"); - if (transport_is_jtag()) { - retval = jtag_add_tms_seq(swd_seq_jtag_to_swd_len, - swd_seq_jtag_to_swd, TAP_INVALID); - if (retval == ERROR_OK) - retval = jtag_execute_queue(); - return retval; - } - - if (transport_is_swd()) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - - return swd->switch_seq(JTAG_TO_SWD); - } - - LOG_ERROR("Nor JTAG nor SWD transport"); - return ERROR_FAIL; + return dap_send_sequence(dap, JTAG_TO_SWD); } /** @@ -839,26 +822,9 @@ int dap_to_swd(struct adiv5_dap *dap) */ int dap_to_jtag(struct adiv5_dap *dap) { - int retval; - LOG_DEBUG("Enter JTAG mode"); - if (transport_is_jtag()) { - retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len, - swd_seq_swd_to_jtag, TAP_RESET); - if (retval == ERROR_OK) - retval = jtag_execute_queue(); - return retval; - } - - if (transport_is_swd()) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - - return swd->switch_seq(SWD_TO_JTAG); - } - - LOG_ERROR("Nor JTAG nor SWD transport"); - return ERROR_FAIL; + return dap_send_sequence(dap, SWD_TO_JTAG); } /* CID interpretation -- see ARM IHI 0029B section 3 @@ -1644,8 +1610,10 @@ COMMAND_HANDLER(handle_dap_info_command) break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1667,8 +1635,10 @@ COMMAND_HANDLER(dap_baseaddr_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1726,8 +1696,10 @@ COMMAND_HANDLER(dap_apsel_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1756,7 +1728,7 @@ COMMAND_HANDLER(dap_apcsw_command) if (csw_val & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) { LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } apcsw = csw_val; break; @@ -1765,7 +1737,7 @@ COMMAND_HANDLER(dap_apcsw_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], csw_mask); if (csw_mask & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) { LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } apcsw = (apcsw & ~csw_mask) | (csw_val & csw_mask); break; @@ -1792,8 +1764,10 @@ COMMAND_HANDLER(dap_apid_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1823,13 +1797,18 @@ COMMAND_HANDLER(dap_apreg_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + ap = dap_ap(dap, apsel); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg); - if (reg >= 256 || (reg & 3)) - return ERROR_COMMAND_SYNTAX_ERROR; + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); @@ -1873,8 +1852,10 @@ COMMAND_HANDLER(dap_dpreg_command) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg); - if (reg >= 256 || (reg & 3)) - return ERROR_COMMAND_SYNTAX_ERROR; + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); @@ -1897,24 +1878,8 @@ COMMAND_HANDLER(dap_dpreg_command) COMMAND_HANDLER(dap_ti_be_32_quirks_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t enable = dap->ti_be_32_quirks; - - switch (CMD_ARGC) { - case 0: - break; - case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], enable); - if (enable > 1) - return ERROR_COMMAND_SYNTAX_ERROR; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - dap->ti_be_32_quirks = enable; - command_print(CMD, "TI BE-32 quirks mode %s", - enable ? "enabled" : "disabled"); - - return 0; + return CALL_COMMAND_HANDLER(handle_command_parse_bool, &dap->ti_be_32_quirks, + "TI BE-32 quirks mode"); } const struct command_registration dap_instance_commands[] = { diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 6e2d8a182..17365bddb 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -158,6 +158,15 @@ #define DP_APSEL_MAX (255) #define DP_APSEL_INVALID (-1) +/* FIXME: not SWD specific; should be renamed, e.g. adiv5_special_seq */ +enum swd_special_seq { + LINE_RESET, + JTAG_TO_SWD, + SWD_TO_JTAG, + SWD_TO_DORMANT, + DORMANT_TO_SWD, +}; + /** * This represents an ARM Debug Interface (v5) Access Port (AP). * Most common is a MEM-AP, for memory access. @@ -234,6 +243,12 @@ struct adiv5_dap { /* dap transaction list for WAIT support */ struct list_head cmd_journal; + /* pool for dap_cmd objects */ + struct list_head cmd_pool; + + /* number of dap_cmd objects in the pool */ + size_t cmd_pool_size; + struct jtag_tap *tap; /* Control config */ uint32_t dp_ctrl_stat; @@ -264,6 +279,12 @@ struct adiv5_dap { * swizzle appropriately. */ bool ti_be_32_quirks; + /** + * STLINK adapter need to know if last AP operation was read or write, and + * in case of write has to flush it with a dummy read from DP_RDBUFF + */ + bool stlink_flush_ap_write; + /** * Signals that an attempt to reestablish communication afresh * should be performed before the next access. @@ -285,6 +306,10 @@ struct adiv5_dap { struct dap_ops { /** connect operation for SWD */ int (*connect)(struct adiv5_dap *dap); + + /** send a sequence to the DAP */ + int (*send_sequence)(struct adiv5_dap *dap, enum swd_special_seq seq); + /** DP register read. */ int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); @@ -332,6 +357,21 @@ enum ap_type { AP_TYPE_AHB5_AP = 0x5, /* AHB5 Memory-AP. */ }; +/** + * Send an adi-v5 sequence to the DAP. + * + * @param dap The DAP used for reading. + * @param seq The sequence to send. + * + * @return ERROR_OK for success, else a fault code. + */ +static inline int dap_send_sequence(struct adiv5_dap *dap, + enum swd_special_seq seq) +{ + assert(dap->ops != NULL); + return dap->ops->send_sequence(dap, seq); +} + /** * Queue a DP register read. * Note that not all DP registers are readable; also, that JTAG and SWD diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 3f063b894..579bacb77 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -261,14 +261,11 @@ COMMAND_HANDLER(handle_cti_dump) COMMAND_HANDLER(handle_cti_enable) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; bool on_off; - if (CMD_ARGC != 1) { - Jim_SetResultString(interp, "wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); @@ -278,14 +275,11 @@ COMMAND_HANDLER(handle_cti_enable) COMMAND_HANDLER(handle_cti_testmode) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; bool on_off; - if (CMD_ARGC != 1) { - Jim_SetResultString(interp, "wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); @@ -295,15 +289,12 @@ COMMAND_HANDLER(handle_cti_testmode) COMMAND_HANDLER(handle_cti_write) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; int offset; uint32_t value; - if (CMD_ARGC != 2) { - Jim_SetResultString(interp, "Wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; offset = cti_find_reg_offset(CMD_ARGV[0]); if (offset < 0) @@ -317,16 +308,13 @@ COMMAND_HANDLER(handle_cti_write) COMMAND_HANDLER(handle_cti_read) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; int offset; int retval; uint32_t value; - if (CMD_ARGC != 1) { - Jim_SetResultString(interp, "Wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; offset = cti_find_reg_offset(CMD_ARGV[0]); if (offset < 0) @@ -341,6 +329,59 @@ COMMAND_HANDLER(handle_cti_read) return ERROR_OK; } +COMMAND_HANDLER(handle_cti_ack) +{ + struct arm_cti_object *obj = CMD_DATA; + struct arm_cti *cti = &obj->cti; + uint32_t event; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], event); + + int retval = arm_cti_ack_events(cti, 1 << event); + + + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_cti_channel) +{ + struct arm_cti_object *obj = CMD_DATA; + struct arm_cti *cti = &obj->cti; + int retval = ERROR_OK; + uint32_t ch_num; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ch_num); + + if (!strcmp(CMD_ARGV[1], "gate")) + retval = arm_cti_gate_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "ungate")) + retval = arm_cti_ungate_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "pulse")) + retval = arm_cti_pulse_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "set")) + retval = arm_cti_set_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "clear")) + retval = arm_cti_clear_channel(cti, ch_num); + else { + command_print(CMD, "Possible channel operations: gate|ungate|set|clear|pulse"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + static const struct command_registration cti_instance_command_handlers[] = { { .name = "dump", @@ -377,6 +418,21 @@ static const struct command_registration cti_instance_command_handlers[] = { .help = "read a CTI register", .usage = "register_name", }, + { + .name = "ack", + .mode = COMMAND_EXEC, + .handler = handle_cti_ack, + .help = "acknowledge a CTI event", + .usage = "event", + }, + { + .name = "channel", + .mode = COMMAND_EXEC, + .handler = handle_cti_channel, + .help = "do an operation on one CTI channel, possible operations: " + "gate, ungate, set, clear and pulse", + .usage = "channel_number operation", + }, COMMAND_REGISTRATION_DONE }; @@ -585,4 +641,3 @@ int cti_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, cti_command_handlers); } - diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index fbcfe0d4d..56442f183 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -34,7 +34,7 @@ static LIST_HEAD(all_dap); extern const struct dap_ops swd_dap_ops; extern const struct dap_ops jtag_dp_ops; -extern struct jtag_interface *jtag_interface; +extern struct adapter_driver *adapter_driver; /* DAP command support */ struct arm_dap_object { @@ -59,6 +59,7 @@ static void dap_instance_init(struct adiv5_dap *dap) dap->ap[i].csw_default = CSW_AHB_DEFAULT; } INIT_LIST_HEAD(&dap->cmd_journal); + INIT_LIST_HEAD(&dap->cmd_pool); } const char *adiv5_dap_name(struct adiv5_dap *self) @@ -117,7 +118,11 @@ static int dap_init_all(void) if (transport_is_swd()) { dap->ops = &swd_dap_ops; - obj->swd = jtag_interface->swd; + obj->swd = adapter_driver->swd_ops; + } else if (transport_is_dapdirect_swd()) { + dap->ops = adapter_driver->dap_swd_ops; + } else if (transport_is_dapdirect_jtag()) { + dap->ops = adapter_driver->dap_jtag_ops; } else dap->ops = &jtag_dp_ops; diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 8eb819446..da8aee28b 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -2086,7 +2086,7 @@ static int evaluate_b_bl_blx_thumb(uint16_t opcode, break; /* BL/BLX prefix */ case 2: - instruction->type = ARM_UNKNOWN_INSTUCTION; + instruction->type = ARM_UNKNOWN_INSTRUCTION; mnemonic = "prefix"; target_address = offset << 12; break; @@ -2309,7 +2309,6 @@ static int evaluate_data_proc_thumb(uint16_t opcode, address, opcode); } return ERROR_OK; - break; } } else { switch (op) { @@ -2673,7 +2672,7 @@ static int evaluate_load_store_multiple_thumb(uint16_t opcode, instruction->type = ARM_STM; mnemonic = "STM"; } - snprintf(ptr_name, sizeof ptr_name, "r%i%s, ", Rn, wback); + snprintf(ptr_name, sizeof(ptr_name), "r%i%s, ", Rn, wback); } else {/* push/pop */ Rn = 13;/* SP */ if (L) { diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index e9f4d44cb..486e903e3 100644 --- a/src/target/arm_disassembler.h +++ b/src/target/arm_disassembler.h @@ -20,7 +20,7 @@ #define OPENOCD_TARGET_ARM_DISASSEMBLER_H enum arm_instruction_type { - ARM_UNKNOWN_INSTUCTION, + ARM_UNKNOWN_INSTRUCTION, /* Branch instructions */ ARM_B, diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 8b9957033..72215f90b 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -145,6 +145,9 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); + if (retval != ERROR_OK) + break; + /* read r1 via dcc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), @@ -209,7 +212,6 @@ int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) break; case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: return dpm_read_reg_u64(dpm, r, regnum); - break; case ARM_VFP_V3_FPSCR: /* "VMRS r0, FPSCR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, @@ -248,6 +250,9 @@ static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); + if (retval != ERROR_OK) + break; + /* write value_r0 to r0 via dcc then, * move to double word register from r0:r1: "vmov vm, r0, r1" */ @@ -288,7 +293,6 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) break; case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: return dpm_write_reg_u64(dpm, r, regnum); - break; case ARM_VFP_V3_FPSCR: /* move to r0 from DCC, then "VMSR FPSCR, r0" */ retval = dpm->instr_write_data_r0(dpm, @@ -1092,10 +1096,11 @@ int arm_dpm_setup(struct arm_dpm *dpm) dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); - dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); - dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); + dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp)); + dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp)); if (!dpm->dbp || !dpm->dwp) { + arm_free_reg_cache(arm); free(dpm->dbp); free(dpm->dwp); return ERROR_FAIL; diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index 9b73d4ea8..49aca3487 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -33,7 +33,7 @@ int arm_jtag_set_instr_inner(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { struct scan_field field; - uint8_t t[4]; + uint8_t t[4] = { 0 }; field.num_bits = tap->ir_length; field.out_value = t; @@ -56,7 +56,7 @@ int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, ta { int retval = ERROR_OK; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; buf_set_u32(out_value, 0, jtag_info->scann_size, new_scan_chain); struct scan_field field = { .num_bits = jtag_info->scann_size, .out_value = out_value, }; diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 53a6b2229..58bc3390a 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -48,6 +48,7 @@ enum { ARMV4_5_SPSR_ABT = 35, ARMV4_5_SPSR_UND = 36, ARM_SPSR_MON = 41, + ARM_SPSR_HYP = 43, }; static const uint8_t arm_usr_indices[17] = { @@ -78,6 +79,10 @@ static const uint8_t arm_mon_indices[3] = { 39, 40, ARM_SPSR_MON, }; +static const uint8_t arm_hyp_indices[2] = { + 42, ARM_SPSR_HYP, +}; + static const struct { const char *name; unsigned short psr; @@ -163,6 +168,14 @@ static const struct { .name = "Handler", .psr = ARM_MODE_HANDLER, }, + + /* armv7-a with virtualization extension */ + { + .name = "Hypervisor", + .psr = ARM_MODE_HYP, + .n_indices = ARRAY_SIZE(arm_hyp_indices), + .indices = arm_hyp_indices, + }, }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ @@ -209,6 +222,8 @@ int arm_mode_to_number(enum arm_mode mode) case ARM_MODE_MON: case ARM_MODE_1176_MON: return 7; + case ARM_MODE_HYP: + return 8; default: LOG_ERROR("invalid mode value encountered %d", mode); return -1; @@ -235,6 +250,8 @@ enum arm_mode armv4_5_number_to_mode(int number) return ARM_MODE_SYS; case 7: return ARM_MODE_MON; + case 8: + return ARM_MODE_HYP; default: LOG_ERROR("mode index out of bounds %d", number); return ARM_MODE_ANY; @@ -274,24 +291,24 @@ static const struct { * correspond to r0..r7, and the fifteenth to PC, so that callers * don't need to map them. */ - { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, .gdb_index = 0, }, - { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, .gdb_index = 1, }, - { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, .gdb_index = 2, }, - { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, .gdb_index = 3, }, - { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, .gdb_index = 4, }, - { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, .gdb_index = 5, }, - { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, .gdb_index = 6, }, - { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, .gdb_index = 7, }, + [0] = { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, .gdb_index = 0, }, + [1] = { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, .gdb_index = 1, }, + [2] = { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, .gdb_index = 2, }, + [3] = { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, .gdb_index = 3, }, + [4] = { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, .gdb_index = 4, }, + [5] = { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, .gdb_index = 5, }, + [6] = { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, .gdb_index = 6, }, + [7] = { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, .gdb_index = 7, }, /* NOTE: regs 8..12 might be shadowed by FIQ ... flagging * them as MODE_ANY creates special cases. (ANY means * "not mapped" elsewhere; here it's "everything but FIQ".) */ - { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, .gdb_index = 8, }, - { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, .gdb_index = 9, }, - { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, .gdb_index = 10, }, - { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, .gdb_index = 11, }, - { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, .gdb_index = 12, }, + [8] = { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, .gdb_index = 8, }, + [9] = { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, .gdb_index = 9, }, + [10] = { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, .gdb_index = 10, }, + [11] = { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, .gdb_index = 11, }, + [12] = { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, .gdb_index = 12, }, /* Historical GDB mapping of indices: * - 13-14 are sp and lr, but banked counterparts are used @@ -300,48 +317,51 @@ static const struct { */ /* NOTE all MODE_USR registers are equivalent to MODE_SYS ones */ - { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, .gdb_index = 26, }, - { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, .gdb_index = 27, }, + [13] = { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, .gdb_index = 26, }, + [14] = { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, .gdb_index = 27, }, /* guaranteed to be at index 15 */ - { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, .gdb_index = 15, }, - { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, .gdb_index = 28, }, - { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, .gdb_index = 29, }, - { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, .gdb_index = 30, }, - { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, .gdb_index = 31, }, - { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, .gdb_index = 32, }, + [15] = { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, .gdb_index = 15, }, + [16] = { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, .gdb_index = 28, }, + [17] = { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, .gdb_index = 29, }, + [18] = { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, .gdb_index = 30, }, + [19] = { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, .gdb_index = 31, }, + [20] = { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, .gdb_index = 32, }, - { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, .gdb_index = 33, }, - { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, .gdb_index = 34, }, + [21] = { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, .gdb_index = 33, }, + [22] = { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, .gdb_index = 34, }, - { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, .gdb_index = 35, }, - { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, .gdb_index = 36, }, + [23] = { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, .gdb_index = 35, }, + [24] = { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, .gdb_index = 36, }, - { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, .gdb_index = 37, }, - { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, .gdb_index = 38, }, + [25] = { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, .gdb_index = 37, }, + [26] = { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, .gdb_index = 38, }, - { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, .gdb_index = 39, }, - { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, .gdb_index = 40, }, + [27] = { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, .gdb_index = 39, }, + [28] = { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, .gdb_index = 40, }, - { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, .gdb_index = 41, }, - { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, .gdb_index = 42, }, + [29] = { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, .gdb_index = 41, }, + [30] = { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, .gdb_index = 42, }, - { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, .gdb_index = 25, }, - { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, .gdb_index = 43, }, - { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, .gdb_index = 44, }, - { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, .gdb_index = 45, }, - { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, .gdb_index = 46, }, - { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, .gdb_index = 47, }, + [31] = { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, .gdb_index = 25, }, + [32] = { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, .gdb_index = 43, }, + [33] = { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, .gdb_index = 44, }, + [34] = { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, .gdb_index = 45, }, + [35] = { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, .gdb_index = 46, }, + [36] = { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, .gdb_index = 47, }, /* These are only used for GDB target description, banked registers are accessed instead */ - { .name = "sp", .cookie = 13, .mode = ARM_MODE_ANY, .gdb_index = 13, }, - { .name = "lr", .cookie = 14, .mode = ARM_MODE_ANY, .gdb_index = 14, }, + [37] = { .name = "sp", .cookie = 13, .mode = ARM_MODE_ANY, .gdb_index = 13, }, + [38] = { .name = "lr", .cookie = 14, .mode = ARM_MODE_ANY, .gdb_index = 14, }, /* These exist only when the Security Extension (TrustZone) is present */ - { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, .gdb_index = 48, }, - { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, .gdb_index = 49, }, - { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, .gdb_index = 50, }, + [39] = { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, .gdb_index = 48, }, + [40] = { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, .gdb_index = 49, }, + [41] = { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, .gdb_index = 50, }, + /* These exist only when the Virtualization Extensions is present */ + [42] = { .name = "sp_hyp", .cookie = 13, .mode = ARM_MODE_HYP, .gdb_index = 51, }, + [43] = { .name = "spsr_hyp", .cookie = 16, .mode = ARM_MODE_HYP, .gdb_index = 52, }, }; static const struct { @@ -391,7 +411,7 @@ static const struct { /* map core mode (USR, FIQ, ...) and register number to * indices into the register cache */ -const int armv4_5_core_reg_map[8][17] = { +const int armv4_5_core_reg_map[9][17] = { { /* USR */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, @@ -414,7 +434,10 @@ const int armv4_5_core_reg_map[8][17] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, { /* MON */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 37, 38, 15, 39, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 39, 40, 15, 41, + }, + { /* HYP */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 42, 14, 15, 43, } }; @@ -658,7 +681,11 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) for (i = 0; i < num_core_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON - && arm->core_type != ARM_MODE_MON) + && arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + if (arm_core_regs[i].mode == ARM_MODE_HYP + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* REVISIT handle Cortex-M, which only shadows R13/SP */ @@ -742,6 +769,27 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) return cache; } +void arm_free_reg_cache(struct arm *arm) +{ + if (!arm || !arm->core_cache) + return; + + struct reg_cache *cache = arm->core_cache; + + for (unsigned int i = 0; i < cache->num_regs; i++) { + struct reg *reg = &cache->reg_list[i]; + + free(reg->feature); + free(reg->reg_data_type); + } + + free(cache->reg_list[0].arch_info); + free(cache->reg_list); + free(cache); + + arm->core_cache = NULL; +} + int arm_arch_state(struct target *target) { struct arm *arm = target_to_arm(target); @@ -768,9 +816,6 @@ int arm_arch_state(struct target *target) return ERROR_OK; } -#define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \ - (cache->reg_list[armv4_5_core_reg_map[mode][num]]) - COMMAND_HANDLER(handle_armv4_5_reg_command) { struct target *target = get_current_target(CMD_CTX); @@ -787,7 +832,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) return ERROR_FAIL; } - if (arm->core_type != ARM_MODE_ANY) { + if (arm->core_type != ARM_CORE_TYPE_STD) { command_print(CMD, "Microcontroller Profile not supported - use standard reg cmd"); return ERROR_OK; @@ -819,8 +864,13 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) name = "System and User"; sep = ""; break; + case ARM_MODE_HYP: + if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + /* FALLTHROUGH */ case ARM_MODE_MON: - if (arm->core_type != ARM_MODE_MON) + if (arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* FALLTHROUGH */ default: @@ -872,7 +922,7 @@ COMMAND_HANDLER(handle_armv4_5_core_state_command) return ERROR_FAIL; } - if (arm->core_type == ARM_MODE_THREAD) { + if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { /* armv7m not supported */ command_print(CMD, "Unsupported Command"); return ERROR_OK; @@ -910,7 +960,7 @@ COMMAND_HANDLER(handle_arm_disassemble_command) return ERROR_FAIL; } - if (arm->core_type == ARM_MODE_THREAD) { + if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { /* armv7m is always thumb mode */ thumb = 1; } @@ -1098,10 +1148,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) return JIM_OK; } -extern __COMMAND_HANDLER(handle_common_semihosting_command); -extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command); -extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command); -extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); +extern const struct command_registration semihosting_common_handlers[]; static const struct command_registration arm_exec_command_handlers[] = { { @@ -1140,32 +1187,7 @@ static const struct command_registration arm_exec_command_handlers[] = { .usage = "cpnum op1 CRn CRm op2", }, { - .name = "semihosting", - .handler = handle_common_semihosting_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting operations", - }, - { - .name = "semihosting_cmdline", - .handler = handle_common_semihosting_cmdline, - .mode = COMMAND_EXEC, - .usage = "arguments", - .help = "command line arguments to be passed to program", - }, - { - .name = "semihosting_fileio", - .handler = handle_common_semihosting_fileio_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting fileio operations", - }, - { - .name = "semihosting_resexit", - .handler = handle_common_semihosting_resumable_exit_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting resumable exit", + .chain = semihosting_common_handlers, }, COMMAND_REGISTRATION_DONE }; @@ -1222,10 +1244,18 @@ int arm_get_gdb_reg_list(struct target *target, (*reg_list)[25] = arm->cpsr; return ERROR_OK; - break; case REG_CLASS_ALL: - *reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51); + switch (arm->core_type) { + case ARM_CORE_TYPE_SEC_EXT: + *reg_list_size = 51; + break; + case ARM_CORE_TYPE_VIRT_EXT: + *reg_list_size = 53; + break; + default: + *reg_list_size = 48; + } unsigned int list_size_core = *reg_list_size; if (arm->arm_vfp_version == ARM_VFP_V3) *reg_list_size += 33; @@ -1237,9 +1267,15 @@ int arm_get_gdb_reg_list(struct target *target, for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) { int reg_index = arm->core_cache->reg_list[i].number; - if (!(arm_core_regs[i].mode == ARM_MODE_MON - && arm->core_type != ARM_MODE_MON)) - (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); + + if (arm_core_regs[i].mode == ARM_MODE_MON + && arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + if (arm_core_regs[i].mode == ARM_MODE_HYP + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); } /* When we supply the target description, there is no need for fake FPA */ @@ -1257,12 +1293,10 @@ int arm_get_gdb_reg_list(struct target *target, } return ERROR_OK; - break; default: LOG_ERROR("not a valid register class type in query."); return ERROR_FAIL; - break; } } @@ -1701,8 +1735,8 @@ int arm_init_arch_info(struct target *target, struct arm *arm) arm->common_magic = ARM_COMMON_MAGIC; /* core_type may be overridden by subtype logic */ - if (arm->core_type != ARM_MODE_THREAD) { - arm->core_type = ARM_MODE_ANY; + if (arm->core_type != ARM_CORE_TYPE_M_PROFILE) { + arm->core_type = ARM_CORE_TYPE_STD; arm_set_cpsr(arm, ARM_MODE_USR); } diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h index 3ce4ed0e5..bef1cfe32 100644 --- a/src/target/armv4_5.h +++ b/src/target/armv4_5.h @@ -38,7 +38,7 @@ int arm_mode_to_number(enum arm_mode mode); enum arm_mode armv4_5_number_to_mode(int number); -extern const int armv4_5_core_reg_map[8][17]; +extern const int armv4_5_core_reg_map[9][17]; #define ARMV4_5_CORE_REG_MODE(cache, mode, num) \ (cache->reg_list[armv4_5_core_reg_map[arm_mode_to_number(mode)][num]]) diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 0ef04c162..3d88c8679 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -178,6 +178,9 @@ static inline bool is_armv7a(struct armv7a_common *armv7a) /* See ARMv7a arch spec section C10.8 */ #define CPUDBG_AUTHSTATUS 0xFB8 +/* See ARMv7a arch spec DDI 0406C C11.10 */ +#define CPUDBG_ID_PFR1 0xD24 + /* Masks for Vector Catch register */ #define DBG_VCR_FIQ_MASK ((1 << 31) | (1 << 7)) #define DBG_VCR_IRQ_MASK ((1 << 30) | (1 << 6)) diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c index f83228d55..eec14a36f 100644 --- a/src/target/armv7a_mmu.c +++ b/src/target/armv7a_mmu.c @@ -62,12 +62,6 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, /* decode memory attribute */ SS = (value >> 1) & 1; -#if !BUILD_TARGET64 - if (SS) { - LOG_ERROR("Super section found with no-64 bit address support"); - return ERROR_FAIL; - } -#endif NOS = (value >> 10) & 1; /* Not Outer shareable */ NS = (value >> 9) & 1; /* Non secure */ INNER = (value >> 4) & 0x7; diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 4b37774a5..017d693ce 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -301,20 +301,22 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct armv7m_common *armv7m = target_to_armv7m(target); - int i; + int i, size; if (reg_class == REG_CLASS_ALL) - *reg_list_size = armv7m->arm.core_cache->num_regs; + size = armv7m->arm.core_cache->num_regs; else - *reg_list_size = ARMV7M_NUM_CORE_REGS; + size = ARMV7M_NUM_CORE_REGS; - *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + *reg_list = malloc(sizeof(struct reg *) * size); if (*reg_list == NULL) return ERROR_FAIL; - for (i = 0; i < *reg_list_size; i++) + for (i = 0; i < size; i++) (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i]; + *reg_list_size = size; + return ERROR_OK; } @@ -462,7 +464,6 @@ int armv7m_wait_algorithm(struct target *target, struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; int retval = ERROR_OK; - uint32_t pc; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ @@ -484,12 +485,14 @@ int armv7m_wait_algorithm(struct target *target, return ERROR_TARGET_TIMEOUT; } - armv7m->load_core_reg_u32(target, 15, &pc); - if (exit_point && (pc != exit_point)) { - LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, - pc, - exit_point); - return ERROR_TARGET_TIMEOUT; + if (exit_point) { + /* PC value has been cached in cortex_m_debug_entry() */ + uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32); + if (pc != exit_point) { + LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, + pc, exit_point); + return ERROR_TARGET_ALGO_EXIT; + } } /* Read memory values to mem_params[] */ @@ -695,7 +698,7 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) /* Enable stimulus port #0 by default */ armv7m->trace_config.itm_ter[0] = 1; - arm->core_type = ARM_MODE_THREAD; + arm->core_type = ARM_CORE_TYPE_M_PROFILE; arm->arch_info = armv7m; arm->setup_semihosting = armv7m_setup_semihosting; diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 6170119d9..6b368f7a0 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -56,41 +56,39 @@ int armv7m_trace_tpiu_config(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_trace_config *trace_config = &armv7m->trace_config; - int prescaler; + uint16_t prescaler; int retval; target_unregister_timer_callback(armv7m_poll_trace, target); - retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, - trace_config->pin_protocol, - trace_config->port_size, - &trace_config->trace_freq); + trace_config->pin_protocol, trace_config->port_size, + &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler); + if (retval != ERROR_OK) return retval; + if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) { + prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; + + if (trace_config->traceclkin_freq % trace_config->trace_freq) { + prescaler++; + + int trace_freq = trace_config->traceclkin_freq / prescaler; + LOG_INFO("Can not obtain %u trace port frequency from %u " + "TRACECLKIN frequency, using %u instead", + trace_config->trace_freq, trace_config->traceclkin_freq, + trace_freq); + + trace_config->trace_freq = trace_freq; + } + } + if (!trace_config->trace_freq) { LOG_ERROR("Trace port frequency is 0, can't enable TPIU"); return ERROR_FAIL; } - prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; - - if (trace_config->traceclkin_freq % trace_config->trace_freq) { - prescaler++; - int trace_freq = trace_config->traceclkin_freq / prescaler; - LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead", - trace_config->trace_freq, trace_config->traceclkin_freq, - trace_freq); - trace_config->trace_freq = trace_freq; - retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, - trace_config->pin_protocol, - trace_config->port_size, - &trace_config->trace_freq); - if (retval != ERROR_OK) - return retval; - } - retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size); if (retval != ERROR_OK) return retval; diff --git a/src/target/armv8.c b/src/target/armv8.c index e7369372a..61f11f24a 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1131,8 +1131,9 @@ int armv8_aarch64_state(struct target *target) return ERROR_FAIL; } - LOG_USER("target halted in %s state due to %s, current mode: %s\n" + LOG_USER("%s halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%" PRIx64 "%s", + target_name(target), armv8_state_strings[arm->core_state], debug_reason_name(target), armv8_mode_name(arm->core_mode), @@ -1753,7 +1754,8 @@ const struct command_registration armv8_command_handlers[] = { const char *armv8_get_gdb_arch(struct target *target) { - return "aarch64"; + struct arm *arm = target_to_arm(target); + return arm->core_state == ARM_STATE_AARCH64 ? "aarch64" : "arm"; } int armv8_get_gdb_reg_list(struct target *target, diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 081eed21b..a3edb7f47 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -681,6 +681,10 @@ static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); } } + + if (retval != ERROR_OK) + LOG_ERROR("Failed to read %s register", r->name); + return retval; } @@ -720,6 +724,9 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } } + if (retval != ERROR_OK) + LOG_ERROR("Failed to write %s register", r->name); + return retval; } @@ -1464,10 +1471,10 @@ int armv8_dpm_setup(struct arm_dpm *dpm) /* FIXME add vector catch support */ dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf); - dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); + dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp)); dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf); - dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); + dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp)); if (!dpm->dbp || !dpm->dwp) { free(dpm->dbp); diff --git a/src/target/armv8_opcodes.c b/src/target/armv8_opcodes.c index 6887b2953..96db72871 100644 --- a/src/target/armv8_opcodes.c +++ b/src/target/armv8_opcodes.c @@ -68,13 +68,13 @@ static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { [ARMV8_OPC_DCCISW] = ARMV4_5_MCR(15, 0, 0, 7, 14, 2), [ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1), [ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1), - [ARMV8_OPC_HLT] = ARMV8_HLT_A1(11), - [ARMV8_OPC_LDRB_IP] = ARMV4_5_LDRB_IP(1, 0), - [ARMV8_OPC_LDRH_IP] = ARMV4_5_LDRH_IP(1, 0), - [ARMV8_OPC_LDRW_IP] = ARMV4_5_LDRW_IP(1, 0), - [ARMV8_OPC_STRB_IP] = ARMV4_5_STRB_IP(1, 0), - [ARMV8_OPC_STRH_IP] = ARMV4_5_STRH_IP(1, 0), - [ARMV8_OPC_STRW_IP] = ARMV4_5_STRW_IP(1, 0), + [ARMV8_OPC_HLT] = ARMV8_HLT_T1(11), + [ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP_T3(1, 0), + [ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP_T3(1, 0), + [ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP_T3(1, 0), + [ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP_T3(1, 0), + [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP_T3(1, 0), + [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP_T3(1, 0), }; void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64) diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 3fda29668..239c4c5f1 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -153,6 +153,7 @@ #define ARMV8_BKPT(Im) (0xD4200000 | ((Im & 0xffff) << 5)) #define ARMV8_HLT(Im) (0x0D4400000 | ((Im & 0xffff) << 5)) #define ARMV8_HLT_A1(Im) (0xE1000070 | ((Im & 0xFFF0) << 4) | (Im & 0xF)) +#define ARMV8_HLT_T1(Im) (0xba80 | (Im & 0x3f)) #define ARMV8_MOVFSP_64(Rt) ((1 << 31) | 0x11000000 | (0x1f << 5) | (Rt)) #define ARMV8_MOVTSP_64(Rt) ((1 << 31) | 0x11000000 | (Rt << 5) | (0x1F)) @@ -163,10 +164,18 @@ #define ARMV8_LDRH_IP(Rd, Rn) (0x78402400 | (Rn << 5) | Rd) #define ARMV8_LDRW_IP(Rd, Rn) (0xb8404400 | (Rn << 5) | Rd) +#define ARMV8_LDRB_IP_T3(Rd, Rn) (0xf8100b01 | (Rn << 16) | (Rd << 12)) +#define ARMV8_LDRH_IP_T3(Rd, Rn) (0xf8300b02 | (Rn << 16) | (Rd << 12)) +#define ARMV8_LDRW_IP_T3(Rd, Rn) (0xf8500b04 | (Rn << 16) | (Rd << 12)) + #define ARMV8_STRB_IP(Rd, Rn) (0x38001400 | (Rn << 5) | Rd) #define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd) #define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd) +#define ARMV8_STRB_IP_T3(Rd, Rn) (0xf8000b01 | (Rn << 16) | (Rd << 12)) +#define ARMV8_STRH_IP_T3(Rd, Rn) (0xf8200b02 | (Rn << 16) | (Rd << 12)) +#define ARMV8_STRW_IP_T3(Rd, Rn) (0xf8400b04 | (Rn << 16) | (Rd << 12)) + #define ARMV8_MOV_GPR_VFP(Rd, Rn, Index) (0x4e083c00 | (Index << 20) | (Rn << 5) | Rd) #define ARMV8_MOV_VFP_GPR(Rd, Rn, Index) (0x4e081c00 | (Index << 20) | (Rn << 5) | Rd) diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index cf08e3ab9..622105913 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -464,7 +464,6 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, break; case 1: return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); - break; default: break; } @@ -505,7 +504,6 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, break; case 1: return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); - break; default: break; } diff --git a/src/target/avr32_jtag.c b/src/target/avr32_jtag.c index 6526810e2..64ebf12ba 100644 --- a/src/target/avr32_jtag.c +++ b/src/target/avr32_jtag.c @@ -35,7 +35,7 @@ static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { do { struct scan_field field; - uint8_t t[4]; + uint8_t t[4] = { 0 }; uint8_t ret[4]; field.num_bits = tap->ir_length; @@ -173,19 +173,15 @@ int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_READ); - avr32_jtag_nexus_read_data(jtag_info, value); - - return ERROR_OK; - + return avr32_jtag_nexus_read_data(jtag_info, value); } + int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_WRITE); - avr32_jtag_nexus_write_data(jtag_info, value); - - return ERROR_OK; + return avr32_jtag_nexus_write_data(jtag_info, value); } int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, @@ -373,4 +369,3 @@ int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits) return ERROR_OK; } - diff --git a/src/target/avrt.c b/src/target/avrt.c index 1e1898c7e..9cb6f2f34 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -145,7 +145,7 @@ static int avr_deassert_reset(struct target *target) return ERROR_OK; } -int avr_jtag_senddat(struct jtag_tap *tap, uint32_t* dr_in, uint32_t dr_out, +int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len) { return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1); diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index b23b37f68..46c980572 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -334,6 +334,18 @@ static int breakpoint_remove_internal(struct target *target, target_addr_t addre return 0; } } + +static void breakpoint_remove_all_internal(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + while (breakpoint) { + struct breakpoint *tmp = breakpoint; + breakpoint = breakpoint->next; + breakpoint_free(target, tmp); + } +} + void breakpoint_remove(struct target *target, target_addr_t address) { int found = 0; @@ -352,7 +364,23 @@ void breakpoint_remove(struct target *target, target_addr_t address) breakpoint_remove_internal(target, address); } -void breakpoint_clear_target_internal(struct target *target) +void breakpoint_remove_all(struct target *target) +{ + if (target->smp) { + struct target_list *head; + struct target *curr; + head = target->head; + while (head != (struct target_list *)NULL) { + curr = head->target; + breakpoint_remove_all_internal(curr); + head = head->next; + } + } else { + breakpoint_remove_all_internal(target); + } +} + +static void breakpoint_clear_target_internal(struct target *target) { LOG_DEBUG("Delete all breakpoints for target: %s", target_name(target)); diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 51bd05abd..20faf4e6c 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -63,6 +63,7 @@ int context_breakpoint_add(struct target *target, int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); void breakpoint_remove(struct target *target, target_addr_t address); +void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index b3a8a41d0..f562a7614 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -425,6 +425,27 @@ static int cortex_a_instr_write_data_dcc(struct arm_dpm *dpm, &dscr); } +static int cortex_a_instr_write_data_rt_dcc(struct arm_dpm *dpm, + uint8_t rt, uint32_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + if (rt > 15) + return ERROR_TARGET_INVALID; + + retval = cortex_a_write_dcc(a, data); + if (retval != ERROR_OK) + return retval; + + /* DCCRX to Rt, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ + return cortex_a_exec_opcode( + a->armv7a_common.arm.target, + ARMV4_5_MRC(14, 0, rt, 0, 5, 0), + &dscr); +} + static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { @@ -432,15 +453,7 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, uint32_t dscr = DSCR_INSTR_COMP; int retval; - retval = cortex_a_write_dcc(a, data); - if (retval != ERROR_OK) - return retval; - - /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ - retval = cortex_a_exec_opcode( - a->armv7a_common.arm.target, - ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data); if (retval != ERROR_OK) return retval; @@ -482,6 +495,25 @@ static int cortex_a_instr_read_data_dcc(struct arm_dpm *dpm, return cortex_a_read_dcc(a, data, &dscr); } +static int cortex_a_instr_read_data_rt_dcc(struct arm_dpm *dpm, + uint8_t rt, uint32_t *data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + if (rt > 15) + return ERROR_TARGET_INVALID; + + retval = cortex_a_exec_opcode( + a->armv7a_common.arm.target, + ARMV4_5_MCR(14, 0, rt, 0, 5, 0), + &dscr); + if (retval != ERROR_OK) + return retval; + + return cortex_a_read_dcc(a, data, &dscr); +} static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) @@ -499,14 +531,7 @@ static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, return retval; /* write R0 to DCC */ - retval = cortex_a_exec_opcode( - a->armv7a_common.arm.target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - - return cortex_a_read_dcc(a, data, &dscr); + return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, @@ -1678,6 +1703,7 @@ static int cortex_a_assert_reset(struct target *target) static int cortex_a_deassert_reset(struct target *target) { + struct armv7a_common *armv7a = target_to_armv7a(target); int retval; LOG_DEBUG(" "); @@ -1696,7 +1722,8 @@ static int cortex_a_deassert_reset(struct target *target) LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); if (target_was_examined(target)) { - retval = target_halt(target); + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; } else @@ -1893,7 +1920,8 @@ static int cortex_a_write_cpu_memory_slow(struct target *target, { /* Writes count objects of size size from *buffer. Old value of DSCR must * be in *dscr; updated to new value. This is slow because it works for - * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and + * non-word-sized objects. Avoid unaligned accesses as they do not work + * on memory address space without "Normal" attribute. If size == 4 and * the address is aligned, cortex_a_write_cpu_memory_fast should be * preferred. * Preconditions: @@ -2050,7 +2078,22 @@ static int cortex_a_write_cpu_memory(struct target *target, /* We are doing a word-aligned transfer, so use fast mode. */ retval = cortex_a_write_cpu_memory_fast(target, count, buffer, &dscr); } else { - /* Use slow path. */ + /* Use slow path. Adjust size for aligned accesses */ + switch (address % 4) { + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + case 0: + default: + break; + } retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2136,7 +2179,8 @@ static int cortex_a_read_cpu_memory_slow(struct target *target, { /* Reads count objects of size size into *buffer. Old value of DSCR must be * in *dscr; updated to new value. This is slow because it works for - * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and + * non-word-sized objects. Avoid unaligned accesses as they do not work + * on memory address space without "Normal" attribute. If size == 4 and * the address is aligned, cortex_a_read_cpu_memory_fast should be * preferred. * Preconditions: @@ -2352,7 +2396,23 @@ static int cortex_a_read_cpu_memory(struct target *target, /* We are doing a word-aligned transfer, so use fast mode. */ retval = cortex_a_read_cpu_memory_fast(target, count, buffer, &dscr); } else { - /* Use slow path. */ + /* Use slow path. Adjust size for aligned accesses */ + switch (address % 4) { + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; + } retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2620,7 +2680,7 @@ static int cortex_a_examine_first(struct target *target) int i; int retval = ERROR_OK; - uint32_t didr, cpuid, dbg_osreg; + uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1; /* Search for the APB-AP - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); @@ -2660,6 +2720,10 @@ static int cortex_a_examine_first(struct target *target) } else armv7a->debug_base = target->dbgbase; + if ((armv7a->debug_base & (1UL<<31)) == 0) + LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n" + "Please fix the target configuration.", target_name(target)); + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DIDR, &didr); if (retval != ERROR_OK) { @@ -2725,7 +2789,25 @@ static int cortex_a_examine_first(struct target *target) } } - armv7a->arm.core_type = ARM_MODE_MON; + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_ID_PFR1, &dbg_idpfr1); + if (retval != ERROR_OK) + return retval; + + if (dbg_idpfr1 & 0x000000f0) { + LOG_DEBUG("target->coreid %" PRId32 " has security extensions", + target->coreid); + armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT; + } + if (dbg_idpfr1 & 0x0000f000) { + LOG_DEBUG("target->coreid %" PRId32 " has virtualization extensions", + target->coreid); + /* + * overwrite and simplify the checks. + * virtualization extensions require implementation of security extension + */ + armv7a->arm.core_type = ARM_CORE_TYPE_VIRT_EXT; + } /* Avoid recreating the registers cache */ if (!target_was_examined(target)) { @@ -2877,6 +2959,7 @@ static void cortex_a_deinit_target(struct target *target) } free(cortex_a->brp_list); + arm_free_reg_cache(dpm->arm); free(dpm->dbp); free(dpm->dwp); free(target->private_config); diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 7f59401b1..d9bee0e53 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -129,7 +129,7 @@ static int cortex_m_write_debug_halt_mask(struct target *target, struct armv7m_common *armv7m = &cortex_m->armv7m; /* mask off status bits */ - cortex_m->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off); + cortex_m->dcb_dhcsr &= ~((0xFFFFul << 16) | mask_off); /* create new register mask */ cortex_m->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on; @@ -710,11 +710,11 @@ static int cortex_m_soft_reset_halt(struct target *target) uint32_t dcb_dhcsr = 0; int retval, timeout = 0; - /* soft_reset_halt is deprecated on cortex_m as the same functionality - * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset' - * As this reset only used VC_CORERESET it would only ever reset the cortex_m + /* on single cortex_m MCU soft_reset_halt should be avoided as same functionality + * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. + * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ - LOG_WARNING("soft_reset_halt is deprecated, please use 'reset halt' instead."); + LOG_DEBUG("soft_reset_halt is discouraged, please use 'reset halt' instead."); /* Set C_DEBUGEN */ retval = cortex_m_write_debug_halt_mask(target, 0, C_STEP | C_MASKINTS); @@ -919,7 +919,7 @@ static int cortex_m_step(struct target *target, int current, * a normal step, otherwise we have to manually step over the bkpt * instruction - as such simulate a step */ if (bkpt_inst_found == false) { - if ((cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO)) { + if (cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO) { /* Automatic ISR masking mode off: Just step over the next * instruction, with interrupts on or off as appropriate. */ cortex_m_set_maskints_for_step(target); @@ -966,8 +966,7 @@ static int cortex_m_step(struct target *target, int current, /* Re-enable interrupts if appropriate */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); cortex_m_set_maskints_for_halt(target); - } - else { + } else { /* Set a temporary break point */ if (breakpoint) { @@ -1980,7 +1979,7 @@ static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dw { struct dwt_reg_state *state; - state = calloc(1, sizeof *state); + state = calloc(1, sizeof(*state)); if (!state) return; state->addr = d->addr; @@ -2021,7 +2020,7 @@ fail0: return; } - cache = calloc(1, sizeof *cache); + cache = calloc(1, sizeof(*cache)); if (!cache) { fail1: free(cm->dwt_comparator_list); @@ -2029,7 +2028,7 @@ fail1: } cache->name = "Cortex-M DWT registers"; cache->num_regs = 2 + cm->dwt_num_comp * 3; - cache->reg_list = calloc(cache->num_regs, sizeof *cache->reg_list); + cache->reg_list = calloc(cache->num_regs, sizeof(*cache->reg_list)); if (!cache->reg_list) { free(cache); goto fail1; @@ -2231,6 +2230,19 @@ int cortex_m_examine(struct target *target) armv7m->debug_ap->tar_autoincr_block = (1 << 10); } + /* Enable debug requests */ + retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr); + if (retval != ERROR_OK) + return retval; + if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { + uint32_t dhcsr = (cortex_m->dcb_dhcsr | C_DEBUGEN) & ~(C_HALT | C_STEP | C_MASKINTS); + + retval = target_write_u32(target, DCB_DHCSR, DBGKEY | (dhcsr & 0x0000FFFFUL)); + if (retval != ERROR_OK) + return retval; + cortex_m->dcb_dhcsr = dhcsr; + } + /* Configure trace modules */ retval = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); if (retval != ERROR_OK) diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 54d7a0228..a767f93c5 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -26,6 +26,7 @@ #define OPENOCD_TARGET_CORTEX_M_H #include "armv7m.h" +#include "helper/bits.h" #define CORTEX_M_COMMON_MAGIC 0x1A451A45 @@ -50,7 +51,7 @@ #define DCB_DCRDR 0xE000EDF8 #define DCB_DEMCR 0xE000EDFC -#define DCRSR_WnR (1 << 16) +#define DCRSR_WnR BIT(16) #define DWT_CTRL 0xE0001000 #define DWT_CYCCNT 0xE0001004 @@ -86,29 +87,32 @@ #define TPIU_FFCR 0xE0040304 #define TPIU_FSCR 0xE0040308 +/* Maximum SWO prescaler value. */ +#define TPIU_ACPR_MAX_SWOSCALER 0x1fff + /* DCB_DHCSR bit and field definitions */ -#define DBGKEY (0xA05F << 16) -#define C_DEBUGEN (1 << 0) -#define C_HALT (1 << 1) -#define C_STEP (1 << 2) -#define C_MASKINTS (1 << 3) -#define S_REGRDY (1 << 16) -#define S_HALT (1 << 17) -#define S_SLEEP (1 << 18) -#define S_LOCKUP (1 << 19) -#define S_RETIRE_ST (1 << 24) -#define S_RESET_ST (1 << 25) +#define DBGKEY (0xA05Ful << 16) +#define C_DEBUGEN BIT(0) +#define C_HALT BIT(1) +#define C_STEP BIT(2) +#define C_MASKINTS BIT(3) +#define S_REGRDY BIT(16) +#define S_HALT BIT(17) +#define S_SLEEP BIT(18) +#define S_LOCKUP BIT(19) +#define S_RETIRE_ST BIT(24) +#define S_RESET_ST BIT(25) /* DCB_DEMCR bit and field definitions */ -#define TRCENA (1 << 24) -#define VC_HARDERR (1 << 10) -#define VC_INTERR (1 << 9) -#define VC_BUSERR (1 << 8) -#define VC_STATERR (1 << 7) -#define VC_CHKERR (1 << 6) -#define VC_NOCPERR (1 << 5) -#define VC_MMERR (1 << 4) -#define VC_CORERESET (1 << 0) +#define TRCENA BIT(24) +#define VC_HARDERR BIT(10) +#define VC_INTERR BIT(9) +#define VC_BUSERR BIT(8) +#define VC_STATERR BIT(7) +#define VC_CHKERR BIT(6) +#define VC_NOCPERR BIT(5) +#define VC_MMERR BIT(4) +#define VC_CORERESET BIT(0) #define NVIC_ICTR 0xE000E004 #define NVIC_ISE0 0xE000E100 @@ -125,12 +129,12 @@ #define NVIC_BFAR 0xE000ED38 /* NVIC_AIRCR bits */ -#define AIRCR_VECTKEY (0x5FA << 16) -#define AIRCR_SYSRESETREQ (1 << 2) -#define AIRCR_VECTCLRACTIVE (1 << 1) -#define AIRCR_VECTRESET (1 << 0) +#define AIRCR_VECTKEY (0x5FAul << 16) +#define AIRCR_SYSRESETREQ BIT(2) +#define AIRCR_VECTCLRACTIVE BIT(1) +#define AIRCR_VECTRESET BIT(0) /* NVIC_SHCSR bits */ -#define SHCSR_BUSFAULTENA (1 << 17) +#define SHCSR_BUSFAULTENA BIT(17) /* NVIC_DFSR bits */ #define DFSR_HALTED 1 #define DFSR_BKPT 2 @@ -140,10 +144,10 @@ #define FPCR_CODE 0 #define FPCR_LITERAL 1 -#define FPCR_REPLACE_REMAP (0 << 30) -#define FPCR_REPLACE_BKPT_LOW (1 << 30) -#define FPCR_REPLACE_BKPT_HIGH (2 << 30) -#define FPCR_REPLACE_BKPT_BOTH (3 << 30) +#define FPCR_REPLACE_REMAP (0ul << 30) +#define FPCR_REPLACE_BKPT_LOW (1ul << 30) +#define FPCR_REPLACE_BKPT_HIGH (2ul << 30) +#define FPCR_REPLACE_BKPT_BOTH (3ul << 30) struct cortex_m_fp_comparator { bool used; diff --git a/src/target/dsp563xx_once.c b/src/target/dsp563xx_once.c index fe4927ba3..624474d1b 100644 --- a/src/target/dsp563xx_once.c +++ b/src/target/dsp563xx_once.c @@ -46,7 +46,7 @@ #define JTAG_INSTR_BYPASS 0x0F /** */ -static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8_t * dr_out, int dr_len, int rti) +static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); @@ -54,19 +54,20 @@ static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8 } /** */ -static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t * dr_in, uint8_t dr_out, int dr_len, int rti) +static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t *dr_in, uint8_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, dr_in, &dr_out, dr_len, rti); } /** */ -static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t * dr_in, uint32_t dr_out, int dr_len, int rti) +static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, (uint8_t *) dr_in, (uint8_t *) &dr_out, dr_len, rti); } /** single word instruction */ -static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex) +static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, + uint8_t rw, uint8_t go, uint8_t ex) { int err; @@ -79,19 +80,19 @@ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t } /* IR and DR functions */ -static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t * ir_in, uint8_t * ir_out, int ir_len, int rti) +static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti) { jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); return ERROR_OK; } -static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out, int ir_len, int rti) +static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti) { return dsp563xx_write_ir(tap, ir_in, &ir_out, ir_len, rti); } -static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out) +static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { return dsp563xx_write_ir_u8(tap, ir_in, ir_out, tap->ir_length, 1); } @@ -195,7 +196,7 @@ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg } /** once read register with register len */ -int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data) +int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data) { int err; @@ -212,7 +213,7 @@ int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint } /** once read register */ -int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data) +int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data) { int err; diff --git a/src/target/dsp563xx_once.h b/src/target/dsp563xx_once.h index da7f5e9b8..811c08698 100644 --- a/src/target/dsp563xx_once.h +++ b/src/target/dsp563xx_once.h @@ -76,9 +76,9 @@ int dsp563xx_once_target_status(struct jtag_tap *tap); /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len); /** once read register */ -int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data); +int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data); /** once read register */ -int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data); +int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data); /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data); /** single word instruction */ diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index a50f2cd47..c74a41846 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -1731,7 +1731,12 @@ static int dsp5680xx_f_ex(struct target *t, uint16_t c, uint32_t a, uint32_t d, } /** - * Prior to the execution of any Flash module command, the Flash module Clock Divider (CLKDIV) register must be initialized. The values of this register determine the speed of the internal Flash Clock (FCLK). FCLK must be in the range of 150kHz ≤ FCLK ≤ 200kHz for proper operation of the Flash module. (Running FCLK too slowly wears out the module, while running it too fast under programs Flash leading to bit errors.) + * Prior to the execution of any Flash module command, the Flash module Clock + * Divider (CLKDIV) register must be initialized. The values of this register + * determine the speed of the internal Flash Clock (FCLK). FCLK must be in the + * range of 150kHz ≤ FCLK ≤ 200kHz for proper operation of the Flash module. + * (Running FCLK too slowly wears out the module, while running it too fast + * under programs Flash leading to bit errors.) * * @param target * @@ -1787,7 +1792,11 @@ static int set_fm_ck_div(struct target *target) } /** - * Executes the FM calculate signature command. The FM will calculate over the data from @address to @address + @words -1. The result is written to a register, then read out by this function and returned in @signature. The value @signature may be compared to the the one returned by perl_crc to verify the flash was written correctly. + * Executes the FM calculate signature command. The FM will calculate over the + * data from @address to @address + @words -1. The result is written to a + * register, then read out by this function and returned in @signature. The + * value @signature may be compared to the the one returned by perl_crc to + * verify the flash was written correctly. * * @param target * @param address Start of flash array where the signature should be calculated. diff --git a/src/target/dsp5680xx.h b/src/target/dsp5680xx.h index 842796bc7..72557cea2 100644 --- a/src/target/dsp5680xx.h +++ b/src/target/dsp5680xx.h @@ -315,7 +315,7 @@ static inline struct dsp5680xx_common *target_to_dsp5680xx(struct target * * @return */ -int dsp5680xx_f_wr(struct target *target, const uint8_t * buffer, uint32_t address, +int dsp5680xx_f_wr(struct target *target, const uint8_t *buffer, uint32_t address, uint32_t count, int is_flash_lock); /** @@ -329,7 +329,7 @@ int dsp5680xx_f_wr(struct target *target, const uint8_t * buffer, uint32_t addre * * @return */ -int dsp5680xx_f_erase_check(struct target *target, uint8_t * erased, +int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, uint32_t sector); /** @@ -354,7 +354,7 @@ int dsp5680xx_f_erase(struct target *target, int first, int last); * * @return */ -int dsp5680xx_f_protect_check(struct target *target, uint16_t * protected); +int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected); /** * Writes the flash security words with a specific value. The chip's security will be diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c index 333a62225..700ae3a60 100644 --- a/src/target/esirisc_jtag.c +++ b/src/target/esirisc_jtag.c @@ -36,7 +36,7 @@ static void esirisc_jtag_set_instr(struct esirisc_jtag *jtag_info, uint32_t new_ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; - uint8_t t[4]; + uint8_t t[4] = { 0 }; field.num_bits = tap->ir_length; field.out_value = t; diff --git a/src/target/etb.c b/src/target/etb.c index 392c6ad7f..0c03c4dbe 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -176,13 +176,13 @@ static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames) fields[0].in_value = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, 4); fields[1].in_value = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; @@ -229,7 +229,7 @@ static int etb_read_reg_w_check(struct reg *reg, fields[0].check_mask = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; @@ -237,7 +237,7 @@ static int etb_read_reg_w_check(struct reg *reg, fields[1].check_mask = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; @@ -310,13 +310,13 @@ static int etb_write_reg(struct reg *reg, uint32_t value) fields[0].in_value = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 1); fields[2].in_value = NULL; diff --git a/src/target/etm.c b/src/target/etm.c index 5751348e7..5d079ffa8 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -303,6 +303,11 @@ struct reg_cache *etm_build_reg_cache(struct target *target, reg_list = calloc(128, sizeof(struct reg)); arch_info = calloc(128, sizeof(struct etm_reg)); + if (reg_cache == NULL || reg_list == NULL || arch_info == NULL) { + LOG_ERROR("No memory"); + goto fail; + } + /* fill in values for the reg cache */ reg_cache->name = "etm registers"; reg_cache->next = NULL; @@ -498,6 +503,7 @@ static int etm_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct etm_reg *etm_reg = reg->arch_info; + assert(etm_reg); const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; @@ -527,7 +533,7 @@ static int etm_read_reg_w_check(struct reg *reg, fields[0].check_mask = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; @@ -535,7 +541,7 @@ static int etm_read_reg_w_check(struct reg *reg, fields[1].check_mask = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; @@ -614,13 +620,13 @@ static int etm_write_reg(struct reg *reg, uint32_t value) fields[0].in_value = NULL; fields[1].num_bits = 7; - uint8_t tmp2; + uint8_t tmp2 = 0; fields[1].out_value = &tmp2; buf_set_u32(&tmp2, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; - uint8_t tmp3; + uint8_t tmp3 = 0; fields[2].out_value = &tmp3; buf_set_u32(&tmp3, 0, 1, 1); fields[2].in_value = NULL; @@ -1068,8 +1074,8 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio (instruction.type == ARM_STM)) { int i; for (i = 0; i < 16; i++) { - if (instruction.info.load_store_multiple. - register_list & (1 << i)) { + if (instruction.info.load_store_multiple.register_list + & (1 << i)) { uint32_t data; if (etmv1_data(ctx, 4, &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 60ed7d64d..f0dc57276 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -25,6 +25,7 @@ #include "config.h" #endif +#include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/hla/hla_transport.h" #include "jtag/hla/hla_interface.h" @@ -499,7 +500,7 @@ static int adapter_poll(struct target *target) return ERROR_OK; } -static int adapter_assert_reset(struct target *target) +static int hl_assert_reset(struct target *target) { int res = ERROR_OK; struct hl_interface_s *adapter = target_to_adapter(target); @@ -514,8 +515,7 @@ static int adapter_assert_reset(struct target *target) if ((jtag_reset_config & RESET_HAS_SRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { - jtag_add_reset(0, 1); - res = adapter->layout->api->assert_srst(adapter->handle, 0); + res = adapter_assert_reset(); srst_asserted = true; } @@ -529,8 +529,7 @@ static int adapter_assert_reset(struct target *target) if (jtag_reset_config & RESET_HAS_SRST) { if (!srst_asserted) { - jtag_add_reset(0, 1); - res = adapter->layout->api->assert_srst(adapter->handle, 0); + res = adapter_assert_reset(); } if (res == ERROR_COMMAND_NOTFOUND) LOG_ERROR("Hardware srst not supported, falling back to software reset"); @@ -563,21 +562,14 @@ static int adapter_assert_reset(struct target *target) return ERROR_OK; } -static int adapter_deassert_reset(struct target *target) +static int hl_deassert_reset(struct target *target) { - struct hl_interface_s *adapter = target_to_adapter(target); - enum reset_types jtag_reset_config = jtag_get_reset_config(); LOG_DEBUG("%s", __func__); if (jtag_reset_config & RESET_HAS_SRST) - adapter->layout->api->assert_srst(adapter->handle, 1); - - /* virtual deassert reset, we need it for the internal - * jtag state machine - */ - jtag_add_reset(0, 0); + adapter_deassert_reset(); target->savedDCRDR = 0; /* clear both DCC busy bits on initial resume */ @@ -819,8 +811,8 @@ struct target_type hla_target = { .arch_state = armv7m_arch_state, .target_request_data = hl_target_request_data, - .assert_reset = adapter_assert_reset, - .deassert_reset = adapter_deassert_reset, + .assert_reset = hl_assert_reset, + .deassert_reset = hl_deassert_reset, .halt = adapter_halt, .resume = adapter_resume, diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index bc46ed4db..330042f00 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -113,7 +113,7 @@ static void ls1_sap_set_instr(struct jtag_tap *tap, uint32_t new_instr) static void ls1_sap_set_addr_high(struct jtag_tap *tap, uint16_t addr_high) { struct scan_field field; - uint8_t buf[2]; + uint8_t buf[2] = { 0 }; ls1_sap_set_instr(tap, 0x21); @@ -130,7 +130,7 @@ static void ls1_sap_memory_cmd(struct jtag_tap *tap, uint32_t address, int32_t size, bool rnw) { struct scan_field field; - uint8_t cmd[8]; + uint8_t cmd[8] = { 0 }; ls1_sap_set_instr(tap, 0x24); diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 29cd37a90..ade48b6d7 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -65,6 +65,15 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta return ERROR_OK; } +static void mem_ap_deinit_target(struct target *target) +{ + LOG_DEBUG("%s", __func__); + + free(target->private_config); + free(target->arch_info); + return; +} + static int mem_ap_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); @@ -169,6 +178,7 @@ struct target_type mem_ap_target = { .target_create = mem_ap_target_create, .init_target = mem_ap_init_target, + .deinit_target = mem_ap_deinit_target, .examine = mem_ap_examine, .target_jim_configure = adiv5_jim_configure, diff --git a/src/target/mips64.c b/src/target/mips64.c new file mode 100644 index 000000000..6a7c4252b --- /dev/null +++ b/src/target/mips64.c @@ -0,0 +1,623 @@ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014 by Antony Pavlov + * Copyright (C) 2014 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mips64.h" + +static const struct { + unsigned id; + const char *name; + enum reg_type type; + const char *group; + const char *feature; + int flag; +} mips64_regs[] = { + { 0, "r0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 1, "r1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 2, "r2", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 3, "r3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 4, "r4", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 5, "r5", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 6, "r6", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 7, "r7", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 8, "r8", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 9, "r9", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 10, "r10", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 11, "r11", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 12, "r12", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 13, "r13", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 14, "r14", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 15, "r15", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 16, "r16", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 17, "r17", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 18, "r18", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 19, "r19", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 20, "r20", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 21, "r21", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 22, "r22", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 23, "r23", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 24, "r24", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 25, "r25", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 26, "r26", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 27, "r27", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 28, "r28", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 29, "r29", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 30, "r30", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 31, "r31", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 32, "lo", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 33, "hi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { MIPS64_NUM_CORE_REGS + 0, "pc", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cpu", 0 }, + { MIPS64_NUM_CORE_REGS + 1, "Random", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 2, "Entrylo_0", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 3, "Entrylo_1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 4, "Context", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 5, "Pagemask", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 6, "Wired", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 7, "badvaddr", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 8, "Count", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 9, "EntryHi", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 10, "Compare", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 11, "status", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 12, "cause", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 13, "EPC", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 14, "PrID", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 15, "Config", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 16, "LLA", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 17, "WatchLo0", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 18, "WatchLo1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 19, "WatchHi0", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 20, "WatchHi1", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 21, "Xcontext", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 22, "ChipMemCtrl", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 23, "Debug", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 24, "Perfcount, sel=0", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 25, "Perfcount, sel=1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 26, "Perfcount, sel=2", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 27, "Perfcount, sel=3", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 28, "ECC", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 29, "CacheErr", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 30, "TagLo", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 31, "TagHi", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 32, "DataHi", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 33, "EEPC", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 32, "fcsr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 33, "fir", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 34, "fconfig", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 35, "fccr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 36, "fexr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 37, "fenr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, +}; + +static int reg_type2size(enum reg_type type) +{ + switch (type) { + case REG_TYPE_UINT32: + case REG_TYPE_INT: + return 32; + case REG_TYPE_UINT64: + case REG_TYPE_IEEE_DOUBLE: + return 64; + default: + return 64; + } +} + +static int mips64_get_core_reg(struct reg *reg) +{ + int retval; + struct mips64_core_reg *mips64_reg = reg->arch_info; + struct target *target = mips64_reg->target; + struct mips64_common *mips64_target = target->arch_info; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = mips64_target->read_core_reg(target, mips64_reg->num); + + return retval; +} + +static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct mips64_core_reg *mips64_reg = reg->arch_info; + struct target *target = mips64_reg->target; + uint64_t value = buf_get_u64(buf, 0, 64); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u64(reg->value, 0, 64, value); + reg->dirty = 1; + reg->valid = 1; + + return ERROR_OK; +} + +static int mips64_read_core_reg(struct target *target, int num) +{ + uint64_t reg_value; + + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + + if ((num < 0) || (num >= MIPS64_NUM_REGS)) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg_value = mips64->core_regs[num]; + buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); + mips64->core_cache->reg_list[num].valid = 1; + mips64->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +static int mips64_write_core_reg(struct target *target, int num) +{ + uint64_t reg_value; + + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + + if ((num < 0) || (num >= MIPS64_NUM_REGS)) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); + mips64->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num , reg_value); + mips64->core_cache->reg_list[num].valid = 1; + mips64->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +int mips64_invalidate_core_regs(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + unsigned int i; + + for (i = 0; i < mips64->core_cache->num_regs; i++) { + mips64->core_cache->reg_list[i].valid = 0; + mips64->core_cache->reg_list[i].dirty = 0; + } + + return ERROR_OK; +} + + +int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + register int i; + + /* include floating point registers */ + *reg_list_size = MIPS64_NUM_REGS; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < MIPS64_NUM_REGS; i++) + (*reg_list)[i] = &mips64->core_cache->reg_list[i]; + + return ERROR_OK; +} + +int mips64_save_context(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + retval = mips64_pracc_read_regs(ejtag_info, mips64->core_regs); + if (retval != ERROR_OK) + return retval; + + for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) + retval = mips64->read_core_reg(target, i); + + return retval; +} + +int mips64_restore_context(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) { + if (mips64->core_cache->reg_list[i].dirty) + mips64->write_core_reg(target, i); + } + + return mips64_pracc_write_regs(ejtag_info, mips64->core_regs); +} + +int mips64_arch_state(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + + if (mips64->common_magic != MIPS64_COMMON_MAGIC) { + LOG_ERROR("BUG: called for a non-MIPS64 target"); + exit(-1); + } + + LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "", + debug_reason_name(target), buf_get_u64(pc->value, 0, 64)); + + return ERROR_OK; +} + +static const struct reg_arch_type mips64_reg_type = { + .get = mips64_get_core_reg, + .set = mips64_set_core_reg, +}; + +int mips64_build_reg_cache(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct reg_cache **cache_p, *cache; + struct mips64_core_reg *arch_info = NULL; + struct reg *reg_list = NULL; + unsigned i; + + cache = calloc(1, sizeof(*cache)); + if (!cache) { + LOG_ERROR("unable to allocate cache"); + return ERROR_FAIL; + } + + reg_list = calloc(MIPS64_NUM_REGS, sizeof(*reg_list)); + if (!reg_list) { + LOG_ERROR("unable to allocate reg_list"); + goto alloc_fail; + } + + arch_info = calloc(MIPS64_NUM_REGS, sizeof(*arch_info)); + if (!arch_info) { + LOG_ERROR("unable to allocate arch_info"); + goto alloc_fail; + } + + for (i = 0; i < MIPS64_NUM_REGS; i++) { + struct mips64_core_reg *a = &arch_info[i]; + struct reg *r = ®_list[i]; + + r->arch_info = &arch_info[i]; + r->caller_save = true; /* gdb defaults to true */ + r->exist = true; + r->feature = &a->feature; + r->feature->name = mips64_regs[i].feature; + r->group = mips64_regs[i].group; + r->name = mips64_regs[i].name; + r->number = i; + r->reg_data_type = &a->reg_data_type; + r->reg_data_type->type = mips64_regs[i].type; + r->size = reg_type2size(mips64_regs[i].type); + r->type = &mips64_reg_type; + r->value = &a->value[0]; + + a->mips64_common = mips64; + a->num = mips64_regs[i].id; + a->target = target; + } + + cache->name = "mips64 registers"; + cache->reg_list = reg_list; + cache->num_regs = MIPS64_NUM_REGS; + + cache_p = register_get_last_cache_p(&target->reg_cache); + (*cache_p) = cache; + + mips64->core_cache = cache; + + return ERROR_OK; + +alloc_fail: + free(cache); + free(reg_list); + free(arch_info); + + return ERROR_FAIL; +} + +int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, + struct jtag_tap *tap) +{ + mips64->bp_scanned = false; + mips64->common_magic = MIPS64_COMMON_MAGIC; + mips64->data_break_list = NULL; + mips64->ejtag_info.tap = tap; + mips64->fast_data_area = NULL; + mips64->mips64mode32 = false; + mips64->read_core_reg = mips64_read_core_reg; + mips64->write_core_reg = mips64_write_core_reg; + + return ERROR_OK; +} + +int mips64_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + /* TODO */ + return ERROR_OK; +} + +int mips64_examine(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + + if (target_was_examined(target)) + return ERROR_OK; + + /* TODO: why we do not do mips64_configure_break_unit() here? */ + mips64->bp_scanned = false; + mips64->num_data_bpoints = 0; + mips64->num_data_bpoints_avail = 0; + mips64->num_inst_bpoints = 0; + mips64->num_inst_bpoints_avail = 0; + + target_set_examined(target); + + return ERROR_OK; +} + +static int mips64_configure_i_break_unit(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *ibl; + uint64_t bpinfo; + int retval; + int i; + + /* get number of inst breakpoints */ + retval = target_read_u64(target, EJTAG64_V25_IBS, &bpinfo); + if (retval != ERROR_OK) + return retval; + + mips64->num_inst_bpoints = (bpinfo >> 24) & 0x0F; + mips64->num_inst_bpoints_avail = mips64->num_inst_bpoints; + ibl = calloc(mips64->num_inst_bpoints, sizeof(*ibl)); + if (!ibl) { + LOG_ERROR("unable to allocate inst_break_list"); + return ERROR_FAIL; + } + + for (i = 0; i < mips64->num_inst_bpoints; i++) + ibl[i].reg_address = EJTAG64_V25_IBA0 + (0x100 * i); + + mips64->inst_break_list = ibl; + /* clear IBIS reg */ + retval = target_write_u64(target, EJTAG64_V25_IBS, 0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int mips64_configure_d_break_unit(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *dbl; + uint64_t bpinfo; + int retval; + int i; + + /* get number of data breakpoints */ + retval = target_read_u64(target, EJTAG64_V25_DBS, &bpinfo); + if (retval != ERROR_OK) + return retval; + + mips64->num_data_bpoints = (bpinfo >> 24) & 0x0F; + mips64->num_data_bpoints_avail = mips64->num_data_bpoints; + + dbl = calloc(mips64->num_data_bpoints, sizeof(*dbl)); + + if (!dbl) { + LOG_ERROR("unable to allocate data_break_list"); + return ERROR_FAIL; + } + + for (i = 0; i < mips64->num_data_bpoints; i++) + dbl[i].reg_address = EJTAG64_V25_DBA0 + (0x100 * i); + + mips64->data_break_list = dbl; + + /* clear DBIS reg */ + retval = target_write_u64(target, EJTAG64_V25_DBS, 0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +int mips64_configure_break_unit(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + uint64_t dcr; + int retval; + + if (mips64->bp_scanned) + return ERROR_OK; + + /* get info about breakpoint support */ + retval = target_read_u64(target, EJTAG64_DCR, &dcr); + if (retval != ERROR_OK) + return retval; + + if (dcr & EJTAG64_DCR_IB) { + retval = mips64_configure_i_break_unit(target); + if (retval != ERROR_OK) + return retval; + } + + if (dcr & EJTAG64_DCR_DB) { + retval = mips64_configure_d_break_unit(target); + if (retval != ERROR_OK) + return retval; + } + + LOG_DEBUG("DCR 0x%" PRIx64 " numinst %i numdata %i", dcr, + mips64->num_inst_bpoints, mips64->num_data_bpoints); + + mips64->bp_scanned = true; + + return ERROR_OK; +} + +int mips64_enable_interrupts(struct target *target, bool enable) +{ + int retval; + bool update = false; + uint64_t dcr; + + /* read debug control register */ + retval = target_read_u64(target, EJTAG64_DCR, &dcr); + if (retval != ERROR_OK) + return retval; + + if (enable) { + if (!(dcr & EJTAG64_DCR_INTE)) { + /* enable interrupts */ + dcr |= EJTAG64_DCR_INTE; + update = true; + } + } else { + if (dcr & EJTAG64_DCR_INTE) { + /* disable interrupts */ + dcr &= ~(uint64_t)EJTAG64_DCR_INTE; + update = true; + } + } + + if (update) { + retval = target_write_u64(target, EJTAG64_DCR, dcr); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} diff --git a/src/target/mips64.h b/src/target/mips64.h new file mode 100644 index 000000000..3453e4ed1 --- /dev/null +++ b/src/target/mips64.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + */ + +#ifndef OPENOCD_TARGET_MIPS64_H +#define OPENOCD_TARGET_MIPS64_H + +#include "target.h" +#include "register.h" +#include "mips64_pracc.h" + +#define MIPS64_COMMON_MAGIC 0xB640B640 + +/* MIPS64 CP0 registers */ +#define MIPS64_C0_INDEX 0 +#define MIPS64_C0_RANDOM 1 +#define MIPS64_C0_ENTRYLO0 2 +#define MIPS64_C0_ENTRYLO1 3 +#define MIPS64_C0_CONTEXT 4 +#define MIPS64_C0_PAGEMASK 5 +#define MIPS64_C0_WIRED 6 +#define MIPS64_C0_BADVADDR 8 +#define MIPS64_C0_COUNT 9 +#define MIPS64_C0_ENTRYHI 10 +#define MIPS64_C0_COMPARE 11 +#define MIPS64_C0_STATUS 12 +#define MIPS64_C0_CAUSE 13 +#define MIPS64_C0_EPC 14 +#define MIPS64_C0_PRID 15 +#define MIPS64_C0_CONFIG 16 +#define MIPS64_C0_LLA 17 +#define MIPS64_C0_WATCHLO 18 +#define MIPS64_C0_WATCHHI 19 +#define MIPS64_C0_XCONTEXT 20 +#define MIPS64_C0_MEMCTRL 22 +#define MIPS64_C0_DEBUG 23 +#define MIPS64_C0_DEPC 24 +#define MIPS64_C0_PERFCOUNT 25 +#define MIPS64_C0_ECC 26 +#define MIPS64_C0_CACHERR 27 +#define MIPS64_C0_TAGLO 28 +#define MIPS64_C0_TAGHI 29 +#define MIPS64_C0_DATAHI 29 +#define MIPS64_C0_EEPC 30 + +/* MIPS64 CP1 registers */ +#define MIPS64_C1_FIR 0 +#define MIPS64_C1_FCONFIG 24 +#define MIPS64_C1_FCSR 31 +#define MIPS64_C1_FCCR 25 +#define MIPS64_C1_FEXR 26 +#define MIPS64_C1_FENR 28 + +/* offsets into mips64 register cache */ +#define MIPS64_NUM_CORE_REGS 34 +#define MIPS64_NUM_C0_REGS 34 +#define MIPS64_NUM_FP_REGS 38 + +#define MIPS64_NUM_REGS (MIPS64_NUM_CORE_REGS + \ + MIPS64_NUM_C0_REGS + \ + MIPS64_NUM_FP_REGS) + +#define MIPS64_NUM_CORE_C0_REGS (MIPS64_NUM_CORE_REGS + MIPS64_NUM_C0_REGS) + +#define MIPS64_PC MIPS64_NUM_CORE_REGS + +struct mips64_comparator { + bool used; + uint64_t bp_value; + uint64_t reg_address; +}; + +struct mips64_common { + uint32_t common_magic; + void *arch_info; + struct reg_cache *core_cache; + struct mips_ejtag ejtag_info; + uint64_t core_regs[MIPS64_NUM_REGS]; + + struct working_area *fast_data_area; + + bool bp_scanned; + int num_inst_bpoints; + int num_data_bpoints; + int num_inst_bpoints_avail; + int num_data_bpoints_avail; + struct mips64_comparator *inst_break_list; + struct mips64_comparator *data_break_list; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, int num); + int (*write_core_reg)(struct target *target, int num); + + bool mips64mode32; +}; + +struct mips64_core_reg { + uint32_t num; + struct target *target; + struct mips64_common *mips64_common; + uint8_t value[8]; + struct reg_feature feature; + struct reg_data_type reg_data_type; +}; + +#define MIPS64_OP_SRL 0x02 +#define MIPS64_OP_BEQ 0x04 +#define MIPS64_OP_BNE 0x05 +#define MIPS64_OP_ADDI 0x08 +#define MIPS64_OP_ANDI 0x0c +#define MIPS64_OP_DADDI 0x18 +#define MIPS64_OP_DADDIU 0x19 +#define MIPS64_OP_AND 0x24 +#define MIPS64_OP_LUI 0x0F +#define MIPS64_OP_LW 0x23 +#define MIPS64_OP_LD 0x37 +#define MIPS64_OP_LBU 0x24 +#define MIPS64_OP_LHU 0x25 +#define MIPS64_OP_MFHI 0x10 +#define MIPS64_OP_MTHI 0x11 +#define MIPS64_OP_MFLO 0x12 +#define MIPS64_OP_MTLO 0x13 +#define MIPS64_OP_SB 0x28 +#define MIPS64_OP_SH 0x29 +#define MIPS64_OP_SW 0x2B +#define MIPS64_OP_SD 0x3F +#define MIPS64_OP_ORI 0x0D +#define MIPS64_OP_JR 0x08 + +#define MIPS64_OP_COP0 0x10 +#define MIPS64_OP_COP1 0x11 +#define MIPS64_OP_COP2 0x12 + +#define MIPS64_COP_MF 0x00 +#define MIPS64_COP_DMF 0x01 +#define MIPS64_COP_MT 0x04 +#define MIPS64_COP_DMT 0x05 +#define MIPS64_COP_CF 0x02 +#define MIPS64_COP_CT 0x06 + +#define MIPS64_R_INST(opcode, rs, rt, rd, shamt, funct) \ +(((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) +#define MIPS64_I_INST(opcode, rs, rt, immd) (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) +#define MIPS64_J_INST(opcode, addr) (((opcode) << 26) | (addr)) + +#define MIPS64_NOP 0 +#define MIPS64_ADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_ADDI, src, tar, val) +#define MIPS64_DADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDI, src, tar, val) +#define MIPS64_DADDIU(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDIU, src, tar, val) +#define MIPS64_AND(reg, off, val) MIPS64_R_INST(0, off, val, reg, 0, MIPS64_OP_AND) +#define MIPS64_ANDI(d, s, im) MIPS64_I_INST(MIPS64_OP_ANDI, s, d, im) +#define MIPS64_SRL(d, w, sh) MIPS64_R_INST(0, 0, w, d, sh, MIPS64_OP_SRL) +#define MIPS64_B(off) MIPS64_BEQ(0, 0, off) +#define MIPS64_BEQ(src, tar, off) MIPS64_I_INST(MIPS64_OP_BEQ, src, tar, off) +#define MIPS64_BNE(src, tar, off) MIPS64_I_INST(MIPS64_OP_BNE, src, tar, off) +#define MIPS64_MFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MF, gpr, cpr, 0, sel) +#define MIPS64_DMFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMF, gpr, cpr, 0, sel) +#define MIPS64_MTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MT, gpr, cpr, 0, sel) +#define MIPS64_DMTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMT, gpr, cpr, 0, sel) +#define MIPS64_MFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MF, gpr, cpr, 0, 0) +#define MIPS64_DMFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMF, gpr, cpr, 0, 0) +#define MIPS64_MTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MT, gpr, cpr, 0, 0) +#define MIPS64_DMTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMT, gpr, cpr, 0, 0) +#define MIPS64_MFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MF, gpr, cpr, 0, sel) +#define MIPS64_MTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MT, gpr, cpr, 0, sel) +#define MIPS64_CFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CF, gpr, cpr, 0, 0) +#define MIPS64_CTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CT, gpr, cpr, 0, 0) +#define MIPS64_CFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CF, gpr, cpr, 0, sel) +#define MIPS64_CTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CT, gpr, cpr, 0, sel) +#define MIPS64_LBU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LBU, base, reg, off) +#define MIPS64_LHU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LHU, base, reg, off) +#define MIPS64_LUI(reg, val) MIPS64_I_INST(MIPS64_OP_LUI, 0, reg, val) +#define MIPS64_LW(reg, off, base) MIPS64_I_INST(MIPS64_OP_LW, base, reg, off) +#define MIPS64_LD(reg, off, base) MIPS64_I_INST(MIPS64_OP_LD, base, reg, off) +#define MIPS64_MFLO(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFLO) +#define MIPS64_MFHI(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFHI) +#define MIPS64_MTLO(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTLO) +#define MIPS64_MTHI(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTHI) +#define MIPS64_ORI(src, tar, val) MIPS64_I_INST(MIPS64_OP_ORI, src, tar, val) +#define MIPS64_SB(reg, off, base) MIPS64_I_INST(MIPS64_OP_SB, base, reg, off) +#define MIPS64_SH(reg, off, base) MIPS64_I_INST(MIPS64_OP_SH, base, reg, off) +#define MIPS64_SW(reg, off, base) MIPS64_I_INST(MIPS64_OP_SW, base, reg, off) +#define MIPS64_SD(reg, off, base) MIPS64_I_INST(MIPS64_OP_SD, base, reg, off) +#define MIPS64_CACHE(op, reg, off) (47 << 26 | (reg) << 21 | (op) << 16 | (off)) +#define MIPS64_SYNCI(reg, off) (1 << 26 | (reg) << 21 | 0x1f << 16 | (off)) +#define MIPS64_JR(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_JR) + +/* ejtag specific instructions */ +#define MIPS64_DRET 0x4200001F +#define MIPS64_SDBBP 0x7000003F +#define MIPS64_SDBBP_LE 0x3f000007 +#define MIPS64_SDBBP_SIZE 4 +#define MIPS16_SDBBP_SIZE 2 + +#define MIPS64_SYNC 0x0000000F + +int mips64_arch_state(struct target *target); +int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, struct jtag_tap *tap); +int mips64_restore_context(struct target *target); +int mips64_save_context(struct target *target); +int mips64_build_reg_cache(struct target *target); +int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + int timeout_ms, void *arch_info); +int mips64_configure_break_unit(struct target *target); +int mips64_enable_interrupts(struct target *target, bool enable); +int mips64_examine(struct target *target); + +int mips64_register_commands(struct command_context *cmd_ctx); +int mips64_invalidate_core_regs(struct target *target); +int mips64_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); + +#endif /* OPENOCD_TARGET_MIPS64_H */ diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c new file mode 100644 index 000000000..b19fd044e --- /dev/null +++ b/src/target/mips64_pracc.c @@ -0,0 +1,1427 @@ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mips64.h" +#include "mips64_pracc.h" + +#include "time_support.h" + +#define STACK_DEPTH 32 + +typedef struct { + uint64_t *local_iparam; + unsigned num_iparam; + uint64_t *local_oparam; + unsigned num_oparam; + const uint32_t *code; + unsigned code_len; + uint64_t stack[STACK_DEPTH]; + unsigned stack_offset; + struct mips_ejtag *ejtag_info; +} mips64_pracc_context; + +static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) +{ + uint32_t ejtag_ctrl; + int nt = 5; + int rc; + + while (1) { + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + ejtag_ctrl = ejtag_info->ejtag_ctrl; + rc = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + if (ejtag_ctrl & EJTAG_CTRL_PRACC) + break; + LOG_DEBUG("DEBUGMODULE: No memory access in progress!\n"); + if (nt == 0) + return ERROR_JTAG_DEVICE_ERROR; + nt--; + } + + *ctrl = ejtag_ctrl; + return ERROR_OK; +} + +static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) +{ + struct mips_ejtag *ejtag_info = ctx->ejtag_info; + unsigned offset; + uint32_t ejtag_ctrl; + uint64_t data; + int rc; + + if ((address >= MIPS64_PRACC_PARAM_IN) + && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { + + offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; + + if (offset >= MIPS64_PRACC_PARAM_IN_SIZE) { + LOG_ERROR("Error: iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE"); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (ctx->local_iparam == NULL) { + LOG_ERROR("Error: unexpected reading of input parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->local_iparam[offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else if ((address >= MIPS64_PRACC_PARAM_OUT) + && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { + + offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_oparam == NULL) { + LOG_ERROR("Error: unexpected reading of output parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->local_oparam[offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else if ((address >= MIPS64_PRACC_TEXT) + && (address < MIPS64_PRACC_TEXT + ctx->code_len * MIPS64_PRACC_ADDR_STEP)) { + + offset = ((address & ~7ull) - MIPS64_PRACC_TEXT) / MIPS64_PRACC_ADDR_STEP; + data = (uint64_t)ctx->code[offset] << 32; + if (offset + 1 < ctx->code_len) + data |= (uint64_t)ctx->code[offset + 1]; + + LOG_DEBUG("Running commands %" PRIx64 " at %" PRIx64, data, + address); + + } else if ((address & ~7llu) == MIPS64_PRACC_STACK) { + + /* load from our debug stack */ + if (ctx->stack_offset == 0) { + LOG_ERROR("Error reading from stack: stack is empty"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->stack[--ctx->stack_offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else { + /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back + * to start of debug vector */ + + data = 0; + LOG_ERROR("Error reading unexpected address %" PRIx64, address); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* Send the data out */ + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); + rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); + if (rc != ERROR_OK) + return rc; + + /* Clear the access pending bit (let the processor eat!) */ + + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); + rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + jtag_add_clocks(5); + + return jtag_execute_queue(); +} + +static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) +{ + uint32_t ejtag_ctrl; + uint64_t data; + unsigned offset; + struct mips_ejtag *ejtag_info = ctx->ejtag_info; + int rc; + + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); + rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); + if (rc != ERROR_OK) + return rc; + + /* Clear access pending bit */ + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); + rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + jtag_add_clocks(5); + rc = jtag_execute_queue(); + if (rc != ERROR_OK) + return rc; + + LOG_DEBUG("Writing %" PRIx64 " at %" PRIx64, data, address); + + if ((address >= MIPS64_PRACC_PARAM_IN) + && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { + offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_iparam == NULL) { + LOG_ERROR("Error: unexpected writing of input parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + ctx->local_iparam[offset] = data; + } else if ((address >= MIPS64_PRACC_PARAM_OUT) + && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { + offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_oparam == NULL) { + LOG_ERROR("Error: unexpected writing of output parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + ctx->local_oparam[offset] = data; + } else if (address == MIPS64_PRACC_STACK) { + /* save data onto our stack */ + if (ctx->stack_offset >= STACK_DEPTH) { + LOG_ERROR("Error: PrAcc stack depth exceeded"); + return ERROR_FAIL; + } + ctx->stack[ctx->stack_offset++] = data; + } else { + LOG_ERROR("Error writing unexpected address 0x%" PRIx64, address); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +int mips64_pracc_exec(struct mips_ejtag *ejtag_info, + unsigned code_len, const uint32_t *code, + unsigned num_param_in, uint64_t *param_in, + unsigned num_param_out, uint64_t *param_out) +{ + uint32_t ejtag_ctrl; + uint64_t address = 0, address_prev = 0, data; + mips64_pracc_context ctx; + int retval; + int pass = 0; + bool first_time_call = true; + unsigned i; + + for (i = 0; i < code_len; i++) + LOG_DEBUG("%08x", code[i]); + + ctx.local_iparam = param_in; + ctx.local_oparam = param_out; + ctx.num_iparam = num_param_in; + ctx.num_oparam = num_param_out; + ctx.code = code; + ctx.code_len = code_len; + ctx.ejtag_info = ejtag_info; + ctx.stack_offset = 0; + + while (true) { + uint32_t address32; + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR wait_for_pracc_rw"); + return retval; + } + if (pass) + address_prev = address; + else + address_prev = 0; + address32 = data = 0; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + mips_ejtag_drscan_32(ejtag_info, &address32); + LOG_DEBUG("-> %08x", address32); + address = 0xffffffffff200000ull | address32; + + int psz = (ejtag_ctrl >> 29) & 3; + int address20 = address & 7; + switch (psz) { + case 3: + if (address20 != 7) { + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + address &= ~7ull; + break; + case 2: + if (address20 != 0 && address20 != 4) { + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + break; + default: + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + + if (first_time_call && address != MIPS64_PRACC_TEXT) { + LOG_ERROR("Error reading address " TARGET_ADDR_FMT " (0x%08llx expected)", + address, MIPS64_PRACC_TEXT); + return ERROR_JTAG_DEVICE_ERROR; + } + + first_time_call = false; + + /* Check for read or write */ + if (ejtag_ctrl & EJTAG_CTRL_PRNW) { + retval = mips64_pracc_exec_write(&ctx, address); + if (retval != ERROR_OK) { + printf("ERROR mips64_pracc_exec_write\n"); + return retval; + } + } else { + /* Check to see if its reading at the debug vector. The first pass through + * the module is always read at the vector, so the first one we allow. When + * the second read from the vector occurs we are done and just exit. */ + if ((address == MIPS64_PRACC_TEXT) && (pass++)) { + LOG_DEBUG("@MIPS64_PRACC_TEXT, address_prev=%" PRIx64, address_prev); + break; + } + retval = mips64_pracc_exec_read(&ctx, address); + if (retval != ERROR_OK) { + printf("ERROR mips64_pracc_exec_read\n"); + return retval; + } + + } + } + + /* stack sanity check */ + if (ctx.stack_offset != 0) + LOG_ERROR("Pracc Stack not zero"); + + return ERROR_OK; +} + +static int mips64_pracc_read_u64(struct mips_ejtag *ejtag_info, uint64_t addr, + uint64_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* ld $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LD(8, 0, 8), + /* sd $8, 0($15) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + uint64_t param_in[1]; + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 1, (uint64_t *) buf); +} + +static int mips64_pracc_read_mem64(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint64_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u64(ejtag_info, addr + 8*i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u32(struct mips_ejtag *ejtag_info, uint64_t addr, + uint32_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LW(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval = ERROR_OK; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint32_t) param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint32_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u32(ejtag_info, addr + 4 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u16(struct mips_ejtag *ejtag_info, uint64_t addr, + uint16_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LHU(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint16_t)param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint16_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u16(ejtag_info, addr + 2*i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u8(struct mips_ejtag *ejtag_info, uint64_t addr, + uint8_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LBU(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint8_t)param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint8_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u8(ejtag_info, addr + i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned size, unsigned count, void *buf) +{ + switch (size) { + case 1: + return mips64_pracc_read_mem8(ejtag_info, addr, count, buf); + case 2: + return mips64_pracc_read_mem16(ejtag_info, addr, count, buf); + case 4: + return mips64_pracc_read_mem32(ejtag_info, addr, count, buf); + case 8: + return mips64_pracc_read_mem64(ejtag_info, addr, count, buf); + } + return ERROR_FAIL; +} + +static int mips64_pracc_write_u64(struct mips_ejtag *ejtag_info, uint64_t addr, + uint64_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN)-8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sd $8, 0($9) */ + MIPS64_SD(8, 0, 9), + MIPS64_SYNCI(9, 0), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(13)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem64(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint64_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u64(ejtag_info, addr + 8 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u32(struct mips_ejtag *ejtag_info, uint64_t addr, + uint32_t *buf) +{ + const uint32_t code[] = { + MIPS64_DMTC0(15, 31, 0), + /* move $15 to COP0 DeSave */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(8, 0, 15), + /* sd $8, ($15) */ + MIPS64_SD(9, 0, 15), + /* sd $9, ($15) */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_SW(8, 0, 9), + /* sw $8, 0($9) */ + MIPS64_SYNCI(9, 0), + MIPS64_LD(9, 0, 15), + /* ld $9, ($15) */ + MIPS64_LD(8, 0, 15), + /* ld $8, ($15) */ + MIPS64_SYNC, + MIPS64_B(NEG16(13)), + /* b start */ + MIPS64_DMFC0(15, 31, 0), + /* move COP0 DeSave to $15 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[1 + 1]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint32_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u32(ejtag_info, addr + 4 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u16(struct mips_ejtag *ejtag_info, uint64_t addr, + uint16_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sh $8, 0($9) */ + MIPS64_SH(8, 0, 9), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(12)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem16(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint16_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u16(ejtag_info, addr + 2 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u8(struct mips_ejtag *ejtag_info, uint64_t addr, + uint8_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sh $8, 0($9) */ + MIPS64_SB(8, 0, 9), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(12)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint8_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u8(ejtag_info, addr + i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned size, + unsigned count, void *buf) +{ + switch (size) { + case 1: + return mips64_pracc_write_mem8(ejtag_info, addr, count, buf); + case 2: + return mips64_pracc_write_mem16(ejtag_info, addr, count, buf); + case 4: + return mips64_pracc_write_mem32(ejtag_info, addr, count, buf); + case 8: + return mips64_pracc_write_mem64(ejtag_info, addr, count, buf); + } + return ERROR_FAIL; +} + +int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) +{ + const uint32_t code[] = { + /* move $2 to COP0 DeSave */ + MIPS64_DMTC0(2, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_IN)), + /* sd $0, 0*8($2) */ + MIPS64_LD(1, 1*8, 2), + /* sd $1, 1*8($2) */ + MIPS64_LD(15, 15*8, 2), + /* sd $11, ($15) */ + MIPS64_DMFC0(2, 31, 0), + MIPS64_DMTC0(15, 31, 0), + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(1, 0, 15), + /* $11 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_LD(3, 3*8, 1), + MIPS64_LD(4, 4*8, 1), + MIPS64_LD(5, 5*8, 1), + MIPS64_LD(6, 6*8, 1), + MIPS64_LD(7, 7*8, 1), + MIPS64_LD(8, 8*8, 1), + MIPS64_LD(9, 9*8, 1), + MIPS64_LD(10, 10*8, 1), + MIPS64_LD(11, 11*8, 1), + MIPS64_LD(12, 12*8, 1), + MIPS64_LD(13, 13*8, 1), + MIPS64_LD(14, 14*8, 1), + MIPS64_LD(16, 16*8, 1), + MIPS64_LD(17, 17*8, 1), + MIPS64_LD(18, 18*8, 1), + MIPS64_LD(19, 19*8, 1), + MIPS64_LD(20, 20*8, 1), + MIPS64_LD(21, 21*8, 1), + MIPS64_LD(22, 22*8, 1), + MIPS64_LD(23, 23*8, 1), + MIPS64_LD(24, 24*8, 1), + MIPS64_LD(25, 25*8, 1), + MIPS64_LD(26, 26*8, 1), + MIPS64_LD(27, 27*8, 1), + MIPS64_LD(28, 28*8, 1), + MIPS64_LD(29, 29*8, 1), + MIPS64_LD(30, 30*8, 1), + MIPS64_LD(31, 31*8, 1), + MIPS64_LD(2, 32*8, 1), + MIPS64_MTLO(2), + MIPS64_LD(2, 33*8, 1), + MIPS64_MTHI(2), + MIPS64_LD(2, MIPS64_NUM_CORE_REGS * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_DEPC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO0, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO1, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_CONTEXT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PAGEMASK, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_WIRED, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_COUNT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_COMPARE, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_STATUS, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CAUSE, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_EPC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CONFIG, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_LLA, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_XCONTEXT, 1), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_MEMCTRL, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 1), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 2), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 3), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_ECC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CACHERR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_TAGLO, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_TAGHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_DATAHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_EEPC, 0), + /* check if FPU is enabled, */ + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SRL(2, 2, 29), + MIPS64_ANDI(2, 2, 1), + /* skip FPU registers restoration if not */ + MIPS64_BEQ(0, 2, 77), + MIPS64_NOP, + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FIR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCSR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCONFIG, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCCR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FEXR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FENR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), + MIPS64_DMTC1(2, 0, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), + MIPS64_DMTC1(2, 1, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), + MIPS64_DMTC1(2, 2, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), + MIPS64_DMTC1(2, 3, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), + MIPS64_DMTC1(2, 4, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), + MIPS64_DMTC1(2, 5, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), + MIPS64_DMTC1(2, 6, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), + MIPS64_DMTC1(2, 7, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), + MIPS64_DMTC1(2, 8, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), + MIPS64_DMTC1(2, 9, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), + MIPS64_DMTC1(2, 10, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), + MIPS64_DMTC1(2, 11, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), + MIPS64_DMTC1(2, 12, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), + MIPS64_DMTC1(2, 13, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), + MIPS64_DMTC1(2, 14, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), + MIPS64_DMTC1(2, 15, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), + MIPS64_DMTC1(2, 16, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), + MIPS64_DMTC1(2, 17, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), + MIPS64_DMTC1(2, 18, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), + MIPS64_DMTC1(2, 19, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), + MIPS64_DMTC1(2, 20, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), + MIPS64_DMTC1(2, 21, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), + MIPS64_DMTC1(2, 22, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), + MIPS64_DMTC1(2, 23, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), + MIPS64_DMTC1(2, 24, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), + MIPS64_DMTC1(2, 25, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), + MIPS64_DMTC1(2, 26, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), + MIPS64_DMTC1(2, 27, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), + MIPS64_DMTC1(2, 28, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), + MIPS64_DMTC1(2, 29, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), + MIPS64_DMTC1(2, 30, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), + MIPS64_DMTC1(2, 31, 0), + MIPS64_LD(2, 2 * 8, 1), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(181)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + MIPS64_NUM_REGS, regs, 0, NULL); +} + +int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) +{ + const uint32_t code[] = { + /* move $2 to COP0 DeSave */ + MIPS64_DMTC0(2, 31, 0), + /* $2 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_OUT)), + /* sd $0, 0*8($2) */ + MIPS64_SD(0, 0*8, 2), + /* sd $1, 1*8($2) */ + MIPS64_SD(1, 1*8, 2), + /* sd $15, 15*8($2) */ + MIPS64_SD(15, 15*8, 2), + /* move COP0 DeSave to $2 */ + MIPS64_DMFC0(2, 31, 0), + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $1, ($15) */ + MIPS64_SD(1, 0, 15), + /* sd $2, ($15) */ + MIPS64_SD(2, 0, 15), + /* $1 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_SD(2, 2 * 8, 1), + MIPS64_SD(3, 3 * 8, 1), + MIPS64_SD(4, 4 * 8, 1), + MIPS64_SD(5, 5 * 8, 1), + MIPS64_SD(6, 6 * 8, 1), + MIPS64_SD(7, 7 * 8, 1), + MIPS64_SD(8, 8 * 8, 1), + MIPS64_SD(9, 9 * 8, 1), + MIPS64_SD(10, 10 * 8, 1), + MIPS64_SD(11, 11 * 8, 1), + MIPS64_SD(12, 12 * 8, 1), + MIPS64_SD(13, 13 * 8, 1), + MIPS64_SD(14, 14 * 8, 1), + MIPS64_SD(16, 16 * 8, 1), + MIPS64_SD(17, 17 * 8, 1), + MIPS64_SD(18, 18 * 8, 1), + MIPS64_SD(19, 19 * 8, 1), + MIPS64_SD(20, 20 * 8, 1), + MIPS64_SD(21, 21 * 8, 1), + MIPS64_SD(22, 22 * 8, 1), + MIPS64_SD(23, 23 * 8, 1), + MIPS64_SD(24, 24 * 8, 1), + MIPS64_SD(25, 25 * 8, 1), + MIPS64_SD(26, 26 * 8, 1), + MIPS64_SD(27, 27 * 8, 1), + MIPS64_SD(28, 28 * 8, 1), + MIPS64_SD(29, 29 * 8, 1), + MIPS64_SD(30, 30 * 8, 1), + MIPS64_SD(31, 31 * 8, 1), + MIPS64_MFLO(2), + MIPS64_SD(2, 32 * 8, 1), + MIPS64_MFHI(2), + MIPS64_SD(2, 33 * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_DEPC, 0), + MIPS64_SD(2, MIPS64_NUM_CORE_REGS * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_RANDOM, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 1) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO0, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO1, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_CONTEXT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PAGEMASK, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_WIRED, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_BADVADDR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 7) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_COUNT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_COMPARE, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CAUSE, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_EPC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PRID, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 14) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CONFIG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_LLA, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_XCONTEXT, 1), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_MEMCTRL, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_DEBUG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 23) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 1), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 2), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 3), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_ECC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CACHERR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_TAGLO, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_TAGHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_DATAHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_EEPC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), + /* check if FPU is enabled, */ + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SRL(2, 2, 29), + MIPS64_ANDI(2, 2, 1), + /* skip FPU registers dump if not */ + MIPS64_BEQ(0, 2, 77), + MIPS64_NOP, + MIPS64_CFC1(2, MIPS64_C1_FIR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCSR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCONFIG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCCR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FEXR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FENR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), + MIPS64_DMFC1(2, 0, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), + MIPS64_DMFC1(2, 1, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), + MIPS64_DMFC1(2, 2, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), + MIPS64_DMFC1(2, 3, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), + MIPS64_DMFC1(2, 4, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), + MIPS64_DMFC1(2, 5, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), + MIPS64_DMFC1(2, 6, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), + MIPS64_DMFC1(2, 7, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), + MIPS64_DMFC1(2, 8, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), + MIPS64_DMFC1(2, 9, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), + MIPS64_DMFC1(2, 10, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), + MIPS64_DMFC1(2, 11, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), + MIPS64_DMFC1(2, 12, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), + MIPS64_DMFC1(2, 13, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), + MIPS64_DMFC1(2, 14, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), + MIPS64_DMFC1(2, 15, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), + MIPS64_DMFC1(2, 16, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), + MIPS64_DMFC1(2, 17, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), + MIPS64_DMFC1(2, 18, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), + MIPS64_DMFC1(2, 19, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), + MIPS64_DMFC1(2, 20, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), + MIPS64_DMFC1(2, 21, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), + MIPS64_DMFC1(2, 22, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), + MIPS64_DMFC1(2, 23, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), + MIPS64_DMFC1(2, 24, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), + MIPS64_DMFC1(2, 25, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), + MIPS64_DMFC1(2, 26, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), + MIPS64_DMFC1(2, 27, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), + MIPS64_DMFC1(2, 28, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), + MIPS64_DMFC1(2, 29, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), + MIPS64_DMFC1(2, 30, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), + MIPS64_DMFC1(2, 31, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), + MIPS64_LD(2, 0, 15), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(192)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 0, NULL, MIPS64_NUM_REGS, regs); +} + +/* fastdata upload/download requires an initialized working area + * to load the download code; it should not be called otherwise + * fetch order from the fastdata area + * 1. start addr + * 2. end addr + * 3. data ... + */ +int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, + struct working_area *source, + bool write_t, uint64_t addr, + unsigned count, uint64_t *buf) +{ + uint32_t handler_code[] = { + /* caution when editing, table is modified below */ + /* r15 points to the start of this code */ + MIPS64_SD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS64_SD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), + MIPS64_SD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), + MIPS64_SD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), + /* start of fastdata area in t0 */ + MIPS64_LUI(8, UPPER16(MIPS64_PRACC_FASTDATA_AREA)), + MIPS64_ORI(8, 8, LOWER16(MIPS64_PRACC_FASTDATA_AREA)), + /* start addr in t1 */ + MIPS64_LD(9, 0, 8), + /* end addr to t2 */ + MIPS64_LD(10, 0, 8), + + /* loop: */ + /* lw t3,[t8 | r9] */ + /* 8 */ MIPS64_LD(11, 0, 0), + /* sw t3,[r9 | r8] */ + /* 9 */ MIPS64_SD(11, 0, 0), + /* bne $t2,t1,loop */ + MIPS64_BNE(10, 9, NEG16(3)), + /* addi t1,t1,4 */ + MIPS64_DADDIU(9, 9, 8), + + MIPS64_LD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS64_LD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), + MIPS64_LD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), + MIPS64_LD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), + + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_TEXT)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_TEXT)), + /* jr start */ + MIPS64_JR(15), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + }; + + uint32_t jmp_code[] = { + /* addr of working area added below */ + /* 0 */ MIPS64_LUI(15, 0), + /* addr of working area added below */ + /* 1 */ MIPS64_ORI(15, 15, 0), + /* jump to ram program */ + MIPS64_JR(15), + MIPS64_NOP, + }; + + int retval; + unsigned i; + uint32_t ejtag_ctrl, address32; + uint64_t address, val; + + if (source->size < MIPS64_FASTDATA_HANDLER_SIZE) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + if (write_t) { + /* load data from probe at fastdata area */ + handler_code[8] = MIPS64_LD(11, 0, 8); + /* store data to RAM @ r9 */ + handler_code[9] = MIPS64_SD(11, 0, 9); + } else { + /* load data from RAM @ r9 */ + handler_code[8] = MIPS64_LD(11, 0, 9); + /* store data to probe at fastdata area */ + handler_code[9] = MIPS64_SD(11, 0, 8); + } + + /* write program into RAM */ + if (write_t != ejtag_info->fast_access_save) { + mips64_pracc_write_mem(ejtag_info, source->address, 4, + ARRAY_SIZE(handler_code), handler_code); + /* save previous operation to speed to any consecutive read/writes */ + ejtag_info->fast_access_save = write_t; + } + + LOG_DEBUG("%s using " TARGET_ADDR_FMT " for write handler", __func__, + source->address); + LOG_DEBUG("daddiu: %08x", handler_code[11]); + + jmp_code[0] |= UPPER16(source->address); + jmp_code[1] |= LOWER16(source->address); + mips64_pracc_exec(ejtag_info, + ARRAY_SIZE(jmp_code), jmp_code, + 0, NULL, 0, NULL); + + /* next fetch to dmseg should be in FASTDATA_AREA, check */ + address = 0; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + retval = mips_ejtag_drscan_32(ejtag_info, &address32); + if (retval != ERROR_OK) + return retval; + address = 0xffffffffff200000ull | address32; + if ((address & ~7ull) != MIPS64_PRACC_FASTDATA_AREA) { + LOG_ERROR("! @MIPS64_PRACC_FASTDATA_AREA (" TARGET_ADDR_FMT ")", address); + return ERROR_FAIL; + } + /* Send the load start address */ + val = addr; + LOG_DEBUG("start: " TARGET_ADDR_FMT, val); + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); + mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); + + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) + return retval; + + /* Send the load end address */ + val = addr + (count - 1) * 8; + LOG_DEBUG("stop: " TARGET_ADDR_FMT, val); + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); + mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); + + /* like in legacy code */ + unsigned num_clocks = 0; + if (ejtag_info->mode != 0) + num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; + LOG_DEBUG("num_clocks=%d", num_clocks); + for (i = 0; i < count; i++) { + jtag_add_clocks(num_clocks); + retval = mips64_ejtag_fastdata_scan(ejtag_info, write_t, buf++); + if (retval != ERROR_OK) { + LOG_ERROR("mips64_ejtag_fastdata_scan failed"); + return retval; + } + } + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("jtag_execute_queue failed"); + return retval; + } + + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) { + LOG_ERROR("wait_for_pracc_rw failed"); + return retval; + } + + address = 0; + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + retval = mips_ejtag_drscan_32(ejtag_info, &address32); + if (retval != ERROR_OK) { + LOG_ERROR("mips_ejtag_drscan_32 failed"); + return retval; + } + + address = 0xffffffffff200000ull | address32; + if ((address & ~7ull) != MIPS64_PRACC_TEXT) + LOG_ERROR("mini program did not return to start"); + + return retval; +} diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h new file mode 100644 index 000000000..65ff6e6ac --- /dev/null +++ b/src/target/mips64_pracc.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + */ + +#ifndef OPENOCD_TARGET_MIPS64_PRACC_H +#define OPENOCD_TARGET_MIPS64_PRACC_H + +#include "mips_ejtag.h" + +#define MIPS64_PRACC_TEXT 0xffffffffFF200200ull + +#define MIPS64_PRACC_STACK 0xffffffffFF204000ull +#define MIPS64_PRACC_PARAM_IN 0xffffffffFF201000ull +#define MIPS64_PRACC_PARAM_IN_SIZE 0x1000 +#define MIPS64_PRACC_PARAM_OUT (MIPS64_PRACC_PARAM_IN + MIPS64_PRACC_PARAM_IN_SIZE) +#define MIPS64_PRACC_PARAM_OUT_SIZE 0x1000 + +#undef UPPER16 +#undef LOWER16 +#define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF)) +#define LOWER16(v) ((uint32_t)(v & 0xFFFF)) +#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000 +#define MIPS64_PRACC_FASTDATA_SIZE 16 +#define MIPS64_FASTDATA_HANDLER_SIZE 0x80 + +/* FIXME: 16-bit NEG */ +#undef NEG16 +#define NEG16(v) ((uint32_t)(((~(v)) + 1) & 0xFFFF)) + +#define MIPS64_PRACC_ADDR_STEP 4 +#define MIPS64_PRACC_DATA_STEP 8 + +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); + +int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); +int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); + +int mips64_pracc_exec(struct mips_ejtag *ejtag_info, + unsigned code_len, const uint32_t *code, + unsigned num_param_in, uint64_t *param_in, + unsigned num_param_out, uint64_t *param_out); + +int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, + struct working_area *source, + bool write_t, uint64_t addr, + unsigned count, uint64_t *buf); + +#endif /* OPENOCD_TARGET_MIPS64_PRACC_H */ diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 03a09529c..3735cbb67 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -27,6 +27,8 @@ #include "mips32.h" #include "mips_ejtag.h" #include "mips32_dmaacc.h" +#include "mips64.h" +#include "mips64_pracc.h" void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) { @@ -38,7 +40,7 @@ void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) struct scan_field field; field.num_bits = tap->ir_length; - uint8_t t[4]; + uint8_t t[4] = { 0 }; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); @@ -87,6 +89,36 @@ void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32 keep_alive(); } +int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) +{ + struct jtag_tap *tap; + tap = ejtag_info->tap; + + if (tap == NULL) + return ERROR_FAIL; + struct scan_field field; + uint8_t t[8] = { 0 }, r[8]; + int retval; + + field.num_bits = 64; + field.out_value = t; + buf_set_u64(t, 0, field.num_bits, *data); + field.in_value = r; + + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("register read failed"); + return retval; + } + + *data = buf_get_u64(field.in_value, 0, 64); + + keep_alive(); + + return ERROR_OK; +} + void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) { assert(ejtag_info->tap != NULL); @@ -95,7 +127,7 @@ void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_ou struct scan_field field; field.num_bits = 32; - uint8_t scan_out[4]; + uint8_t scan_out[4] = { 0 }; field.out_value = scan_out; buf_set_u32(scan_out, 0, field.num_bits, data_out); @@ -314,7 +346,7 @@ static void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) EJTAG_IMP_HAS(EJTAG_IMP_ASID6) ? " ASID_6" : "", EJTAG_IMP_HAS(EJTAG_IMP_MIPS16) ? " MIPS16" : "", EJTAG_IMP_HAS(EJTAG_IMP_NODMA) ? " noDMA" : " DMA", - EJTAG_IMP_HAS(EJTAG_DCR_MIPS64) ? " MIPS64" : " MIPS32"); + EJTAG_IMP_HAS(EJTAG_IMP_MIPS64) ? " MIPS64" : " MIPS32"); switch (ejtag_info->ejtag_version) { case EJTAG_VERSION_20: @@ -422,3 +454,108 @@ int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_ return ERROR_OK; } + +int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step) +{ + const uint32_t code_enable[] = { + MIPS64_MTC0(1, 31, 0), /* move $1 to COP0 DeSave */ + MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ + MIPS64_ORI(1, 1, 0x0100), /* set SSt bit in debug reg */ + MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ + MIPS64_B(NEG16(5)), + MIPS64_MFC0(1, 31, 0), /* move COP0 DeSave to $1 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + const uint32_t code_disable[] = { + MIPS64_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), /* $15 = MIPS64_PRACC_STACK */ + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(1, 0, 15), /* sw $1,($15) */ + MIPS64_SD(2, 0, 15), /* sw $2,($15) */ + MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ + MIPS64_LUI(2, 0xFFFF), /* $2 = 0xfffffeff */ + MIPS64_ORI(2, 2, 0xFEFF), + MIPS64_AND(1, 1, 2), + MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ + MIPS64_LD(2, 0, 15), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + MIPS64_B(NEG16(14)), + MIPS64_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + const uint32_t *code = enable_step ? code_enable : code_disable; + unsigned code_len = enable_step ? ARRAY_SIZE(code_enable) : + ARRAY_SIZE(code_disable); + + return mips64_pracc_exec(ejtag_info, + code_len, code, 0, NULL, 0, NULL); +} + +int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info) +{ + const uint32_t code[] = { + MIPS64_DRET, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, + ARRAY_SIZE(code), code, 0, NULL, 0, NULL); +} + +int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data) +{ + struct jtag_tap *tap; + + tap = ejtag_info->tap; + assert(tap != NULL); + + struct scan_field fields[2]; + uint8_t spracc = 0; + uint8_t t[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + /* fastdata 1-bit register */ + fields[0].num_bits = 1; + fields[0].out_value = &spracc; + fields[0].in_value = NULL; + + /* processor access data register 64 bit */ + fields[1].num_bits = 64; + fields[1].out_value = t; + + if (write_t) { + fields[1].in_value = NULL; + buf_set_u64(t, 0, 64, *data); + } else + fields[1].in_value = (uint8_t *) data; + + jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); + + if (!write_t && data) + jtag_add_callback(mips_le_to_h_u64, + (jtag_callback_data_t) data); + keep_alive(); + + return ERROR_OK; +} diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index c64e858a3..ace3d281e 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -130,7 +130,7 @@ /* v2.0 - 1:4 Number of Break Channels. */ #define EJTAG_V20_IMP_BCHANNELS_MASK 0xf #define EJTAG_V20_IMP_BCHANNELS_SHIFT 1 -#define EJTAG_DCR_MIPS64 (1 << 0) +#define EJTAG_IMP_MIPS64 (1 << 0) /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 @@ -182,6 +182,20 @@ #define EJTAG_VERSION_41 4 #define EJTAG_VERSION_51 5 +/* + * Additional defines for MIPS64 EJTAG + */ +#define EJTAG64_DCR 0xFFFFFFFFFF300000ull +#define EJTAG64_DCR_ENM (1llu << 29) +#define EJTAG64_DCR_DB (1llu << 17) +#define EJTAG64_DCR_IB (1llu << 16) +#define EJTAG64_DCR_INTE (1llu << 4) +#define EJTAG64_DCR_MP (1llu << 2) +#define EJTAG64_V25_DBA0 0xFFFFFFFFFF302100ull +#define EJTAG64_V25_DBS 0xFFFFFFFFFF302000ull +#define EJTAG64_V25_IBA0 0xFFFFFFFFFF301100ull +#define EJTAG64_V25_IBS 0xFFFFFFFFFF301000ull + struct mips_ejtag { struct jtag_tap *tap; uint32_t impcode; @@ -224,17 +238,21 @@ struct mips_ejtag { void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr); int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info); +int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info); void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf); +int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data); void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data); int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data); void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data); int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data); int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data); +int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data); int mips_ejtag_init(struct mips_ejtag *ejtag_info); int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step); +int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step); static inline void mips_le_to_h_u32(jtag_callback_data_t arg) { @@ -242,4 +260,10 @@ static inline void mips_le_to_h_u32(jtag_callback_data_t arg) *((uint32_t *)arg) = le_to_h_u32(in); } +static inline void mips_le_to_h_u64(jtag_callback_data_t arg) +{ + uint8_t *in = (uint8_t *)arg; + *((uint64_t *)arg) = le_to_h_u64(in); +} + #endif /* OPENOCD_TARGET_MIPS_EJTAG_H */ diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c new file mode 100644 index 000000000..3a592f7f3 --- /dev/null +++ b/src/target/mips_mips64.c @@ -0,0 +1,1193 @@ +/* + * MIPS64 generic target support + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "breakpoints.h" +#include "mips32.h" +#include "mips64.h" +#include "mips_mips64.h" +#include "target_type.h" +#include "register.h" + +static int mips_mips64_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint); + +static uint64_t mips64_extend_sign(uint64_t addr) +{ + if (addr >> 32) + return addr; + if (addr >> 31) + return addr | (ULLONG_MAX << 32); + return addr; +} + +static int mips_mips64_examine_debug_reason(struct target *target) +{ + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) + target->debug_reason = DBG_REASON_BREAKPOINT; + + return ERROR_OK; +} + +static int mips_mips64_debug_entry(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + + mips64_save_context(target); + + /* make sure stepping disabled, SSt bit in CP0 debug register cleared */ + mips64_ejtag_config_step(ejtag_info, 0); + + /* make sure break unit configured */ + mips64_configure_break_unit(target); + + /* attempt to find halt reason */ + mips_mips64_examine_debug_reason(target); + + LOG_DEBUG("entered debug state at PC 0x%" PRIx64 ", target->state: %s", + *(uint64_t *)pc->value, target_state_name(target)); + + return ERROR_OK; +} + +static int mips_mips64_poll(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl; + + /* read ejtag control reg */ + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + + /* clear this bit before handling polling + * as after reset registers will read zero */ + if (ejtag_ctrl & EJTAG_CTRL_ROCC) { + /* we have detected a reset, clear flag + * otherwise ejtag will not work */ + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + LOG_DEBUG("Reset Detected"); + } + + /* check for processor halted */ + if (ejtag_ctrl & EJTAG_CTRL_BRKST) { + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { + target->state = TARGET_HALTED; + retval = mips_mips64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } else if (target->state == TARGET_DEBUG_RUNNING) { + target->state = TARGET_HALTED; + retval = mips_mips64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } + } else { + target->state = TARGET_RUNNING; + } + + return ERROR_OK; +} + +static int mips_mips64_halt(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + 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 { + /* we came here in a reset_halt or reset_init sequence + * debug entry was already prepared in mips64_prepare_reset_halt() + */ + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; + } + } + + /* break processor */ + mips_ejtag_enter_debug(ejtag_info); + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int mips_mips64_assert_reset(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + + LOG_DEBUG("target->state: %s", + target_state_name(target)); + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (!(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("Can't assert SRST"); + return ERROR_FAIL; + } + + if (target->reset_halt) + /* use hardware to catch reset */ + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT); + else + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); + + /* here we 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 + jtag_add_reset(0, 1); + + target->state = TARGET_RESET; + jtag_add_sleep(5000); + + retval = mips64_invalidate_core_regs(target); + if (retval != ERROR_OK) + return retval; + + if (target->reset_halt) { + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +static int mips_mips64_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 mips_mips64_soft_reset_halt(struct target *target) +{ + /* TODO */ + return ERROR_OK; +} + +static int mips_mips64_single_step_core(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + + /* configure single step mode */ + mips64_ejtag_config_step(ejtag_info, 1); + + /* disable interrupts while stepping */ + retval = mips64_enable_interrupts(target, false); + if (retval != ERROR_OK) + return retval; + + /* exit debug mode */ + retval = mips64_ejtag_exit_debug(ejtag_info); + if (retval != ERROR_OK) + return retval; + + mips_mips64_debug_entry(target); + + return ERROR_OK; +} + +/* TODO: HW breakpoints are in EJTAG spec. Should we share it for MIPS32? */ +static int mips_mips64_set_hwbp(struct target *target, struct breakpoint *bp) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *c, *cl = mips64->inst_break_list; + uint64_t bp_value; + int retval, bp_num = 0; + + while (cl[bp_num].used && (bp_num < mips64->num_inst_bpoints)) + bp_num++; + + if (bp_num >= mips64->num_inst_bpoints) { + LOG_DEBUG("ERROR Can not find free FP Comparator(bpid: %d)", + bp->unique_id); + LOG_WARNING("ERROR Can not find free FP Comparator"); + exit(-1); + } + + c = &cl[bp_num]; + c->used = true; + c->bp_value = bp->address; + bp_value = bp->address; + + /* Instruction Breakpoint Address n (IBAn) Register */ + retval = target_write_u64(target, c->reg_address, bp_value); + if (retval != ERROR_OK) + return retval; + + /* TODO: use defines */ + /* Instruction Breakpoint Address Mask n (IBMn) Register */ + retval = target_write_u64(target, c->reg_address + 0x08, 0); + if (retval != ERROR_OK) + return retval; + + /* Instruction Breakpoint Control n (IBCn) Register */ + retval = target_write_u64(target, c->reg_address + 0x18, 1); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("bpid: %d, bp_num %i bp_value 0x%" PRIx64 "", bp->unique_id, + bp_num, c->bp_value); + + return ERROR_OK; +} + +/* TODO: is it MIPS64 or MIPS32 instruction. If MIPS32, can it be shared with + * MIPS32 code? */ +static int mips_mips64_set_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint32_t verify; + int retval; + + retval = target_read_memory(target, + bp->address, bp->length, 1, + bp->orig_instr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, bp->address, MIPS64_SDBBP); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, bp->address, &verify); + if (retval != ERROR_OK) + return retval; + + if (verify != MIPS64_SDBBP) { + LOG_ERROR("Unable to set 32bit breakpoint at address %16" PRIx64, + bp->address); + retval = ERROR_FAIL; + } + + return retval; +} + +/* TODO do MIPS64 support MIPS16 instructions? Can it be shared with MIPS32 + * code? */ +static int mips_mips16_set_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint32_t isa_req = bp->length & 1; + uint16_t verify; + int retval; + + retval = target_read_memory(target, + bp->address, bp->length, 1, + bp->orig_instr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u16(target, bp->address, MIPS16_SDBBP(isa_req)); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u16(target, bp->address, &verify); + if (retval != ERROR_OK) + return retval; + + if (verify != MIPS16_SDBBP(isa_req)) { + LOG_ERROR("Unable to set 16bit breakpoint at address %16" PRIx64, + bp->address); + retval = ERROR_FAIL; + } + + return retval; +} + +static int mips_mips64_set_breakpoint(struct target *target, + struct breakpoint *bp) +{ + int retval; + + if (bp->set) { + LOG_WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (bp->type == BKPT_HARD) { + retval = mips_mips64_set_hwbp(target, bp); + } else { + LOG_DEBUG("bpid: %d", bp->unique_id); + + switch (bp->length) { + case MIPS64_SDBBP_SIZE: + retval = mips_mips64_set_sdbbp(target, bp); + break; + case MIPS16_SDBBP_SIZE: + retval = mips_mips16_set_sdbbp(target, bp); + break; + default: + retval = ERROR_FAIL; + } + } + + if (retval != ERROR_OK) { + LOG_ERROR("can't unset breakpoint. Some thing wrong happened"); + return retval; + } + + bp->set = true; + + return ERROR_OK; +} + +static int mips_mips64_enable_breakpoints(struct target *target) +{ + struct breakpoint *bp = target->breakpoints; + int retval = ERROR_OK; + + /* set any pending breakpoints */ + while (bp) { + if (!bp->set) { + retval = mips_mips64_set_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + bp = bp->next; + } + + return ERROR_OK; +} + +/* TODO: HW data breakpoints are in EJTAG spec. Should we share it for MIPS32? */ +static int mips_mips64_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + uint64_t wp_value; + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *c, *cl = mips64->data_break_list; + int retval, wp_num = 0; + + /* + * watchpoint enabled, ignore all byte lanes in value register + * and exclude both load and store accesses from watchpoint + * condition evaluation + */ + int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE + | (0xff << EJTAG_DBCn_BLM_SHIFT); + + if (watchpoint->set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (cl[wp_num].used && (wp_num < mips64->num_data_bpoints)) + wp_num++; + + if (wp_num >= mips64->num_data_bpoints) { + LOG_ERROR("ERROR Can not find free comparator"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (watchpoint->length != 4) { + LOG_ERROR("Only watchpoints of length 4 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + if (watchpoint->address % 4) { + LOG_ERROR("Watchpoints address should be word aligned"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + switch (watchpoint->rw) { + case WPT_READ: + enable &= ~EJTAG_DBCn_NOLB; + break; + case WPT_WRITE: + enable &= ~EJTAG_DBCn_NOSB; + break; + case WPT_ACCESS: + enable &= ~(EJTAG_DBCn_NOLB | EJTAG_DBCn_NOSB); + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + c = &cl[wp_num]; + watchpoint->set = wp_num + 1; + c->used = true; + c->bp_value = watchpoint->address; + + wp_value = watchpoint->address; + if (wp_value & 0x80000000) + wp_value |= ULLONG_MAX << 32; + + retval = target_write_u64(target, c->reg_address, wp_value); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x08, 0); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x10, 0); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x18, enable); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x20, 0); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64 "", wp_num, c->bp_value); + + return ERROR_OK; +} + +static int mips_mips64_enable_watchpoints(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + int retval; + + /* set any pending watchpoints */ + while (watchpoint) { + if (watchpoint->set == 0) { + retval = mips_mips64_set_watchpoint(target, watchpoint); + if (retval != ERROR_OK) + return retval; + } + watchpoint = watchpoint->next; + } + + return ERROR_OK; +} + +static int mips_mips64_unset_hwbp(struct target *target, struct breakpoint *bp) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *comparator_list = mips64->inst_break_list; + int bp_num; + + bp_num = bp->set - 1; + + if ((bp_num < 0) || (bp_num >= mips64->num_inst_bpoints)) { + LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %d)", + bp->unique_id); + return ERROR_OK; + } + + LOG_DEBUG("bpid: %d - releasing hw: %d", bp->unique_id, bp_num); + comparator_list[bp_num].used = false; + comparator_list[bp_num].bp_value = 0; + + return target_write_u64(target, + comparator_list[bp_num].reg_address + 0x18, 0); +} + +static int mips_mips64_unset_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint8_t buf[MIPS64_SDBBP_SIZE]; + uint32_t instr; + int retval; + + retval = target_read_memory(target, bp->address, MIPS64_SDBBP_SIZE, 1, + &buf[0]); + if (retval != ERROR_OK) + return retval; + + instr = target_buffer_get_u32(target, &buf[0]); + if (instr != MIPS64_SDBBP) + return ERROR_OK; + + return target_write_memory(target, bp->address, MIPS64_SDBBP_SIZE, 1, + bp->orig_instr); +} + +static int mips_mips16_unset_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint8_t buf[MIPS16_SDBBP_SIZE]; + uint16_t instr; + int retval; + + retval = target_read_memory(target, bp->address, MIPS16_SDBBP_SIZE, 1, + &buf[0]); + if (retval != ERROR_OK) + return retval; + + instr = target_buffer_get_u16(target, &buf[0]); + if (instr != MIPS16_SDBBP(bp->length & 1)) + return ERROR_OK; + + return target_write_memory(target, bp->address, MIPS16_SDBBP_SIZE, 1, + bp->orig_instr); +} + +static int mips_mips64_unset_breakpoint(struct target *target, + struct breakpoint *bp) +{ + /* get pointers to arch-specific information */ + int retval; + + if (!bp->set) { + LOG_WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (bp->type == BKPT_HARD) { + retval = mips_mips64_unset_hwbp(target, bp); + } else { + LOG_DEBUG("bpid: %d", bp->unique_id); + + switch (bp->length) { + case MIPS64_SDBBP_SIZE: + retval = mips_mips64_unset_sdbbp(target, bp); + break; + case MIPS16_SDBBP_SIZE: + retval = mips_mips16_unset_sdbbp(target, bp); + break; + default: + retval = ERROR_FAIL; + } + } + if (retval != ERROR_OK) { + LOG_ERROR("can't unset breakpoint. Some thing wrong happened"); + return retval; + } + + bp->set = false; + + return ERROR_OK; +} + +static int mips_mips64_resume(struct target *target, int current, + uint64_t address, int handle_breakpoints, + int debug_execution) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval = ERROR_OK; + uint64_t resume_pc; + struct reg *pc; + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted %d", target->state); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) { + target_free_all_working_areas(target); + retval = mips_mips64_enable_breakpoints(target); + if (retval != ERROR_OK) + return retval; + + retval = mips_mips64_enable_watchpoints(target); + if (retval != ERROR_OK) + return retval; + } + + pc = &mips64->core_cache->reg_list[MIPS64_PC]; + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) { + buf_set_u64(pc->value, 0, 64, address); + pc->dirty = 1; + pc->valid = 1; + } + + resume_pc = buf_get_u64(pc->value, 0, 64); + + retval = mips64_restore_context(target); + if (retval != ERROR_OK) + return retval; + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + struct breakpoint *bp; + + /* Single step past breakpoint at current address */ + bp = breakpoint_find(target, (uint64_t) resume_pc); + if (bp) { + LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64 "", + bp->address); + retval = mips_mips64_unset_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + + retval = mips_mips64_single_step_core(target); + if (retval != ERROR_OK) + return retval; + + retval = mips_mips64_set_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + } + + /* enable interrupts if we are running */ + retval = mips64_enable_interrupts(target, !debug_execution); + if (retval != ERROR_OK) + return retval; + + /* exit debug mode */ + retval = mips64_ejtag_exit_debug(ejtag_info); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + + /* registers are now invalid */ + retval = mips64_invalidate_core_regs(target); + if (retval != ERROR_OK) + return retval; + + if (!debug_execution) { + target->state = TARGET_RUNNING; + retval = target_call_event_callbacks(target, + TARGET_EVENT_RESUMED); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("target resumed at 0x%" PRIx64 "", resume_pc); + } else { + target->state = TARGET_DEBUG_RUNNING; + retval = target_call_event_callbacks(target, + TARGET_EVENT_DEBUG_RESUMED); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("target debug resumed at 0x%" PRIx64 "", resume_pc); + } + + return ERROR_OK; +} + +static int mips_mips64_step(struct target *target, int current, + uint64_t address, int handle_breakpoints) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + struct breakpoint *bp = NULL; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + /* current = 1: continue on current pc, otherwise continue at + *
*/ + if (!current) { + buf_set_u64(pc->value, 0, 64, address); + pc->dirty = 1; + pc->valid = 1; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + bp = breakpoint_find(target, buf_get_u64(pc->value, 0, 64)); + if (bp) { + retval = mips_mips64_unset_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + } + + retval = mips64_restore_context(target); + if (retval != ERROR_OK) + return retval; + + /* configure single step mode */ + retval = mips64_ejtag_config_step(ejtag_info, 1); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_SINGLESTEP; + + retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + if (retval != ERROR_OK) + return retval; + + /* disable interrupts while stepping */ + retval = mips64_enable_interrupts(target, false); + if (retval != ERROR_OK) + return retval; + + /* exit debug mode */ + retval = mips64_ejtag_exit_debug(ejtag_info); + if (retval != ERROR_OK) + return retval; + + /* registers are now invalid */ + retval = mips64_invalidate_core_regs(target); + if (retval != ERROR_OK) + return retval; + + if (bp) { + retval = mips_mips64_set_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + + LOG_DEBUG("target stepped "); + + retval = mips_mips64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); +} + +static int mips_mips64_add_breakpoint(struct target *target, + struct breakpoint *bp) +{ + struct mips64_common *mips64 = target->arch_info; + + if (mips64->mips64mode32) + bp->address = mips64_extend_sign(bp->address); + + if (bp->type == BKPT_HARD) { + if (mips64->num_inst_bpoints_avail < 1) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + mips64->num_inst_bpoints_avail--; + } + + return mips_mips64_set_breakpoint(target, bp); +} + +static int mips_mips64_remove_breakpoint(struct target *target, + struct breakpoint *bp) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (bp->set) + retval = mips_mips64_unset_breakpoint(target, bp); + + if (bp->type == BKPT_HARD) + mips64->num_inst_bpoints_avail++; + + return retval; +} + +static int mips_mips64_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *comparator_list = mips64->data_break_list; + + if (!watchpoint->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wp_num = watchpoint->set - 1; + if ((wp_num < 0) || (wp_num >= mips64->num_data_bpoints)) { + LOG_DEBUG("Invalid FP Comparator number in watchpoint"); + return ERROR_OK; + } + comparator_list[wp_num].used = false; + comparator_list[wp_num].bp_value = 0; + target_write_u64(target, comparator_list[wp_num].reg_address + 0x18, 0); + watchpoint->set = 0; + + return ERROR_OK; +} + +static int mips_mips64_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct mips64_common *mips64 = target->arch_info; + + if (mips64->num_data_bpoints_avail < 1) { + LOG_INFO("no hardware watchpoints available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + mips64->num_data_bpoints_avail--; + + return mips_mips64_set_watchpoint(target, watchpoint); +} + +static int mips_mips64_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + retval = mips_mips64_unset_watchpoint(target, watchpoint); + + mips64->num_data_bpoints_avail++; + + return retval; +} + +static int mips_mips64_read_memory(struct target *target, uint64_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + void *t; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted %d", target->state); + return ERROR_TARGET_NOT_HALTED; + } + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + /* sanitize arguments */ + if (((size != 8) && (size != 4) && (size != 2) && (size != 1)) + || !count || !buffer) + return ERROR_COMMAND_ARGUMENT_INVALID; + + if (((size == 8) && (address & 0x7)) || ((size == 4) && (address & 0x3)) + || ((size == 2) && (address & 0x1))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + if (size > 1) { + t = calloc(count, size); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + } else + t = buffer; + + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + address, size, count); + retval = mips64_pracc_read_mem(ejtag_info, address, size, count, + (void *)t); + + if (ERROR_OK != retval) { + LOG_ERROR("mips64_pracc_read_mem filed"); + goto read_done; + } + + switch (size) { + case 8: + target_buffer_set_u64_array(target, buffer, count, t); + break; + case 4: + target_buffer_set_u32_array(target, buffer, count, t); + break; + case 2: + target_buffer_set_u16_array(target, buffer, count, t); + break; + } + +read_done: + if (size > 1) + free(t); + + return retval; +} + +static int mips_mips64_bulk_write_memory(struct target *target, + target_addr_t address, uint32_t count, + const uint8_t *buffer) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + struct working_area *fast_data_area; + int retval; + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + address, count); + + if (address & 0x7) + return ERROR_TARGET_UNALIGNED_ACCESS; + + if (!mips64->fast_data_area) { + /* Get memory for block write handler + * we preserve this area between calls and gain a speed increase + * of about 3kb/sec when writing flash + * this will be released/nulled by the system when the target is resumed or reset */ + retval = target_alloc_working_area(target, + MIPS64_FASTDATA_HANDLER_SIZE, + &mips64->fast_data_area); + if (retval != ERROR_OK) { + LOG_ERROR("No working area available"); + return retval; + } + + /* reset fastadata state so the algo get reloaded */ + ejtag_info->fast_access_save = -1; + } + + fast_data_area = mips64->fast_data_area; + + if (address <= fast_data_area->address + fast_data_area->size && + fast_data_area->address <= address + count) { + LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area " + "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", + fast_data_area->address, address, address + count); + LOG_ERROR("Change work-area-phys or load_image address!"); + return ERROR_FAIL; + } + + /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ + /* but byte array represents target endianness */ + uint64_t *t; + + t = calloc(count, sizeof(uint64_t)); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + target_buffer_get_u64_array(target, buffer, count, t); + + retval = mips64_pracc_fastdata_xfer(ejtag_info, mips64->fast_data_area, + true, address, count, t); + + if (retval != ERROR_OK) + LOG_ERROR("Fastdata access Failed"); + + free(t); + + return retval; +} + +static int mips_mips64_write_memory(struct target *target, uint64_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + /* sanitize arguments */ + if (((size != 8) && (size != 4) && (size != 2) && (size != 1)) + || !count || !buffer) + return ERROR_COMMAND_ARGUMENT_INVALID; + + if (((size == 8) && (address & 0x7)) || ((size == 4) && (address & 0x3)) + || ((size == 2) && (address & 0x1))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + + + if (size == 8 && count > 8) { + retval = mips_mips64_bulk_write_memory(target, address, count, + buffer); + if (retval == ERROR_OK) + return ERROR_OK; + + LOG_WARNING("Falling back to non-bulk write"); + } + + void *t = NULL; + if (size > 1) { + t = calloc(count, size); + if (!t) { + LOG_ERROR("unable to allocate t for write buffer"); + return ERROR_FAIL; + } + + switch (size) { + case 8: + target_buffer_get_u64_array(target, buffer, count, + (uint64_t *)t); + break; + case 4: + target_buffer_get_u32_array(target, buffer, count, + (uint32_t *)t); + break; + case 2: + target_buffer_get_u16_array(target, buffer, count, + (uint16_t *)t); + break; + } + buffer = t; + } + + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + address, size, count); + + retval = mips64_pracc_write_mem(ejtag_info, address, size, count, + (void *)buffer); + free(t); + + return retval; +} + +static int mips_mips64_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + return mips64_build_reg_cache(target); +} + +static int mips_mips64_target_create(struct target *target, Jim_Interp *interp) +{ + struct mips_mips64_common *mips_mips64; + struct mips64_common *mips64; + + mips_mips64 = calloc(1, sizeof(*mips_mips64)); + if (!mips_mips64) { + LOG_ERROR("unable to allocate mips_mips64"); + return ERROR_FAIL; + } + + mips_mips64->common_magic = MIPS64_COMMON_MAGIC; + + mips64 = &mips_mips64->mips64_common; + mips64->arch_info = mips_mips64; + target->arch_info = mips64; + + return mips64_init_arch_info(target, mips64, target->tap); +} + +static int mips_mips64_examine(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + + retval = mips_ejtag_init(&mips64->ejtag_info); + if (retval != ERROR_OK) + return retval; + + return mips64_examine(target); +} + +static int mips_mips64_checksum_memory(struct target *target, uint64_t address, + uint32_t size, uint32_t *checksum) +{ + return ERROR_FAIL; /* use bulk read method */ +} + +COMMAND_HANDLER(handle_mips64mode32) +{ + struct target *target = get_current_target(CMD_CTX); + struct mips64_common *mips64 = target->arch_info; + + if (CMD_ARGC > 0) + COMMAND_PARSE_BOOL(CMD_ARGV[0], mips64->mips64mode32, "on", "off"); + + if (mips64->mips64mode32) + command_print(CMD, "enabled"); + else + command_print(CMD, "disabled"); + + return ERROR_OK; +} + + +static const struct command_registration mips64_commands_handlers[] = { + { + .name = "mips64mode32", + .mode = COMMAND_EXEC, + .help = "Enable/disable 32 bit mode", + .usage = "[1|0]", + .handler = handle_mips64mode32 + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type mips_mips64_target = { + .name = "mips_mips64", + + .poll = mips_mips64_poll, + .arch_state = mips64_arch_state, + + .target_request_data = NULL, + + .halt = mips_mips64_halt, + .resume = mips_mips64_resume, + .step = mips_mips64_step, + + .assert_reset = mips_mips64_assert_reset, + .deassert_reset = mips_mips64_deassert_reset, + .soft_reset_halt = mips_mips64_soft_reset_halt, + + .get_gdb_reg_list = mips64_get_gdb_reg_list, + + .read_memory = mips_mips64_read_memory, + .write_memory = mips_mips64_write_memory, + .checksum_memory = mips_mips64_checksum_memory, + .blank_check_memory = NULL, + + .run_algorithm = mips64_run_algorithm, + + .add_breakpoint = mips_mips64_add_breakpoint, + .remove_breakpoint = mips_mips64_remove_breakpoint, + .add_watchpoint = mips_mips64_add_watchpoint, + .remove_watchpoint = mips_mips64_remove_watchpoint, + + .target_create = mips_mips64_target_create, + .init_target = mips_mips64_init_target, + .examine = mips_mips64_examine, + + .commands = mips64_commands_handlers, +}; diff --git a/src/target/mips_mips64.h b/src/target/mips_mips64.h new file mode 100644 index 000000000..69fb2a6f9 --- /dev/null +++ b/src/target/mips_mips64.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * MIPS64 generic target support * + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + */ + +#ifndef OPENOCD_TARGET_MIPS_MIPS64_H +#define OPENOCD_TARGET_MIPS_MIPS64_H + +#include "helper/types.h" + +struct mips_mips64_common { + int common_magic; + struct mips64_common mips64_common; +}; + +#endif /* OPENOCD_TARGET_MIPS_MIPS64_H */ diff --git a/src/target/nds32.c b/src/target/nds32.c index 4115ea4f2..f40ce534b 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -2361,7 +2361,7 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil fileio_info->param_4 = reg_r2; target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; + fileio_info->param_2 = strlen((char *)filename); } break; case NDS32_SYSCALL_CLOSE: @@ -2399,7 +2399,7 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil /* reserve fileio_info->param_2 for length of path */ target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; + fileio_info->param_2 = strlen((char *)filename); } break; case NDS32_SYSCALL_RENAME: @@ -2413,10 +2413,10 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil /* reserve fileio_info->param_4 for length of new path */ target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; + fileio_info->param_2 = strlen((char *)filename); target->type->read_buffer(target, reg_r1, 256, filename); - fileio_info->param_4 = strlen((char *)filename) + 1; + fileio_info->param_4 = strlen((char *)filename); } break; case NDS32_SYSCALL_FSTAT: @@ -2458,7 +2458,7 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil /* reserve fileio_info->param_2 for length of old path */ target->type->read_buffer(target, reg_r0, 256, command); - fileio_info->param_2 = strlen((char *)command) + 1; + fileio_info->param_2 = strlen((char *)command); } break; case NDS32_SYSCALL_ERRNO: diff --git a/src/target/nds32.h b/src/target/nds32.h index 141dbf4cb..3670fd289 100644 --- a/src/target/nds32.h +++ b/src/target/nds32.h @@ -82,7 +82,7 @@ enum nds32_syscall_id { NDS32_SYSCALL_ERRNO = 6001, }; -#define NDS32_COMMON_MAGIC (int)0xADE5ADE5 +#define NDS32_COMMON_MAGIC 0xADE5ADE5U struct nds32_edm { @@ -235,7 +235,7 @@ struct nds32_misc_config { * Represents a generic Andes core. */ struct nds32 { - int common_magic; + uint32_t common_magic; struct reg_cache *core_cache; /** Handle for the debug module. */ diff --git a/src/target/nds32_cmd.c b/src/target/nds32_cmd.c index 1accf6f83..d7d040e4b 100644 --- a/src/target/nds32_cmd.c +++ b/src/target/nds32_cmd.c @@ -1007,7 +1007,7 @@ static const struct command_registration nds32_exec_command_handlers[] = { .handler = handle_nds32_global_stop_command, .mode = COMMAND_ANY, .usage = "['on'|'off']", - .help = "turn on/off global stop. After turning on, every load/store" \ + .help = "turn on/off global stop. After turning on, every load/store " "instructions will be stopped to check memory access.", }, { @@ -1015,7 +1015,7 @@ static const struct command_registration nds32_exec_command_handlers[] = { .handler = handle_nds32_soft_reset_halt_command, .mode = COMMAND_ANY, .usage = "['on'|'off']", - .help = "as issuing rest-halt, to use soft-reset-halt or not." \ + .help = "as issuing rest-halt, to use soft-reset-halt or not." "the feature is for backward-compatible.", }, { @@ -1123,4 +1123,3 @@ const struct command_registration nds32_command_handlers[] = { }, COMMAND_REGISTRATION_DONE }; - diff --git a/src/target/nds32_disassembler.c b/src/target/nds32_disassembler.c index f27aba2cc..0cfd197d2 100644 --- a/src/target/nds32_disassembler.c +++ b/src/target/nds32_disassembler.c @@ -493,7 +493,7 @@ static int nds32_parse_mem(struct nds32 *nds32, uint32_t opcode, uint32_t addres switch (sub_opcode & 0x7) { case 0: /* LB */ nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), \ + &(instruction->info.ra), &(instruction->info.rb), &(instruction->info.imm)); instruction->type = NDS32_INSN_LOAD_STORE; nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 1e5db8c61..44825d002 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1207,8 +1207,8 @@ int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *file } static int or1k_checksum_memory(struct target *target, target_addr_t address, - uint32_t count, uint32_t *checksum) { - + uint32_t count, uint32_t *checksum) +{ return ERROR_FAIL; } diff --git a/src/target/openrisc/or1k_tap_vjtag.c b/src/target/openrisc/or1k_tap_vjtag.c index 607451a7c..db10f103b 100644 --- a/src/target/openrisc/or1k_tap_vjtag.c +++ b/src/target/openrisc/or1k_tap_vjtag.c @@ -149,7 +149,7 @@ static int or1k_tap_vjtag_init(struct or1k_jtag *jtag_info) * into the USER1 DR is sufficient to cover the most conservative case for m and n. */ - uint8_t t[4]; + uint8_t t[4] = { 0 }; struct scan_field field; struct jtag_tap *tap = jtag_info->tap; diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index ff67d3037..f1b3c6658 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -279,7 +279,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; buf_set_u32(out_value, 0, 32, out); @@ -421,7 +421,7 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, { riscv011_info_t *info = get_info(target); uint8_t in[8] = {0}; - uint8_t out[8]; + uint8_t out[8] = {0}; struct scan_field field = { .num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE, .out_value = out, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index bbe77e938..2c60a36d9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -69,7 +69,7 @@ static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address, uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); -void write_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t* write_data, +void write_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t *write_data, uint32_t write_size, uint32_t sbcs); void read_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs); @@ -425,7 +425,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out); @@ -495,6 +495,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, } memset(in, 0, num_bytes); + memset(out, 0, num_bytes); assert(info->abits != 0); @@ -723,10 +724,8 @@ uint32_t abstract_register_size(unsigned width) return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); case 64: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); - break; case 128: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); - break; default: LOG_ERROR("Unsupported register width: %d", width); return 0; @@ -2349,11 +2348,9 @@ static target_addr_t sb_read_address(struct target *target) target_addr_t address = 0; uint32_t v; if (sbasize > 32) { -#if BUILD_TARGET64 dmi_read(target, &v, DMI_SBADDRESS1); address |= v; address <<= 32; -#endif } dmi_read(target, &v, DMI_SBADDRESS0); address |= v; @@ -2370,11 +2367,7 @@ static int sb_write_address(struct target *target, target_addr_t address) if (sbasize > 64) dmi_write(target, DMI_SBADDRESS2, 0); if (sbasize > 32) -#if BUILD_TARGET64 dmi_write(target, DMI_SBADDRESS1, address >> 32); -#else - dmi_write(target, DMI_SBADDRESS1, 0); -#endif return dmi_write(target, DMI_SBADDRESS0, address); } @@ -4682,13 +4675,13 @@ int riscv013_test_compliance(struct target *target) But at any rate, this is not legal and should cause an error. */ COMPLIANCE_WRITE(target, DMI_COMMAND, 0xAAAAAAAA); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "Illegal COMMAND should result in UNSUPPORTED"); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); COMPLIANCE_WRITE(target, DMI_COMMAND, 0x55555555); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "Illegal COMMAND should result in UNSUPPORTED"); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 65b60cd90..97c21b59e 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -417,7 +417,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out); @@ -761,7 +761,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_FAIL; } - uint8_t buff[4]; + uint8_t buff[4] = { 0 }; buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); int const retval = target_write_memory(target, breakpoint->address, 2, breakpoint->length / 2, buff); @@ -995,12 +995,9 @@ static int oldriscv_step(struct target *target, int current, uint32_t address, return tt->step(target, current, address, handle_breakpoints); } -static int old_or_new_riscv_step( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints -){ +static int old_or_new_riscv_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ RISCV_INFO(r); LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) @@ -1785,7 +1782,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, /* Disable Interrupts before attempting to run the algorithm. */ uint64_t current_mstatus; - uint8_t mstatus_bytes[8]; + uint8_t mstatus_bytes[8] = { 0 }; LOG_DEBUG("Disabling Interrupts"); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, @@ -1862,7 +1859,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Restore registers */ - uint8_t buf[8]; + uint8_t buf[8] = { 0 }; buf_set_u64(buf, 0, info->xlen[0], saved_pc); if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) return ERROR_FAIL; @@ -2188,12 +2185,9 @@ int riscv_openocd_poll(struct target *target) return ERROR_OK; } -int riscv_openocd_step( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints -) { +int riscv_openocd_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ LOG_DEBUG("stepping rtos hart"); if (!current) @@ -2743,13 +2737,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "test_sba_config_reg", .handler = riscv_test_sba_config_reg, .mode = COMMAND_ANY, - .usage = "riscv test_sba_config_reg legal_address num_words" + .usage = "riscv test_sba_config_reg legal_address num_words " "illegal_address run_sbbusyerror_test[on/off]", - .help = "Perform a series of tests on the SBCS register." - "Inputs are a legal, 128-byte aligned address and a number of words to" - "read/write starting at that address (i.e., address range [legal address," - "legal_address+word_size*num_words) must be legally readable/writable)" - ", an illegal, 128-byte aligned address for error flag/handling cases," + .help = "Perform a series of tests on the SBCS register. " + "Inputs are a legal, 128-byte aligned address and a number of words to " + "read/write starting at that address (i.e., address range [legal address, " + "legal_address+word_size*num_words) must be legally readable/writable), " + "an illegal, 128-byte aligned address for error flag/handling cases, " "and whether sbbusyerror test should be run." }, { @@ -2824,11 +2818,6 @@ static const struct command_registration riscv_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -extern __COMMAND_HANDLER(handle_common_semihosting_command); -extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command); -extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command); -extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); - /* * To be noted that RISC-V targets use the same semihosting commands as * ARM targets. @@ -2842,37 +2831,7 @@ extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); * protocol, then a command like `riscv semihosting enable` will make * sense, but for now all semihosting commands are prefixed with `arm`. */ -static const struct command_registration arm_exec_command_handlers[] = { - { - .name = "semihosting", - .handler = handle_common_semihosting_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting operations", - }, - { - .name = "semihosting_cmdline", - .handler = handle_common_semihosting_cmdline, - .mode = COMMAND_EXEC, - .usage = "arguments", - .help = "command line arguments to be passed to program", - }, - { - .name = "semihosting_fileio", - .handler = handle_common_semihosting_fileio_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting fileio operations", - }, - { - .name = "semihosting_resexit", - .handler = handle_common_semihosting_resumable_exit_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting resumable exit", - }, - COMMAND_REGISTRATION_DONE -}; +extern const struct command_registration semihosting_common_handlers[]; const struct command_registration riscv_command_handlers[] = { { @@ -2887,7 +2846,7 @@ const struct command_registration riscv_command_handlers[] = { .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", - .chain = arm_exec_command_handlers + .chain = semihosting_common_handlers }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index ce6a79171..a02f2df3f 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -944,6 +944,8 @@ int semihosting_common(struct target *target) uint8_t *fn1 = malloc(len1+1); uint8_t *fn2 = malloc(len2+1); if (!fn1 || !fn2) { + free(fn1); + free(fn2); semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { @@ -1459,7 +1461,7 @@ static void semihosting_set_field(struct target *target, uint64_t value, /* ------------------------------------------------------------------------- * Common semihosting commands handlers. */ -__COMMAND_HANDLER(handle_common_semihosting_command) +static __COMMAND_HANDLER(handle_common_semihosting_command) { struct target *target = get_current_target(CMD_CTX); @@ -1500,8 +1502,7 @@ __COMMAND_HANDLER(handle_common_semihosting_command) return ERROR_OK; } - -__COMMAND_HANDLER(handle_common_semihosting_fileio_command) +static __COMMAND_HANDLER(handle_common_semihosting_fileio_command) { struct target *target = get_current_target(CMD_CTX); @@ -1531,7 +1532,7 @@ __COMMAND_HANDLER(handle_common_semihosting_fileio_command) return ERROR_OK; } -__COMMAND_HANDLER(handle_common_semihosting_cmdline) +static __COMMAND_HANDLER(handle_common_semihosting_cmdline) { struct target *target = get_current_target(CMD_CTX); unsigned int i; @@ -1564,7 +1565,7 @@ __COMMAND_HANDLER(handle_common_semihosting_cmdline) return ERROR_OK; } -__COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) +static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) { struct target *target = get_current_target(CMD_CTX); @@ -1593,3 +1594,35 @@ __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } + +const struct command_registration semihosting_common_handlers[] = { + { + "semihosting", + .handler = handle_common_semihosting_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting operations", + }, + { + "semihosting_cmdline", + .handler = handle_common_semihosting_cmdline, + .mode = COMMAND_EXEC, + .usage = "arguments", + .help = "command line arguments to be passed to program", + }, + { + "semihosting_fileio", + .handler = handle_common_semihosting_fileio_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting fileio operations", + }, + { + "semihosting_resexit", + .handler = handle_common_semihosting_resumable_exit_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting resumable exit", + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/startup.tcl b/src/target/startup.tcl index 4d4426f98..976cd2af5 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -66,7 +66,9 @@ proc ocd_process_reset_inner { MODE } { if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t invoke-event examine-start set err [catch "$t arp_examine allow-defer"] - if { $err == 0 } { + if { $err } { + $t invoke-event examine-fail + } else { $t invoke-event examine-end } } @@ -221,9 +223,3 @@ proc cortex_a8 args { echo "DEPRECATED! use 'cortex_a' not 'cortex_a8'" eval cortex_a $args } - -# deprecated ftdi cmds -proc ftdi_location args { - echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" - eval adapter usb location $args -} diff --git a/src/target/stm8.c b/src/target/stm8.c index fcfc1707e..ce8cfaa51 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1,20 +1,20 @@ /* - OpenOCD STM8 target driver - 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 . +* OpenOCD STM8 target driver +* 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 . */ #ifdef HAVE_CONFIG_H @@ -25,10 +25,9 @@ #include "target.h" #include "target_type.h" #include "hello.h" +#include "jtag/interface.h" #include "jtag/jtag.h" -#include "jtag/hla/hla_transport.h" -#include "jtag/hla/hla_interface.h" -#include "jtag/hla/hla_layout.h" +#include "jtag/swim.h" #include "register.h" #include "breakpoints.h" #include "algorithm.h" @@ -46,6 +45,8 @@ static int stm8_set_breakpoint(struct target *target, static void stm8_enable_watchpoints(struct target *target); static int stm8_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); +static int (*adapter_speed)(int speed); +extern struct adapter_driver *adapter_driver; static const struct { unsigned id; @@ -179,68 +180,31 @@ struct stm8_comparator { enum hw_break_type type; }; -static inline struct hl_interface_s *target_to_adapter(struct target *target) -{ - return target->tap->priv; -} - static int stm8_adapter_read_memory(struct target *target, uint32_t addr, int size, int count, void *buf) { - int ret; - struct hl_interface_s *adapter = target_to_adapter(target); - - ret = adapter->layout->api->read_mem(adapter->handle, - addr, size, count, buf); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; + return swim_read_mem(addr, size, count, buf); } static int stm8_adapter_write_memory(struct target *target, uint32_t addr, int size, int count, const void *buf) { - int ret; - struct hl_interface_s *adapter = target_to_adapter(target); - - ret = adapter->layout->api->write_mem(adapter->handle, - addr, size, count, buf); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; + return swim_write_mem(addr, size, count, buf); } static int stm8_write_u8(struct target *target, uint32_t addr, uint8_t val) { - int ret; uint8_t buf[1]; - struct hl_interface_s *adapter = target_to_adapter(target); buf[0] = val; - ret = adapter->layout->api->write_mem(adapter->handle, addr, 1, 1, buf); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; + return swim_write_mem(addr, 1, 1, buf); } static int stm8_read_u8(struct target *target, uint32_t addr, uint8_t *val) { - int ret; - struct hl_interface_s *adapter = target_to_adapter(target); - - ret = adapter->layout->api->read_mem(adapter->handle, addr, 1, 1, val); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; -} - -static int stm8_set_speed(struct target *target, int speed) -{ - struct hl_interface_s *adapter = target_to_adapter(target); - adapter->layout->api->speed(adapter->handle, speed, 0); - return ERROR_OK; + return swim_read_mem(addr, 1, 1, val); } /* @@ -355,7 +319,7 @@ static int stm8_set_hwbreak(struct target *target, if ((comparator_list[0].type != HWBRK_EXEC) && (comparator_list[1].type != HWBRK_EXEC)) { - if ((comparator_list[0].type != comparator_list[1].type)) { + if (comparator_list[0].type != comparator_list[1].type) { LOG_ERROR("data hw breakpoints must be of same type"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -835,8 +799,35 @@ static int stm8_read_memory(struct target *target, target_addr_t address, return retval; } +static int stm8_speed(int speed) +{ + int retval; + uint8_t csr; + + LOG_DEBUG("stm8_speed: %d", speed); + + csr = SAFE_MASK | SWIM_DM; + if (speed >= SWIM_FREQ_HIGH) + csr |= HS; + + LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS:%d)", csr & HS ? 1 : 0); + retval = stm8_write_u8(NULL, SWIM_CSR, csr); + if (retval != ERROR_OK) + return retval; + return adapter_speed(speed); +} + static int stm8_init(struct command_context *cmd_ctx, struct target *target) { + /* + * FIXME: this is a temporarily hack that needs better implementation. + * Being the only overwrite of adapter_driver, it prevents declaring const + * the struct adapter_driver. + * intercept adapter_driver->speed() calls + */ + adapter_speed = adapter_driver->speed; + adapter_driver->speed = stm8_speed; + stm8_build_reg_cache(target); return ERROR_OK; @@ -923,16 +914,13 @@ static int stm8_halt(struct target *target) static int stm8_reset_assert(struct target *target) { int res = ERROR_OK; - struct hl_interface_s *adapter = target_to_adapter(target); struct stm8_common *stm8 = target_to_stm8(target); bool use_srst_fallback = true; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { - jtag_add_reset(0, 1); - res = adapter->layout->api->assert_srst(adapter->handle, 0); - + res = adapter_assert_reset(); if (res == ERROR_OK) /* hardware srst supported */ use_srst_fallback = false; @@ -943,7 +931,7 @@ static int stm8_reset_assert(struct target *target) if (use_srst_fallback) { LOG_DEBUG("Hardware srst not supported, falling back to swim reset"); - res = adapter->layout->api->reset(adapter->handle); + res = swim_system_reset(); if (res != ERROR_OK) return res; } @@ -966,21 +954,14 @@ static int stm8_reset_assert(struct target *target) static int stm8_reset_deassert(struct target *target) { int res; - struct hl_interface_s *adapter = target_to_adapter(target); - enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { - res = adapter->layout->api->assert_srst(adapter->handle, 1); + res = adapter_deassert_reset(); if ((res != ERROR_OK) && (res != ERROR_COMMAND_NOTFOUND)) return res; } - /* virtual deassert reset, we need it for the internal - * jtag state machine - */ - jtag_add_reset(0, 0); - /* The cpu should now be stalled. If halt was requested let poll detect the stall */ if (target->reset_halt) @@ -1704,34 +1685,26 @@ static int stm8_examine(struct target *target) uint8_t csr1, csr2; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); - struct hl_interface_s *adapter = target_to_adapter(target); + enum reset_types jtag_reset_config = jtag_get_reset_config(); if (!target_was_examined(target)) { if (!stm8->swim_configured) { - /* set SWIM_CSR = 0xa0 (enable mem access & mask reset) */ - LOG_DEBUG("writing A0 to SWIM_CSR (SAFE_MASK + SWIM_DM)"); - retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM); - if (retval != ERROR_OK) - return retval; - /* set high speed */ - LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS)"); - retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS); - if (retval != ERROR_OK) - return retval; - retval = stm8_set_speed(target, 1); - if (retval == ERROR_OK) - stm8->swim_configured = true; + stm8->swim_configured = true; /* Now is the time to deassert reset if connect_under_reset. Releasing reset line will cause the option bytes to load. The core will still be stalled. */ - if (adapter->param.connect_under_reset) - stm8_reset_deassert(target); + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + stm8_reset_deassert(target); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } } else { LOG_INFO("trying to reconnect"); - retval = adapter->layout->api->state(adapter->handle); + retval = swim_reconnect(); if (retval != ERROR_OK) { LOG_ERROR("reconnect failed"); return ERROR_FAIL; diff --git a/src/target/stm8.h b/src/target/stm8.h index 39fac3e32..da7f1f119 100644 --- a/src/target/stm8.h +++ b/src/target/stm8.h @@ -1,20 +1,20 @@ /* - OpenOCD STM8 target driver - 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 . +* OpenOCD STM8 target driver +* 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 . */ #ifndef OPENOCD_TARGET_STM8_H diff --git a/src/target/target.c b/src/target/target.c index 5ac66c40c..bccafbfa2 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -94,6 +94,7 @@ extern struct target_type cortexr4_target; extern struct target_type arm11_target; extern struct target_type ls1_sap_target; extern struct target_type mips_m4k_target; +extern struct target_type mips_mips64_target; extern struct target_type avr_target; extern struct target_type dsp563xx_target; extern struct target_type dsp5680xx_target; @@ -110,6 +111,7 @@ extern struct target_type stm8_target; extern struct target_type riscv_target; extern struct target_type mem_ap_target; extern struct target_type esirisc_target; +extern struct target_type arcv2_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -145,9 +147,9 @@ static struct target_type *target_types[] = { &riscv_target, &mem_ap_target, &esirisc_target, -#if BUILD_TARGET64 + &arcv2_target, &aarch64_target, -#endif + &mips_mips64_target, NULL, }; @@ -201,6 +203,8 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_RESUMED, .name = "resumed" }, { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" }, { .value = TARGET_EVENT_RESUME_END, .name = "resume-end" }, + { .value = TARGET_EVENT_STEP_START, .name = "step-start" }, + { .value = TARGET_EVENT_STEP_END, .name = "step-end" }, { .name = "gdb-start", .value = TARGET_EVENT_GDB_START }, { .name = "gdb-end", .value = TARGET_EVENT_GDB_END }, @@ -215,6 +219,7 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" }, + { .value = TARGET_EVENT_EXAMINE_FAIL, .name = "examine-fail" }, { .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" }, { .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" }, @@ -704,13 +709,17 @@ static int default_check_reset(struct target *target) return ERROR_OK; } +/* Equvivalent Tcl code arp_examine_one is in src/target/startup.tcl + * Keep in sync */ int target_examine_one(struct target *target) { target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); int retval = target->type->examine(target); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_FAIL); return retval; + } target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); @@ -1247,7 +1256,17 @@ bool target_supports_gdb_connection(struct target *target) int target_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { - return target->type->step(target, current, address, handle_breakpoints); + int retval; + + target_call_event_callbacks(target, TARGET_EVENT_STEP_START); + + retval = target->type->step(target, current, address, handle_breakpoints); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_STEP_END); + + return retval; } int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) @@ -1687,7 +1706,7 @@ static int target_call_timer_callbacks_check_time(int checktime) * next item; initially, that's a standalone "root of the * list" variable. */ struct target_timer_callback **callback = &target_timer_callbacks; - while (*callback) { + while (callback && *callback) { if ((*callback)->removed) { struct target_timer_callback *p = *callback; *callback = (*callback)->next; @@ -2047,6 +2066,8 @@ static void target_destroy(struct target *target) target->smp = 0; } + rtos_destroy(target); + free(target->gdb_port_override); free(target->type); free(target->trace_info); @@ -2290,7 +2311,7 @@ static int target_read_buffer_default(struct target *target, target_addr_t addre return ERROR_OK; } -int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* crc) +int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc) { uint8_t *buffer; int retval; @@ -3158,7 +3179,7 @@ COMMAND_HANDLER(handle_step_command) struct target *target = get_current_target(CMD_CTX); - return target->type->step(target, current_pc, addr, 1); + return target_step(target, current_pc, addr, 1); } void target_handle_md_output(struct command_invocation *cmd, @@ -3360,8 +3381,8 @@ COMMAND_HANDLER(handle_mw_command) target_addr_t address; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - target_addr_t value; - COMMAND_PARSE_ADDRESS(CMD_ARGV[1], value); + uint64_t value; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], value); unsigned count = 1; if (CMD_ARGC == 3) @@ -3660,14 +3681,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver data = malloc(buf_cnt); - /* Can we use 32bit word accesses? */ - int size = 1; - int count = buf_cnt; - if ((count % 4) == 0) { - size *= 4; - count /= 4; - } - retval = target_read_memory(target, image.sections[i].base_address, size, count, data); + retval = target_read_buffer(target, image.sections[i].base_address, buf_cnt, data); if (retval == ERROR_OK) { uint32_t t; for (t = 0; t < buf_cnt; t++) { @@ -3849,11 +3863,16 @@ COMMAND_HANDLER(handle_rbp_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - target_addr_t addr; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - struct target *target = get_current_target(CMD_CTX); - breakpoint_remove(target, addr); + + if (!strcmp(CMD_ARGV[0], "all")) { + breakpoint_remove_all(target); + } else { + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + + breakpoint_remove(target, addr); + } return ERROR_OK; } @@ -5017,7 +5036,7 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv if (goi.argc > 0 && strcmp(Jim_GetString(argv[1], NULL), "allow-defer") == 0) { /* consume it */ - struct Jim_Obj *obj; + Jim_Obj *obj; int e = Jim_GetOpt_Obj(&goi, &obj); if (e != JIM_OK) return e; @@ -5187,7 +5206,6 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a "target: %s wait %s fails (%#s) %s", target_name(target), n->name, eObj, target_strerror_safe(e)); - Jim_FreeNewObj(interp, eObj); return JIM_ERR; } return JIM_OK; @@ -6241,7 +6259,7 @@ static const struct command_registration target_exec_command_handlers[] = { .name = "halt", .handler = handle_halt_command, .mode = COMMAND_EXEC, - .help = "request target to halt, then wait up to the specified" + .help = "request target to halt, then wait up to the specified " "number of milliseconds (default 5000) for it to complete", .usage = "[milliseconds]", }, @@ -6257,7 +6275,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_reset_command, .mode = COMMAND_EXEC, .usage = "[run|halt|init]", - .help = "Reset all targets into the specified mode." + .help = "Reset all targets into the specified mode. " "Default reset mode is run, if not given.", }, { @@ -6342,7 +6360,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_rbp_command, .mode = COMMAND_EXEC, .help = "remove breakpoint", - .usage = "address", + .usage = "'all' | address", }, { .name = "wp", diff --git a/src/target/target.h b/src/target/target.h index 89077144b..57440006c 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -32,6 +32,7 @@ #define OPENOCD_TARGET_TARGET_H #include +#include struct reg; struct trace; @@ -258,6 +259,8 @@ enum target_event { TARGET_EVENT_RESUMED, /* target resumed to normal execution */ TARGET_EVENT_RESUME_START, TARGET_EVENT_RESUME_END, + TARGET_EVENT_STEP_START, + TARGET_EVENT_STEP_END, TARGET_EVENT_GDB_START, /* debugger started execution (step/run) */ TARGET_EVENT_GDB_END, /* debugger stopped execution (step/run) */ @@ -275,6 +278,7 @@ enum target_event { TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */ TARGET_EVENT_EXAMINE_START, + TARGET_EVENT_EXAMINE_FAIL, TARGET_EVENT_EXAMINE_END, TARGET_EVENT_GDB_ATTACH, @@ -290,8 +294,8 @@ enum target_event { struct target_event_action { enum target_event event; - struct Jim_Interp *interp; - struct Jim_Obj *body; + Jim_Interp *interp; + Jim_Obj *body; struct target_event_action *next; }; @@ -763,6 +767,7 @@ void target_handle_md_output(struct command_invocation *cmd, #define ERROR_TARGET_NOT_RUNNING (-310) #define ERROR_TARGET_NOT_EXAMINED (-311) #define ERROR_TARGET_DUPLICATE_BREAKPOINT (-312) +#define ERROR_TARGET_ALGO_EXIT (-313) extern bool get_target_reset_nag(void); diff --git a/src/target/xscale.c b/src/target/xscale.c index 1a099c946..edab4f9fc 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -129,7 +129,7 @@ static const struct xscale_reg xscale_reg_arch_info[] = { /* convenience wrapper to access XScale specific registers */ static int xscale_set_reg_u32(struct reg *reg, uint32_t value) { - uint8_t buf[4]; + uint8_t buf[4] = { 0 }; buf_set_u32(buf, 0, 32, value); @@ -154,9 +154,9 @@ static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_s if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; - uint8_t scratch[4]; + uint8_t scratch[4] = { 0 }; - memset(&field, 0, sizeof field); + memset(&field, 0, sizeof(field)); field.num_bits = tap->ir_length; field.out_value = scratch; buf_set_u32(scratch, 0, field.num_bits, new_instr); @@ -186,7 +186,7 @@ static int xscale_read_dcsr(struct target *target) buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0; @@ -259,7 +259,7 @@ static int xscale_receive(struct target *target, uint32_t *buffer, int num_words path[1] = TAP_DRCAPTURE; path[2] = TAP_DRSHIFT; - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; uint8_t tmp; @@ -367,7 +367,7 @@ static int xscale_read_tx(struct target *target, int consume) noconsume_path[4] = TAP_DREXIT2; noconsume_path[5] = TAP_DRSHIFT; - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].in_value = &field0_in; @@ -442,7 +442,7 @@ static int xscale_write_rx(struct target *target) XSCALE_DBGRX << xscale->xscale_variant, TAP_IDLE); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0_out; @@ -514,7 +514,7 @@ static int xscale_send(struct target *target, const uint8_t *buffer, int count, TAP_IDLE); static const uint8_t t0; - uint8_t t1[4]; + uint8_t t1[4] = { 0 }; static const uint8_t t2 = 1; struct scan_field fields[3] = { { .num_bits = 3, .out_value = &t0 }, @@ -598,7 +598,7 @@ static int xscale_write_dcsr(struct target *target, int hold_rst, int ext_dbg_br buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0; @@ -645,8 +645,8 @@ static unsigned int parity(unsigned int v) static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8]) { struct xscale_common *xscale = target_to_xscale(target); - uint8_t packet[4]; - uint8_t cmd; + uint8_t packet[4] = { 0 }; + uint8_t cmd = 0; int word; struct scan_field fields[2]; @@ -666,7 +666,7 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 6; fields[0].out_value = &cmd; @@ -699,8 +699,8 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] static int xscale_invalidate_ic_line(struct target *target, uint32_t va) { struct xscale_common *xscale = target_to_xscale(target); - uint8_t packet[4]; - uint8_t cmd; + uint8_t packet[4] = { 0 }; + uint8_t cmd = 0; struct scan_field fields[2]; xscale_jtag_set_instr(target->tap, @@ -713,7 +713,7 @@ static int xscale_invalidate_ic_line(struct target *target, uint32_t va) /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 6; fields[0].out_value = &cmd; @@ -1551,7 +1551,7 @@ static int xscale_deassert_reset(struct target *target) * coprocessors, trace data, etc. */ address = xscale->handler_address; - for (unsigned binary_size = sizeof xscale_debug_handler; + for (unsigned binary_size = sizeof(xscale_debug_handler); binary_size > 0; binary_size -= buf_cnt, buffer += buf_cnt) { uint32_t cache_line[8]; @@ -2981,7 +2981,7 @@ static int xscale_init_arch_info(struct target *target, /* prepare ARMv4/5 specific information */ arm->arch_info = xscale; - arm->core_type = ARM_MODE_ANY; + arm->core_type = ARM_CORE_TYPE_STD; arm->read_core_reg = xscale_read_core_reg; arm->write_core_reg = xscale_write_core_reg; arm->full_context = xscale_full_context; @@ -3004,7 +3004,7 @@ static int xscale_target_create(struct target *target, Jim_Interp *interp) { struct xscale_common *xscale; - if (sizeof xscale_debug_handler > 0x800) { + if (sizeof(xscale_debug_handler) > 0x800) { LOG_ERROR("debug_handler.bin: larger than 2kb"); return ERROR_FAIL; } @@ -3227,7 +3227,6 @@ COMMAND_HANDLER(xscale_handle_vector_catch_command) if (retval != ERROR_OK) return retval; - dcsr_value = buf_get_u32(dcsr_reg->value, 0, 32); if (CMD_ARGC > 0) { if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "all") == 0) { diff --git a/src/transport/transport.c b/src/transport/transport.c index 77db9e210..010ea7c44 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -290,7 +290,6 @@ static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *a } Jim_SetResultString(interp, session->name, -1); return JIM_OK; - break; case 2: /* assign */ if (session) { if (!strcmp(session->name, argv[1]->bytes)) { @@ -327,7 +326,6 @@ static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *a LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes); return JIM_ERR; - break; default: Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]"); return JIM_ERR; diff --git a/src/transport/transport.h b/src/transport/transport.h index 140ef503d..809564e78 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -96,6 +96,9 @@ bool transports_are_declared(void); bool transport_is_jtag(void); bool transport_is_swd(void); +bool transport_is_dapdirect_jtag(void); +bool transport_is_dapdirect_swd(void); +bool transport_is_swim(void); #if BUILD_HLADAPTER bool transport_is_hla(void); diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index e574c6f0e..bec32f21e 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -918,8 +918,10 @@ COMMAND_HANDLER(handle_xsvf_command) struct scan_field field; result = svf_add_statemove(loop_state); - if (result != ERROR_OK) + if (result != ERROR_OK) { + free(dr_in_mask); return result; + } jtag_add_clocks(loop_clocks); jtag_add_sleep(loop_usecs); diff --git a/tcl/bitsbytes.tcl b/tcl/bitsbytes.tcl index 2c4fd2907..52ca83db2 100644 --- a/tcl/bitsbytes.tcl +++ b/tcl/bitsbytes.tcl @@ -57,5 +57,3 @@ proc show_normalize_bitfield { VALUE MSB LSB } { echo [format "((0x%08x & 0x%08x) -> 0x%08x) >> %2d => (0x%x) %5d " $VALUE $m $mr $LSB $sr $sr] return $sr } - - diff --git a/tcl/board/actux3.cfg b/tcl/board/actux3.cfg index 5435ff885..0de4cb4ca 100644 --- a/tcl/board/actux3.cfg +++ b/tcl/board/actux3.cfg @@ -4,7 +4,7 @@ reset_config trst_and_srst separate -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 source [find target/ixp42x.cfg] diff --git a/tcl/board/adsp-sc584-ezbrd.cfg b/tcl/board/adsp-sc584-ezbrd.cfg index 1054a941f..82df381f6 100644 --- a/tcl/board/adsp-sc584-ezbrd.cfg +++ b/tcl/board/adsp-sc584-ezbrd.cfg @@ -25,7 +25,6 @@ source [find interface/jlink.cfg] transport select swd # chosen speed is 'safe' choice, but your adapter may be capable of more -adapter_khz 400 +adapter speed 400 source [find target/adsp-sc58x.cfg] - diff --git a/tcl/board/alphascale_asm9260_ek.cfg b/tcl/board/alphascale_asm9260_ek.cfg index 46e8a5b5b..1c126827f 100644 --- a/tcl/board/alphascale_asm9260_ek.cfg +++ b/tcl/board/alphascale_asm9260_ek.cfg @@ -23,7 +23,7 @@ $_TARGETNAME configure -event reset-init { # select PLL as main source mww 0x80040120 0x1 - # disable and enble main clk to update changes? + # disable and enable main clk to update changes? mww 0x80040124 0x0 mww 0x80040124 0x1 diff --git a/tcl/board/altera_sockit.cfg b/tcl/board/altera_sockit.cfg index 569414331..eb4c863fa 100644 --- a/tcl/board/altera_sockit.cfg +++ b/tcl/board/altera_sockit.cfg @@ -7,7 +7,7 @@ # openocd does not currently support the on-board USB Blaster II. # Install the JTAG header and use a USB Blaster instead. -interface usb_blaster +adapter driver usb_blaster source [find target/altera_fpgasoc.cfg] @@ -15,5 +15,4 @@ source [find target/altera_fpgasoc.cfg] #usb_blaster_vid_pid 0x6810 0x09fb #usb_blaster_device_desc "USB-Blaster II" -adapter_khz 100 - +adapter speed 100 diff --git a/tcl/board/am3517evm.cfg b/tcl/board/am3517evm.cfg index 2bff51246..8d6eba160 100644 --- a/tcl/board/am3517evm.cfg +++ b/tcl/board/am3517evm.cfg @@ -18,4 +18,3 @@ source [find target/amdm37x.cfg] reset_config trst_only # "amdm37x_dbginit am35x.cpu" needs to be run after init. - diff --git a/tcl/board/arm_evaluator7t.cfg b/tcl/board/arm_evaluator7t.cfg index 52de57afe..96d859cd3 100644 --- a/tcl/board/arm_evaluator7t.cfg +++ b/tcl/board/arm_evaluator7t.cfg @@ -7,4 +7,3 @@ source [find target/samsung_s3c4510.cfg] # Add (A) sdram configuration # Add (B) flash cfi programing configuration # - diff --git a/tcl/board/arm_musca_a.cfg b/tcl/board/arm_musca_a.cfg index fa7cf5eef..25f8ce61a 100644 --- a/tcl/board/arm_musca_a.cfg +++ b/tcl/board/arm_musca_a.cfg @@ -15,7 +15,7 @@ source [find target/swj-dp.tcl] # set a safe JTAG clock speed, can be overridden -adapter_khz 1000 +adapter speed 1000 global _CHIPNAME if { [info exists CHIPNAME] } { diff --git a/tcl/board/arty_s7.cfg b/tcl/board/arty_s7.cfg index ca7d3f1c4..5ab408391 100644 --- a/tcl/board/arty_s7.cfg +++ b/tcl/board/arty_s7.cfg @@ -10,7 +10,7 @@ source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] -adapter_khz 25000 +adapter speed 25000 # Usage: # diff --git a/tcl/board/at91cap7a-stk-sdram.cfg b/tcl/board/at91cap7a-stk-sdram.cfg index 9bc02e8c0..8395ba33b 100644 --- a/tcl/board/at91cap7a-stk-sdram.cfg +++ b/tcl/board/at91cap7a-stk-sdram.cfg @@ -28,7 +28,7 @@ target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAM $_TARGETNAME configure -event reset-start { # start off real slow when we're running off internal RC oscillator - adapter_khz 32 + adapter speed 32 } proc peek32 {address} { @@ -43,13 +43,13 @@ proc wait_state {expression} { return } } - return -code 1 "Timed out" + return -code 1 "Timed out" } # Use a global variable here to be able to tinker interactively with # post reset jtag frequency. global post_reset_khz -# Danger!!!! Even 16MHz kinda works with this target, but +# Danger!!!! Even 16MHz kinda works with this target, but # it needs to be as low as 2000kHz to be stable. set post_reset_khz 2000 @@ -61,25 +61,25 @@ $_TARGETNAME configure -event reset-init { mww 0xfffffd08 0xa5000001 # Enable main oscillator mww 0xFFFFFc20 0x00000f01 - wait_state {expr {([peek32 0xFFFFFC68] & 0x1) == 0}} + wait_state {expr {([peek32 0xFFFFFC68] & 0x1) == 0}} # Set PLLA to 96MHz mww 0xFFFFFc28 0x20072801 - wait_state {expr {([peek32 0xFFFFFC68] & 0x2) == 0}} + wait_state {expr {([peek32 0xFFFFFC68] & 0x2) == 0}} # Select prescaler mww 0xFFFFFC30 0x00000004 - wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} + wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} # Select master clock to 48MHz mww 0xFFFFFC30 0x00000006 - wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} + wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} echo "Master clock ok." - + # Now that we're up and running, crank up speed! - global post_reset_khz ; adapter_khz $post_reset_khz - + global post_reset_khz ; adapter speed $post_reset_khz + echo "Configuring the SDRAM controller..." # Configure EBI Chip select for SDRAM @@ -95,7 +95,7 @@ $_TARGETNAME configure -event reset-init { # Configure SDRAMC CR mww 0xFFFFEA08 0xA63392F9 - + # NOP command mww 0xFFFFEA00 0x1 mww 0x20000000 0 @@ -151,7 +151,7 @@ $_TARGETNAME configure -event reset-init { #remap internal memory at address 0x0 mww 0xffffef00 0x3 - + echo "SDRAM configuration ok." } @@ -162,4 +162,3 @@ arm7_9 fast_memory_access enable #set _FLASHNAME $_CHIPNAME.flash #flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 - diff --git a/tcl/board/at91eb40a.cfg b/tcl/board/at91eb40a.cfg index d8a82a59d..d314e181d 100644 --- a/tcl/board/at91eb40a.cfg +++ b/tcl/board/at91eb40a.cfg @@ -64,4 +64,4 @@ $_TARGETNAME configure -event reset-init { } # This target is pretty snappy... -adapter_khz 16000 +adapter speed 16000 diff --git a/tcl/board/at91rm9200-dk.cfg b/tcl/board/at91rm9200-dk.cfg index f484fded1..b8ec00eab 100644 --- a/tcl/board/at91rm9200-dk.cfg +++ b/tcl/board/at91rm9200-dk.cfg @@ -19,7 +19,7 @@ flash bank $_FLASHNAME cfi 0x10000000 0x00200000 2 2 $_TARGETNAME proc at91rm9200_dk_init { } { # Try to run at 1khz... Yea, that slow! # Chip is really running @ 32khz - adapter_khz 8 + adapter speed 8 mww 0xfffffc64 0xffffffff ## disable all clocks but system clock @@ -45,7 +45,7 @@ proc at91rm9200_dk_init { } { #======================================== # CPU now runs at 180mhz # SYS runs at 60mhz. - adapter_khz 40000 + adapter speed 40000 #======================================== diff --git a/tcl/board/at91rm9200-ek.cfg b/tcl/board/at91rm9200-ek.cfg index a3f253a26..958bc9d51 100644 --- a/tcl/board/at91rm9200-ek.cfg +++ b/tcl/board/at91rm9200-ek.cfg @@ -19,12 +19,12 @@ set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # The chip may run @ 32khz, so set a really low JTAG speed -adapter_khz 8 +adapter speed 8 proc at91rm9200_ek_init { } { # Try to run at 1khz... Yea, that slow! # Chip is really running @ 32khz - adapter_khz 8 + adapter speed 8 mww 0xfffffc64 0xffffffff ## disable all clocks but system clock @@ -61,7 +61,7 @@ proc at91rm9200_ek_init { } { #======================================== # CPU now runs at 180mhz # SYS runs at 60mhz. - adapter_khz 40000 + adapter speed 40000 #======================================== ## Init SDRAM diff --git a/tcl/board/at91sam9g20-ek.cfg b/tcl/board/at91sam9g20-ek.cfg index 741d6018d..03296c50e 100644 --- a/tcl/board/at91sam9g20-ek.cfg +++ b/tcl/board/at91sam9g20-ek.cfg @@ -19,7 +19,7 @@ set _FLASHTYPE nandflash_cs3 reset_config srst_only -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 # If you don't want to execute built-in boot rom code (and there are good reasons at times not to do that) in the @@ -54,7 +54,7 @@ proc at91sam9g20_reset_start { } { # jtag speed without causing GDB keep alive problem. arm7_9 fast_memory_access disable - adapter_khz 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow. + adapter speed 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow. halt ;# Make sure processor is halted, or error will result in following steps. wait_halt 10000 mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset. @@ -103,7 +103,7 @@ proc at91sam9g20_reset_init { } { # Switch over to adaptive clocking. - adapter_khz 0 + adapter speed 0 # Enable faster DCC downloads and memory accesses. @@ -139,13 +139,13 @@ proc at91sam9g20_reset_init { } { # (MT29F2G08AACWP) can be established by setting four registers in order: SMC_SETUP3, # SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. Computing the exact values of these registers # is a little tedious to do here. If you have questions about how to do this, Atmel has - # a decent application note #6255B that covers this process. + # a decent application note #6255B that covers this process. mww 0xffffec30 0x00020002 ;# SMC_SETUP3 : 2 clock cycle setup for NRD and NWE mww 0xffffec34 0x04040404 ;# SMC_PULSE3 : 4 clock cycle pulse for all signals mww 0xffffec38 0x00070006 ;# SMC_CYCLE3 : 7 clock cycle NRD and 6 NWE cycle - mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, - + mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, + mww 0xffffe800 0x00000001 ;# ECC_CR : reset the ECC parity registers mww 0xffffe804 0x00000002 ;# ECC_MR : page size is 2112 words (word is 8 bits) @@ -169,7 +169,7 @@ proc at91sam9g20_reset_init { } { # TRC = 9 cycles # TWR = 2 cycles # 9 column, 13 row, 4 banks - # refresh equal to or less then 7.8 us for commerical/industrial rated devices + # refresh equal to or less then 7.8 us for commercial/industrial rated devices # # Thus SDRAM_CR = 0xa6339279 @@ -216,4 +216,3 @@ proc at91sam9g20_reset_init { } { mww 0xffffea04 0x0000039c } - diff --git a/tcl/board/atmel_at91sam7s-ek.cfg b/tcl/board/atmel_at91sam7s-ek.cfg index d7e848654..48edfc9a7 100644 --- a/tcl/board/atmel_at91sam7s-ek.cfg +++ b/tcl/board/atmel_at91sam7s-ek.cfg @@ -4,5 +4,3 @@ set CHIPNAME at91sam7s256 source [find target/at91sam7sx.cfg] - - diff --git a/tcl/board/atmel_sam3n_ek.cfg b/tcl/board/atmel_sam3n_ek.cfg index 2ae73ebfa..e43008f10 100644 --- a/tcl/board/atmel_sam3n_ek.cfg +++ b/tcl/board/atmel_sam3n_ek.cfg @@ -7,6 +7,6 @@ reset_config srst_only set CHIPNAME at91sam3n4c -adapter_khz 32 +adapter speed 32 source [find target/at91sam3nXX.cfg] diff --git a/tcl/board/atmel_sam3u_ek.cfg b/tcl/board/atmel_sam3u_ek.cfg index 13d930b1d..1584879bf 100644 --- a/tcl/board/atmel_sam3u_ek.cfg +++ b/tcl/board/atmel_sam3u_ek.cfg @@ -1,4 +1,3 @@ source [find target/at91sam3u4e.cfg] reset_config srst_only - diff --git a/tcl/board/avnet_ultrazed-eg.cfg b/tcl/board/avnet_ultrazed-eg.cfg index 9879bfcb1..3e4a11a3e 100644 --- a/tcl/board/avnet_ultrazed-eg.cfg +++ b/tcl/board/avnet_ultrazed-eg.cfg @@ -9,7 +9,7 @@ transport select jtag reset_config none # slow default clock -adapter_khz 1000 +adapter speed 1000 set CHIPNAME uscale diff --git a/tcl/board/bcm28155_ap.cfg b/tcl/board/bcm28155_ap.cfg index fb729e191..5d3d22a3e 100644 --- a/tcl/board/bcm28155_ap.cfg +++ b/tcl/board/bcm28155_ap.cfg @@ -1,9 +1,8 @@ # BCM28155_AP -adapter_khz 20000 +adapter speed 20000 set CHIPNAME bcm28155 source [find target/bcm281xx.cfg] reset_config trst_and_srst - diff --git a/tcl/board/bluefield.cfg b/tcl/board/bluefield.cfg new file mode 100644 index 000000000..3058d48ca --- /dev/null +++ b/tcl/board/bluefield.cfg @@ -0,0 +1,6 @@ +# +# Board configuration for BlueField SoC. +# + +source [find interface/rshim.cfg] +source [find target/bluefield.cfg] diff --git a/tcl/board/colibri.cfg b/tcl/board/colibri.cfg index 7c1f1cb51..0f30afd09 100644 --- a/tcl/board/colibri.cfg +++ b/tcl/board/colibri.cfg @@ -1,13 +1,9 @@ # Toradex Colibri PXA270 source [find target/pxa270.cfg] reset_config trst_and_srst srst_push_pull -adapter_nsrst_assert_width 40 +adapter srst pulse_width 40 # CS0 -- one bank of CFI flash, 32 MBytes # the bank is 32-bits wide, two 16-bit chips in parallel set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME - - - - diff --git a/tcl/board/crossbow_tech_imote2.cfg b/tcl/board/crossbow_tech_imote2.cfg index 002b5372f..277c353a1 100644 --- a/tcl/board/crossbow_tech_imote2.cfg +++ b/tcl/board/crossbow_tech_imote2.cfg @@ -4,7 +4,7 @@ set CHIPNAME imote2 source [find target/pxa270.cfg] # longer-than-normal reset delay -adapter_nsrst_delay 800 +adapter srst delay 800 reset_config trst_and_srst separate diff --git a/tcl/board/csb337.cfg b/tcl/board/csb337.cfg index 5e225f5f5..a9d013929 100644 --- a/tcl/board/csb337.cfg +++ b/tcl/board/csb337.cfg @@ -19,7 +19,7 @@ if { [info exists ETM_DRIVER] } { proc csb337_clk_init { } { # CPU is in Slow Clock Mode (32KiHz) ... needs slow JTAG clock - adapter_khz 8 + adapter speed 8 # CKGR_MOR: start main oscillator (3.6864 MHz) mww 0xfffffc20 0xff01 @@ -37,7 +37,7 @@ proc csb337_clk_init { } { sleep 20 # CPU is in Normal Mode ... allows faster JTAG clock speed - adapter_khz 40000 + adapter speed 40000 } proc csb337_nor_init { } { diff --git a/tcl/board/csb732.cfg b/tcl/board/csb732.cfg index 4d6f0e489..35e397ff2 100644 --- a/tcl/board/csb732.cfg +++ b/tcl/board/csb732.cfg @@ -3,7 +3,7 @@ source [find target/imx35.cfg] # Determined by trial and error reset_config trst_and_srst combined -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 $_TARGETNAME configure -event gdb-attach { reset init } diff --git a/tcl/board/digi_connectcore_wi-9c.cfg b/tcl/board/digi_connectcore_wi-9c.cfg index 8a8d4c3bf..43ad1c90e 100644 --- a/tcl/board/digi_connectcore_wi-9c.cfg +++ b/tcl/board/digi_connectcore_wi-9c.cfg @@ -36,7 +36,7 @@ if { [info exists CPUTAPID] } { set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 0 diff --git a/tcl/board/digilent_analog_discovery.cfg b/tcl/board/digilent_analog_discovery.cfg index d356fc0f4..954e54008 100644 --- a/tcl/board/digilent_analog_discovery.cfg +++ b/tcl/board/digilent_analog_discovery.cfg @@ -7,12 +7,12 @@ # https://github.com/bvanheu/urjtag-ad/commit/8bd883ee01d134f94b79cbbd00df42cd03bafd71 # -interface ftdi +adapter driver ftdi ftdi_device_desc "Digilent USB Device" ftdi_vid_pid 0x0403 0x6014 ftdi_layout_init 0x8008 0x800b -adapter_khz 25000 +adapter speed 25000 source [find cpld/xilinx-xc6s.cfg] diff --git a/tcl/board/dk-tm4c129.cfg b/tcl/board/dk-tm4c129.cfg old mode 100755 new mode 100644 index f1171af12..2c7de290d --- a/tcl/board/dk-tm4c129.cfg +++ b/tcl/board/dk-tm4c129.cfg @@ -1,14 +1,3 @@ -# -# TI Tiva C DK-TM4C129X Connected Development Kit -# -# http://www.ti.com/tool/dk-tm4c129x -# +echo "WARNING: board/dk-tm4c129.cfg is deprecated, please switch to board/ti_dk-tm4c129.cfg" -source [find interface/ti-icdi.cfg] - -transport select hla_jtag - -set WORKAREASIZE 0x8000 -set CHIPNAME tm4c129xnczad - -source [find target/stellaris.cfg] +source [find board/ti_dk-tm4c129.cfg] diff --git a/tcl/board/dm365evm.cfg b/tcl/board/dm365evm.cfg index 8f268c455..3b29dd866 100644 --- a/tcl/board/dm365evm.cfg +++ b/tcl/board/dm365evm.cfg @@ -103,7 +103,7 @@ proc dm365evm_init {} { echo "Initialize DM365 EVM board" # CLKIN = 24 MHz ... can't talk quickly to ARM yet - adapter_khz 1500 + adapter speed 1500 # FIXME -- PLL init @@ -143,5 +143,3 @@ proc dm365evm_init {} { flashprobe } - - diff --git a/tcl/board/dp_busblaster_v3.cfg b/tcl/board/dp_busblaster_v3.cfg index f21197b73..a9974d9bc 100644 --- a/tcl/board/dp_busblaster_v3.cfg +++ b/tcl/board/dp_busblaster_v3.cfg @@ -4,7 +4,7 @@ # http://dangerousprototypes.com/docs/Bus_Blaster # # To reprogram the on-board CPLD do: -# openocd -f board/dp_busblaster_v3.cfg -c "adapter_khz 1000; init; svf ; shutdown" +# openocd -f board/dp_busblaster_v3.cfg -c "adapter speed 1000; init; svf ; shutdown" # source [find interface/ftdi/dp_busblaster.cfg] diff --git a/tcl/board/efm32.cfg b/tcl/board/efm32.cfg index d2bc9a611..adbdda72e 100644 --- a/tcl/board/efm32.cfg +++ b/tcl/board/efm32.cfg @@ -5,7 +5,7 @@ source [find interface/jlink.cfg] transport select swd -adapter_khz 1000 +adapter speed 1000 set CHIPNAME efm32 source [find target/efm32.cfg] diff --git a/tcl/board/eir.cfg b/tcl/board/eir.cfg index a014e116b..422db0d88 100644 --- a/tcl/board/eir.cfg +++ b/tcl/board/eir.cfg @@ -91,4 +91,3 @@ $_TARGETNAME configure -event reset-init { # mww 0xfffffd08 0xa5000001 } - diff --git a/tcl/board/ek-lm3s1968.cfg b/tcl/board/ek-lm3s1968.cfg index 8d990b198..bbb04baa6 100644 --- a/tcl/board/ek-lm3s1968.cfg +++ b/tcl/board/ek-lm3s1968.cfg @@ -5,7 +5,7 @@ # # NOTE: to use J-Link instead of the on-board interface, -# you may also need to reduce adapter_khz to be about 1200. +# you may also need to reduce adapter speed to be about 1200. # source [find interface/jlink.cfg] # include the FT2232 interface config for on-board JTAG interface diff --git a/tcl/board/ek-tm4c123gxl.cfg b/tcl/board/ek-tm4c123gxl.cfg index 4fc1050c7..3e497ba19 100644 --- a/tcl/board/ek-tm4c123gxl.cfg +++ b/tcl/board/ek-tm4c123gxl.cfg @@ -1,13 +1,3 @@ -# -# TI Tiva C Series ek-tm4c123gxl Launchpad Evaluation Kit -# -# http://www.ti.com/tool/ek-tm4c123gxl -# +echo "WARNING: board/ek-tm4c123gxl.cfg is deprecated, please switch to board/ti_ek-tm4c123gxl.cfg" -source [find interface/ti-icdi.cfg] - -transport select hla_jtag - -set WORKAREASIZE 0x8000 -set CHIPNAME tm4c123gh6pm -source [find target/stellaris.cfg] +source [find board/ti_ek-tm4c123gxl.cfg] diff --git a/tcl/board/ek-tm4c1294xl.cfg b/tcl/board/ek-tm4c1294xl.cfg index b3f384c0e..676386680 100644 --- a/tcl/board/ek-tm4c1294xl.cfg +++ b/tcl/board/ek-tm4c1294xl.cfg @@ -1,14 +1,3 @@ -# -# TI Tiva C Series ek-tm4c1294xl Launchpad Evaluation Kit -# -# http://www.ti.com/tool/ek-tm4c1294xl -# +echo "WARNING: board/ek-tm4c1294xl.cfg is deprecated, please switch to board/ti_ek-tm4c1294xl.cfg" -source [find interface/ti-icdi.cfg] - -transport select hla_jtag - -set WORKAREASIZE 0x8000 -set CHIPNAME tm4c1294ncpdt - -source [find target/stellaris.cfg] +source [find board/ti_ek-tm4c1294xl.cfg] diff --git a/tcl/board/embedded-artists_lpc2478-32.cfg b/tcl/board/embedded-artists_lpc2478-32.cfg index b036cd69c..8ef9179de 100644 --- a/tcl/board/embedded-artists_lpc2478-32.cfg +++ b/tcl/board/embedded-artists_lpc2478-32.cfg @@ -15,7 +15,7 @@ proc read_register {register} { proc init_board {} { # Delays on reset lines - adapter_nsrst_delay 500 + adapter srst delay 500 jtag_ntrst_delay 1 # Adaptive JTAG clocking through RTCK. @@ -151,4 +151,3 @@ proc enable_pll {} { mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED } - diff --git a/tcl/board/emcraft_imx8m-som-bsb.cfg b/tcl/board/emcraft_imx8m-som-bsb.cfg index 5571d0ecb..248c0d400 100644 --- a/tcl/board/emcraft_imx8m-som-bsb.cfg +++ b/tcl/board/emcraft_imx8m-som-bsb.cfg @@ -6,13 +6,13 @@ transport select jtag # set a safe JTAG clock speed, can be overridden -adapter_khz 1000 +adapter speed 1000 # SRST and TRST are wired up reset_config trst_and_srst # delay after SRST goes inactive -adapter_nsrst_delay 70 +adapter srst delay 70 # board has an i.MX8MQ with 4 Cortex-A53 cores set CHIPNAME imx8mq diff --git a/tcl/board/ethernut3.cfg b/tcl/board/ethernut3.cfg index ad4552733..72fc5ade3 100644 --- a/tcl/board/ethernut3.cfg +++ b/tcl/board/ethernut3.cfg @@ -20,13 +20,13 @@ flash bank $_FLASHNAME cfi 0x10000000 0x400000 2 2 $_TARGETNAME # Micrel MIC2775-29YM5 Supervisor # Reset output will remain active for 280ms (maximum) # -adapter_nsrst_delay 300 +adapter srst delay 300 jtag_ntrst_delay 300 arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable -adapter_khz 16000 +adapter speed 16000 # Target events diff --git a/tcl/board/fsl_imx6q_sabresd.cfg b/tcl/board/fsl_imx6q_sabresd.cfg index e1f0892f0..cf34cd16d 100644 --- a/tcl/board/fsl_imx6q_sabresd.cfg +++ b/tcl/board/fsl_imx6q_sabresd.cfg @@ -13,7 +13,7 @@ transport select jtag # iMX6Q POR gates JTAG and the chip is completely incommunicado # over JTAG for at least 10ms after nSRST is deasserted -adapter_nsrst_delay 11 +adapter srst delay 11 # Source generic iMX6Q target configuration set CHIPNAME imx6q @@ -144,4 +144,4 @@ $_TARGETNAME.0 configure -event reset-assert { } # hook the init function into the reset-init event $_TARGETNAME.0 configure -event reset-init { imx6q_sabresd_init } # set a slow default JTAG clock, can be overridden later -adapter_khz 1000 +adapter speed 1000 diff --git a/tcl/board/glyn_tonga2.cfg b/tcl/board/glyn_tonga2.cfg index 17ed3cf20..f48702ca6 100644 --- a/tcl/board/glyn_tonga2.cfg +++ b/tcl/board/glyn_tonga2.cfg @@ -19,12 +19,12 @@ source [find target/tmpa900.cfg] # Initial JTAG speed should not exceed 1/6 of the initial CPU clock # frequency (24MHz). Be conservative and use 1/8 of the frequency. # (24MHz / 8 = 3MHz) -adapter_khz 3000 +adapter speed 3000 $_TARGETNAME configure -event reset-start { # Upon reset, set the JTAG frequency to 3MHz again, see above. echo "Setting JTAG speed to 3MHz until clocks are initialized." - adapter_khz 3000 + adapter speed 3000 # Halt the CPU. halt @@ -41,7 +41,7 @@ $_TARGETNAME configure -event reset-init { # Tests showed that 15MHz works OK, higher speeds can cause problems, # though. Not sure if this is a CPU issue or JTAG adapter issue. echo "Increasing JTAG speed to 15MHz." - adapter_khz 15000 + adapter speed 15000 # Enable faster memory access. arm7_9 fast_memory_access enable @@ -197,4 +197,3 @@ proc tonga2_init { } { ####################### # TODO: Implement NAND support. - diff --git a/tcl/board/gumstix-aerocore.cfg b/tcl/board/gumstix-aerocore.cfg index ba217c043..f0103ed45 100644 --- a/tcl/board/gumstix-aerocore.cfg +++ b/tcl/board/gumstix-aerocore.cfg @@ -1,6 +1,6 @@ # JTAG for the STM32F4x chip used on the Gumstix AeroCore is available on # the first interface of a Quad FTDI chip. nTRST is bit 4. -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6011 ftdi_layout_init 0x0000 0x001b diff --git a/tcl/board/hilscher_nxdb500sys.cfg b/tcl/board/hilscher_nxdb500sys.cfg index 77073e729..20fa3ea03 100644 --- a/tcl/board/hilscher_nxdb500sys.cfg +++ b/tcl/board/hilscher_nxdb500sys.cfg @@ -5,7 +5,7 @@ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 @@ -17,7 +17,7 @@ $_TARGETNAME configure -event reset-init { arm7_9 dcc_downloads enable sdram_fix - + puts "Configuring SDRAM controller for paired K4S561632C (64MB) " mww 0x00100140 0 mww 0x00100144 0x03C13261 diff --git a/tcl/board/hilscher_nxeb500hmi.cfg b/tcl/board/hilscher_nxeb500hmi.cfg index 64391561e..a51fa03bc 100644 --- a/tcl/board/hilscher_nxeb500hmi.cfg +++ b/tcl/board/hilscher_nxeb500hmi.cfg @@ -5,7 +5,7 @@ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 @@ -17,7 +17,7 @@ $_TARGETNAME configure -event reset-init { arm7_9 dcc_downloads disable sdram_fix - + puts "Configuring SDRAM controller for MT48LC8M32 (32MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 diff --git a/tcl/board/hilscher_nxhx10.cfg b/tcl/board/hilscher_nxhx10.cfg index 4ef2f3b96..add424d4e 100644 --- a/tcl/board/hilscher_nxhx10.cfg +++ b/tcl/board/hilscher_nxhx10.cfg @@ -9,7 +9,7 @@ source [find target/hilscher_netx10.cfg] # problems try to line below # reset_config trst_and_srst srst_pulls_trst reset_config trst_and_srst -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x08000000 -work-area-phys 0x08000000 -work-area-size 0x4000 -work-area-backup 1 @@ -79,4 +79,4 @@ $_TARGETNAME configure -event reset-init { #flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init -reset init \ No newline at end of file +reset init diff --git a/tcl/board/hilscher_nxhx50.cfg b/tcl/board/hilscher_nxhx50.cfg index eebb16524..0867f2ed6 100644 --- a/tcl/board/hilscher_nxhx50.cfg +++ b/tcl/board/hilscher_nxhx50.cfg @@ -5,7 +5,7 @@ source [find target/hilscher_netx50.cfg] reset_config trst_and_srst -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x10000000 -work-area-phys 0x10000000 -work-area-size 0x4000 -work-area-backup 1 diff --git a/tcl/board/hilscher_nxhx500.cfg b/tcl/board/hilscher_nxhx500.cfg index dd3a9514d..2ba030ec1 100644 --- a/tcl/board/hilscher_nxhx500.cfg +++ b/tcl/board/hilscher_nxhx500.cfg @@ -5,7 +5,7 @@ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 diff --git a/tcl/board/hilscher_nxsb100.cfg b/tcl/board/hilscher_nxsb100.cfg index efb091b10..c332beec0 100644 --- a/tcl/board/hilscher_nxsb100.cfg +++ b/tcl/board/hilscher_nxsb100.cfg @@ -5,7 +5,7 @@ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 @@ -17,7 +17,7 @@ $_TARGETNAME configure -event reset-init { arm7_9 dcc_downloads enable sdram_fix - + puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 diff --git a/tcl/board/hitex_lpc1768stick.cfg b/tcl/board/hitex_lpc1768stick.cfg index 161e9654a..ac176cad7 100644 --- a/tcl/board/hitex_lpc1768stick.cfg +++ b/tcl/board/hitex_lpc1768stick.cfg @@ -11,5 +11,4 @@ source [find target/lpc17xx.cfg] # startup @ 500kHz -adapter_khz 500 - +adapter speed 500 diff --git a/tcl/board/hitex_lpc2929.cfg b/tcl/board/hitex_lpc2929.cfg index d2515371d..2fe1f3cda 100644 --- a/tcl/board/hitex_lpc2929.cfg +++ b/tcl/board/hitex_lpc2929.cfg @@ -2,12 +2,12 @@ # http://www.hitex.com/ # Delays on reset lines -adapter_nsrst_delay 50 +adapter srst delay 50 jtag_ntrst_delay 1 # Maximum of 1/8 of clock frequency (XTAL = 16 MHz). # Adaptive clocking through RTCK is not supported. -adapter_khz 2000 +adapter speed 2000 # Target device: LPC29xx with ETB # The following variables are used by the LPC2900 script: @@ -24,7 +24,7 @@ $_TARGETNAME configure -work-area-phys 0x58000000 -work-area-size 0x10000 -work- # Event handlers $_TARGETNAME configure -event reset-start { # Back to the slow JTAG clock - adapter_khz 2000 + adapter speed 2000 } # External 16-bit flash at chip select CS7 (SST39VF3201-70, 4 MiB) @@ -46,7 +46,7 @@ $_TARGETNAME configure -event reset-init { mww 0xFFFF8070 0x02000000 ;# SYS_CLK_CONF: PLL # Increase JTAG speed - adapter_khz 6000 + adapter speed 6000 # Enable external memory bus (16-bit SRAM at CS6, 16-bit flash at CS7) mww 0xE0001138 0x0000001F ;# P1.14 = D0 @@ -103,4 +103,3 @@ $_TARGETNAME configure -event reset-init { mww 0x600000CC 0x0000000C ;# Bank7 WST2=8 mww 0x600000C4 0x00000002 ;# Bank7 IDCY=2 } - diff --git a/tcl/board/hitex_stm32-performancestick.cfg b/tcl/board/hitex_stm32-performancestick.cfg index 82fb16961..74dc5839a 100644 --- a/tcl/board/hitex_stm32-performancestick.cfg +++ b/tcl/board/hitex_stm32-performancestick.cfg @@ -12,5 +12,4 @@ source [find target/stm32f1x.cfg] jtag newtap str750 cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id 0x4f1f0041 # for some reason this board like to startup @ 500kHz -adapter_khz 500 - +adapter speed 500 diff --git a/tcl/board/hitex_str9-comstick.cfg b/tcl/board/hitex_str9-comstick.cfg index be153314f..3b9225213 100644 --- a/tcl/board/hitex_str9-comstick.cfg +++ b/tcl/board/hitex_str9-comstick.cfg @@ -5,9 +5,9 @@ source [find interface/ftdi/hitex_str9-comstick.cfg] # set jtag speed -adapter_khz 3000 +adapter speed 3000 -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst diff --git a/tcl/board/iar_lpc1768.cfg b/tcl/board/iar_lpc1768.cfg index d8c8c2d71..38ffc3582 100644 --- a/tcl/board/iar_lpc1768.cfg +++ b/tcl/board/iar_lpc1768.cfg @@ -14,4 +14,3 @@ $_TARGETNAME configure -event reset-init { flash probe 0 } - diff --git a/tcl/board/iar_str912_sk.cfg b/tcl/board/iar_str912_sk.cfg index ba060a046..54f517b73 100644 --- a/tcl/board/iar_str912_sk.cfg +++ b/tcl/board/iar_str912_sk.cfg @@ -1,3 +1,3 @@ # The IAR str912-sk evaluation kick start board has an str912 -source [find target/str912.cfg] \ No newline at end of file +source [find target/str912.cfg] diff --git a/tcl/board/icnova_imx53_sodimm.cfg b/tcl/board/icnova_imx53_sodimm.cfg index aa6a148a0..dce9c470e 100644 --- a/tcl/board/icnova_imx53_sodimm.cfg +++ b/tcl/board/icnova_imx53_sodimm.cfg @@ -15,14 +15,14 @@ echo "i.MX53 SO-Dimm board lodaded." # Set reset type #reset_config srst_only -adapter_khz 3000 +adapter speed 3000 # Slow speed to be sure it will work jtag_rclk 1000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } $_TARGETNAME configure -event "reset-assert" { - echo "Reseting ...." + echo "Resetting ...." #cortex_a dbginit } @@ -58,7 +58,7 @@ proc sodimm_init { } { arm core_state arm jtag_rclk 3000 -# adapter_khz 3000 +# adapter speed 3000 } diff --git a/tcl/board/icnova_sam9g45_sodimm.cfg b/tcl/board/icnova_sam9g45_sodimm.cfg index 84dab3899..30dc34748 100644 --- a/tcl/board/icnova_sam9g45_sodimm.cfg +++ b/tcl/board/icnova_sam9g45_sodimm.cfg @@ -15,7 +15,7 @@ source [find target/at91sam9g45.cfg] # Set reset type. # reset_config trst_and_srst -# adapter_nsrst_delay 200 +# adapter srst delay 200 # jtag_ntrst_delay 200 @@ -58,7 +58,7 @@ proc at91sam9g45_start { } { arm7_9 fast_memory_access disable # Slow-speed oscillator enabled at reset, so run jtag speed slow. - adapter_khz 4 + adapter speed 4 # Make sure processor is halted, or error will result in following steps. halt wait_halt 10000 @@ -117,7 +117,7 @@ proc at91sam9g45_init { } { # Switch over to adaptive clocking. - adapter_khz 6000 + adapter speed 6000 # Enable faster DCC downloads. @@ -274,5 +274,3 @@ proc at91sam9g45_init { } { arm7_9 fast_memory_access enable } - - diff --git a/tcl/board/imx27lnst.cfg b/tcl/board/imx27lnst.cfg index e0ed05794..ac5a9f3e6 100644 --- a/tcl/board/imx27lnst.cfg +++ b/tcl/board/imx27lnst.cfg @@ -8,7 +8,7 @@ proc imx27lnst_init { } { # This setup puts RAM at 0xA0000000 # reset the board correctly - adapter_khz 500 + adapter speed 500 reset run reset halt diff --git a/tcl/board/imx31pdk.cfg b/tcl/board/imx31pdk.cfg index 502d40774..2dce157db 100644 --- a/tcl/board/imx31pdk.cfg +++ b/tcl/board/imx31pdk.cfg @@ -28,36 +28,36 @@ proc imx31pdk_init { } { mww 0x53FC0000 0x040 mww 0x53F80000 0x074B0B7D - + # 399MHz - 26MHz input, PD=1,MFI=7, MFN=27, MFD=40 #mww 0x53F80004 0xFF871D50 #mww 0x53F80010 0x00271C1B - + # Start 16 bit NorFlash Initialization on CS0 mww 0xb8002000 0x0000CC03 mww 0xb8002004 0xa0330D01 mww 0xb8002008 0x00220800 - + # Configure CPLD on CS4 mww 0xb8002040 0x0000DCF6 mww 0xb8002044 0x444A4541 mww 0xb8002048 0x44443302 - + # SDCLK mww 0x43FAC26C 0 - + # CAS mww 0x43FAC270 0 - + # RAS mww 0x43FAC274 0 - + # CS2 (CSD0) mww 0x43FAC27C 0x1000 - + # DQM3 mww 0x43FAC284 0 - + # DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2DC) mww 0x43FAC288 0 mww 0x43FAC28C 0 @@ -81,7 +81,7 @@ proc imx31pdk_init { } { mww 0x43FAC2D4 0 mww 0x43FAC2D8 0 mww 0x43FAC2DC 0 - + # Initialization script for 32 bit DDR on MX31 ADS mww 0xB8001010 0x00000004 mww 0xB8001004 0x006ac73a diff --git a/tcl/board/imx35pdk.cfg b/tcl/board/imx35pdk.cfg index b5aa752fa..2a7efaba7 100644 --- a/tcl/board/imx35pdk.cfg +++ b/tcl/board/imx35pdk.cfg @@ -8,9 +8,9 @@ $_TARGETNAME configure -event reset-init { imx35pdk_init } jtag_rclk 10 proc imx35pdk_init { } { - + imx3x_reset - + mww 0x43f00040 0x00000000 mww 0x43f00044 0x00000000 mww 0x43f00048 0x00000000 @@ -25,11 +25,11 @@ proc imx35pdk_init { } { mww 0x53f00050 0x00000000 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 - + # clock setup mww 0x53F80004 0x00821000 ;# first need to set IPU_HND_BYP mww 0x53F80004 0x00821000 ;#arm clock is 399Mhz and ahb clock is 133Mhz. - + #================================================= # WEIM config #================================================= @@ -45,14 +45,14 @@ proc imx35pdk_init { } { mww 0xB8002054 0x444a4541 # CS5A mww 0xB8002058 0x44443302 - + # IO SW PAD Control registers - setting of 0x0002 is high drive, mDDR mww 0x43FAC368 0x00000006 mww 0x43FAC36C 0x00000006 mww 0x43FAC370 0x00000006 mww 0x43FAC374 0x00000006 mww 0x43FAC378 0x00000006 - mww 0x43FAC37C 0x00000006 + mww 0x43FAC37C 0x00000006 mww 0x43FAC380 0x00000006 mww 0x43FAC384 0x00000006 mww 0x43FAC388 0x00000006 @@ -76,7 +76,7 @@ proc imx35pdk_init { } { mww 0x43FAC3D0 0x00000006 mww 0x43FAC3D4 0x00000006 mww 0x43FAC3D8 0x00000006 - + # DDR data bus SD 0 through 31 mww 0x43FAC3DC 0x00000082 mww 0x43FAC3E0 0x00000082 @@ -110,13 +110,13 @@ proc imx35pdk_init { } { mww 0x43FAC450 0x00000082 mww 0x43FAC454 0x00000082 mww 0x43FAC458 0x00000082 - + # DQM setup mww 0x43FAC45c 0x00000082 mww 0x43FAC460 0x00000082 mww 0x43FAC464 0x00000082 mww 0x43FAC468 0x00000082 - + mww 0x43FAC46c 0x00000006 mww 0x43FAC470 0x00000006 mww 0x43FAC474 0x00000006 @@ -130,30 +130,30 @@ proc imx35pdk_init { } { mww 0x43FAC494 0x00000006 mww 0x43FAC498 0x00000006 mww 0x43FAC49c 0x00000006 - mww 0x43FAC4A0 0x00000006 + mww 0x43FAC4A0 0x00000006 mww 0x43FAC4A4 0x00000006 ;# RAS mww 0x43FAC4A8 0x00000006 ;# CAS mww 0x43FAC4Ac 0x00000006 ;# SDWE mww 0x43FAC4B0 0x00000006 ;# SDCKE0 mww 0x43FAC4B4 0x00000006 ;# SDCKE1 mww 0x43FAC4B8 0x00000002 ;# SDCLK - + # SDQS0 through SDQS3 mww 0x43FAC4Bc 0x00000082 mww 0x43FAC4C0 0x00000082 mww 0x43FAC4C4 0x00000082 mww 0x43FAC4C8 0x00000082 - - + + # *================================================== # Initialization script for 32 bit DDR2 on RINGO 3DS # *================================================== - + #-------------------------------------------- # Init CCM #-------------------------------------------- mww 0x53F80028 0x7D000028 - + #-------------------------------------------- # Init IOMUX for JTAG #-------------------------------------------- @@ -164,24 +164,24 @@ proc imx35pdk_init { } { mww 0x43FAC5FC 0x000000F3 mww 0x43FAC600 0x000000F3 mww 0x43FAC604 0x000000F3 - - + + # ESD_MISC : enable DDR2 mww 0xB8001010 0x00000304 - + #-------------------------------------------- - # Init 32-bit DDR2 memeory on CSD0 + # Init 32-bit DDR2 memory on CSD0 # COL=10-bit, ROW=13-bit, BA[1:0]=Addr[26:25] #-------------------------------------------- - - # ESD_ESDCFG0 : set timing paramters - mww 0xB8001004 0x007ffC2f - + + # ESD_ESDCFG0 : set timing parameters + mww 0xB8001004 0x007ffC2f + # ESD_ESDCTL0 : select Prechare-All mode mww 0xB8001000 0x92220000 # DDR2 : Prechare-All mww 0x80000400 0x12345678 - + # ESD_ESDCTL0 : select Load-Mode-Register mode mww 0xB8001000 0xB2220000 # DDR2 : Load reg EMR2 @@ -192,18 +192,18 @@ proc imx35pdk_init { } { mwb 0x82000400 0xda # DDR2 : Load reg MR -- reset DLL mwb 0x80000333 0xda - + # ESD_ESDCTL0 : select Prechare-All mode mww 0xB8001000 0x92220000 # DDR2 : Prechare-All mwb 0x80000400 0x12345678 - + # ESD_ESDCTL0 : select Manual-Refresh mode mww 0xB8001000 0xA2220000 # DDR2 : Manual-Refresh 2 times mww 0x80000000 0x87654321 mww 0x80000000 0x87654321 - + # ESD_ESDCTL0 : select Load-Mode-Register mode mww 0xB8001000 0xB2220000 # DDR2 : Load reg MR -- CL=3, BL=8, end DLL reset @@ -212,19 +212,19 @@ proc imx35pdk_init { } { mwb 0x82000780 0xda # DDR2 : Load reg EMR1 -- OCD exit mwb 0x82000400 0xda ;# ODT disabled - + # ESD_ESDCTL0 : select normal-operation mode # DSIZ=32-bit, BL=8, COL=10-bit, ROW=13-bit # disable PWT & PRCT # disable Auto-Refresh mww 0xB8001000 0x82220080 - + ## ESD_ESDCTL0 : enable Auto-Refresh mww 0xB8001000 0x82228080 ## ESD_ESDCTL1 : enable Auto-Refresh mww 0xB8001008 0x00002000 - - + + #*********************************************** # Adjust the ESDCDLY5 register #*********************************************** @@ -233,20 +233,20 @@ proc imx35pdk_init { } { mww 0xB8001024 0x00F48000 ;# this is the default value mww 0xB8001028 0x00F48000 ;# this is the default value mww 0xB800102c 0x00F48000 ;# this is the default value - - + + #Then you can make force measure with the dedicated bit (Bit 7 at ESDMISC) mww 0xB8001010 0x00000384 # wait a while sleep 1000 # now clear the force measurement bit mww 0xB8001010 0x00000304 - + # dummy write to DDR memory to set DQS low mww 0x80000000 0x00000000 - + mww 0x30000100 0x0 mww 0x30000104 0x31024 - - + + } diff --git a/tcl/board/imx53-m53evk.cfg b/tcl/board/imx53-m53evk.cfg index eada27ab6..baeb3cd9d 100644 --- a/tcl/board/imx53-m53evk.cfg +++ b/tcl/board/imx53-m53evk.cfg @@ -18,10 +18,10 @@ echo "iMX53 M53EVK board lodaded." reset_config trst_and_srst separate trst_open_drain srst_open_drain # Run at 6 MHz -adapter_khz 6000 +adapter speed 6000 $_TARGETNAME configure -event "reset-assert" { - echo "Reseting ...." + echo "Resetting ...." #cortex_a dbginit } diff --git a/tcl/board/imx53loco.cfg b/tcl/board/imx53loco.cfg index 06c399378..18caca574 100644 --- a/tcl/board/imx53loco.cfg +++ b/tcl/board/imx53loco.cfg @@ -13,7 +13,7 @@ echo "iMX53 Loco board lodaded." # Set reset type #reset_config srst_only -adapter_khz 3000 +adapter speed 3000 # Slow speed to be sure it will work jtag_rclk 1000 @@ -23,7 +23,7 @@ $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } #jtag_ntrst_delay 200 $_TARGETNAME configure -event "reset-assert" { - echo "Reseting ...." + echo "Resetting ...." #cortex_a dbginit } @@ -59,7 +59,7 @@ proc loco_init { } { arm core_state arm jtag_rclk 3000 -# adapter_khz 3000 +# adapter speed 3000 } diff --git a/tcl/board/imx8mp-evk.cfg b/tcl/board/imx8mp-evk.cfg new file mode 100644 index 000000000..97a303ac7 --- /dev/null +++ b/tcl/board/imx8mp-evk.cfg @@ -0,0 +1,15 @@ +# +# configuration file for NXP MC-IMX8MP-EVK +# +# Board includes FTDI-based JTAG adapter: interface/ftdi/imx8mp-evk.cfg +# + +transport select jtag +adapter speed 1000 +reset_config srst_only +adapter srst delay 100 + +set CHIPNAME imx8mp +set CHIPCORES 4 + +source [find target/imx8m.cfg] diff --git a/tcl/board/insignal_arndale.cfg b/tcl/board/insignal_arndale.cfg index 25c123e7b..09a7223f0 100644 --- a/tcl/board/insignal_arndale.cfg +++ b/tcl/board/insignal_arndale.cfg @@ -5,4 +5,4 @@ source [find target/exynos5250.cfg] # Experimentally determined highest working speed -adapter_khz 200 +adapter speed 200 diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg index 2c5e26853..06cc1e6c0 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -1,4 +1,4 @@ -interface ftdi +adapter driver ftdi ftdi_device_desc "Quad RS232-HS" ftdi_vid_pid 0x0403 0x6011 ftdi_channel 0 @@ -7,7 +7,7 @@ ftdi_layout_init 0x0008 0x000b reset_config none transport select jtag -adapter_khz 25000 +adapter speed 25000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] diff --git a/tcl/board/kc100.cfg b/tcl/board/kc100.cfg new file mode 100644 index 000000000..1d383bef5 --- /dev/null +++ b/tcl/board/kc100.cfg @@ -0,0 +1,31 @@ +# Knovative KC-100 cable modem + +# TNETC4401PYP, 208-QFP U3 +source [find target/tnetc4401.cfg] + +# 14-pin EJTAG on JP1. Standard pinout, 1-3-5-7-9-11 = nTRST-TDI-TDO-TMS-TCK-nSRST. Use 2 for GND. +# Was initially disabled in hardware; had to add a solder bridge reenabling R124, R125 on back. +reset_config trst_and_srst separate + +# 16Mb Intel CFI flash. Note this CPU has an internal ROM at 0x1FC0000 (phys) for cold boot. +# All that really does is some minimal checks before jumping to external flash at 0x00000000 phys. +# That is remapped to 0xB0000000 uncached, 0x90000000 cached. +flash bank intel cfi 0xB0000000 0x200000 2 2 $_TARGETNAME + +# Perform this after a clean reboot, halt, and reset init (which should also leave it halted). +proc kc100_dump_flash {} { + echo "Probing 48 TSOP Intel CFI flash chip (2MB)..." + flash probe intel + echo "Dumping 2MB flash chip to flashdump.bin. + flash read_bank 0 flashdump.bin 0 0x200000 +} + +#TODO figure out memory init sequence to be able to dump from cached segment instead + +# There is also a serial console on JP2, 3-5-6 = TX-RX-GND. 9600/8/N/1. + +# Possibly of note, this modem's ancient ethernet port does not support Auto-MDIX. + +# This modem in many ways appears to be essentially a clone of the SB5120. See usbjtag.com. +# The firmware/OS is also susceptible to many of the same procedures in "Hacking the Cable Modem" +# by DerEngel (Ryan Harris), available from No Starch Press. diff --git a/tcl/board/kc705.cfg b/tcl/board/kc705.cfg index e032e9b21..51ea14d46 100644 --- a/tcl/board/kc705.cfg +++ b/tcl/board/kc705.cfg @@ -5,7 +5,7 @@ source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] source [find fpga/xilinx-dna.cfg] -adapter_khz 25000 +adapter speed 25000 # example command to write bitstream, soft-cpu bios and runtime: # openocd -f board/kc705.cfg -c "init;\ diff --git a/tcl/board/kcu105.cfg b/tcl/board/kcu105.cfg index c8daea652..e2b68ca75 100644 --- a/tcl/board/kcu105.cfg +++ b/tcl/board/kcu105.cfg @@ -8,4 +8,4 @@ source [find cpld/xilinx-xcu.cfg] source [find cpld/jtagspi.cfg] -adapter_khz 25000 +adapter speed 25000 diff --git a/tcl/board/keil_mcb1700.cfg b/tcl/board/keil_mcb1700.cfg index d63d3ede9..05f12dfba 100644 --- a/tcl/board/keil_mcb1700.cfg +++ b/tcl/board/keil_mcb1700.cfg @@ -5,4 +5,3 @@ # source [find target/lpc17xx.cfg] - diff --git a/tcl/board/keil_mcb2140.cfg b/tcl/board/keil_mcb2140.cfg index db81efad5..bb41a2ab5 100644 --- a/tcl/board/keil_mcb2140.cfg +++ b/tcl/board/keil_mcb2140.cfg @@ -5,4 +5,3 @@ # source [find target/lpc2148.cfg] - diff --git a/tcl/board/kindle2.cfg b/tcl/board/kindle2.cfg index f32b2a321..a39f15c67 100644 --- a/tcl/board/kindle2.cfg +++ b/tcl/board/kindle2.cfg @@ -18,7 +18,7 @@ source [find target/imx31.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { kindle2_init } -$_TARGETNAME configure -event reset-start { adapter_khz 1000 } +$_TARGETNAME configure -event reset-start { adapter speed 1000 } # 8MiB NOR Flash set _FLASHNAME $_CHIPNAME.flash @@ -36,7 +36,7 @@ jtag_ntrst_delay 30 # this is broken but enabled by default arm11 memwrite burst disable -adapter_khz 1000 +adapter speed 1000 ftdi_tdo_sample_edge falling proc kindle2_init {} { @@ -162,7 +162,7 @@ proc kindle2_sdram_init {} { # LPDDR1 Initialization script mww 0xb8001010 0x00000002 mww 0xb8001010 0x00000004 - # ESDCFG0: set timing paramters + # ESDCFG0: set timing parameters mww 0xb8001004 0x007fff7f # ESDCTL0: select Prechare-All mode mww 0xb8001000 0x92100000 diff --git a/tcl/board/linksys_nslu2.cfg b/tcl/board/linksys_nslu2.cfg index e605fc19e..0b0f58b84 100644 --- a/tcl/board/linksys_nslu2.cfg +++ b/tcl/board/linksys_nslu2.cfg @@ -5,4 +5,3 @@ source [find target/ixp42x.cfg] # The _TARGETNAME is set by the above. $_TARGETNAME configure -work-area-phys 0x00020000 -work-area-size 0x10000 -work-area-backup 0 - diff --git a/tcl/board/lubbock.cfg b/tcl/board/lubbock.cfg index 298954cc0..d803e6fb2 100644 --- a/tcl/board/lubbock.cfg +++ b/tcl/board/lubbock.cfg @@ -4,7 +4,7 @@ source [find target/pxa255.cfg] -adapter_nsrst_delay 250 +adapter srst delay 250 jtag_ntrst_delay 250 # NOTE: until after pinmux and such are set up, only CS0 is diff --git a/tcl/board/marsohod.cfg b/tcl/board/marsohod.cfg index 681f575cc..b1393a914 100644 --- a/tcl/board/marsohod.cfg +++ b/tcl/board/marsohod.cfg @@ -6,7 +6,7 @@ # Recommended MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] -adapter_khz 2000 +adapter speed 2000 transport select jtag # Altera MAXII EPM240T100C CPLD diff --git a/tcl/board/marsohod2.cfg b/tcl/board/marsohod2.cfg index d4897c3c3..31819a2f9 100644 --- a/tcl/board/marsohod2.cfg +++ b/tcl/board/marsohod2.cfg @@ -6,7 +6,7 @@ # Built-in MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] -adapter_khz 2000 +adapter speed 2000 transport select jtag # Cyclone III EP3C10E144 FPGA diff --git a/tcl/board/marsohod3.cfg b/tcl/board/marsohod3.cfg index bb3c74f28..fa00706d3 100644 --- a/tcl/board/marsohod3.cfg +++ b/tcl/board/marsohod3.cfg @@ -6,7 +6,7 @@ # Built-in MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] -adapter_khz 2000 +adapter speed 2000 transport select jtag # MAX10 10M50SAE144C8GES FPGA diff --git a/tcl/board/mcb1700.cfg b/tcl/board/mcb1700.cfg index 068a19b24..01080a0b1 100644 --- a/tcl/board/mcb1700.cfg +++ b/tcl/board/mcb1700.cfg @@ -1,5 +1,5 @@ # Keil MCB1700 PCB with 1768 -# +# # Reset init script sets it to 100MHz set CCLK 100000 @@ -11,7 +11,7 @@ set MCB1700_CCLK $CCLK $_TARGETNAME configure -event reset-start { # Start *real slow* as we do not know the # state the boot rom left the clock in - adapter_khz 10 + adapter speed 10 } # Set up 100MHz clock to CPU @@ -53,9 +53,9 @@ $_TARGETNAME configure -event reset-init { # Dividing CPU clock by 8 should be pretty conservative # - # + # global MCB1700_CCLK - adapter_khz [expr $MCB1700_CCLK / 8] + adapter speed [expr $MCB1700_CCLK / 8] # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, diff --git a/tcl/board/microchip_same54_xplained_pro.cfg b/tcl/board/microchip_same54_xplained_pro.cfg index db8a8561d..7482de47f 100644 --- a/tcl/board/microchip_same54_xplained_pro.cfg +++ b/tcl/board/microchip_same54_xplained_pro.cfg @@ -10,4 +10,3 @@ set CHIPNAME same54 source [find target/atsame5x.cfg] reset_config srst_only - diff --git a/tcl/board/microchip_saml11_xplained_pro.cfg b/tcl/board/microchip_saml11_xplained_pro.cfg index 3558a8e71..2ab61118f 100644 --- a/tcl/board/microchip_saml11_xplained_pro.cfg +++ b/tcl/board/microchip_saml11_xplained_pro.cfg @@ -4,7 +4,7 @@ # source [find interface/cmsis-dap.cfg] -adapter_khz 1000 +adapter speed 1000 set CHIPNAME saml11 source [find target/atsaml1x.cfg] diff --git a/tcl/board/mini2440.cfg b/tcl/board/mini2440.cfg index 874f829ab..9dca5a37c 100644 --- a/tcl/board/mini2440.cfg +++ b/tcl/board/mini2440.cfg @@ -111,7 +111,7 @@ target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup 1 #reset configuration -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst @@ -120,7 +120,7 @@ reset_config trst_and_srst # IMPORTANT! See README at top of this file. #------------------------------------------------------------------------- - adapter_khz 12000 + adapter speed 12000 jtag interface #------------------------------------------------------------------------- @@ -140,7 +140,7 @@ reset_config trst_and_srst nand device s3c2440 0 - adapter_nsrst_delay 100 + adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst init diff --git a/tcl/board/mini6410.cfg b/tcl/board/mini6410.cfg index d00ce1f8c..2cee93935 100644 --- a/tcl/board/mini6410.cfg +++ b/tcl/board/mini6410.cfg @@ -88,8 +88,8 @@ proc init_6410_flash {} { } -adapter_khz 1000 -adapter_nsrst_delay 100 +adapter speed 1000 +adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst diff --git a/tcl/board/novena-internal-fpga.cfg b/tcl/board/novena-internal-fpga.cfg index 87495e372..0e9ff5b1f 100644 --- a/tcl/board/novena-internal-fpga.cfg +++ b/tcl/board/novena-internal-fpga.cfg @@ -14,7 +14,7 @@ # | DISP0_DAT17 | FPGA_TMS | 5-11 | 139 | TMS | # +-------------+--------------+------+-------+---------+ -interface sysfsgpio +adapter driver sysfsgpio transport select jtag @@ -22,4 +22,3 @@ transport select jtag sysfsgpio_jtag_nums 136 139 137 138 source [find cpld/xilinx-xc6s.cfg] - diff --git a/tcl/board/numato_mimas_a7.cfg b/tcl/board/numato_mimas_a7.cfg index 1261feacc..d4012bada 100644 --- a/tcl/board/numato_mimas_a7.cfg +++ b/tcl/board/numato_mimas_a7.cfg @@ -7,7 +7,7 @@ # Programming while powering via USB may lead to programming failure. # Therefore, prefer external power supply. -interface ftdi +adapter driver ftdi ftdi_device_desc "Mimas Artix 7 FPGA Module" ftdi_vid_pid 0x2a19 0x1009 @@ -30,7 +30,7 @@ ftdi_tdo_sample_edge falling # ftdi_layout_init 0x0008 0x004b reset_config none -adapter_khz 30000 +adapter speed 30000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] diff --git a/tcl/board/nxp_imx7sabre.cfg b/tcl/board/nxp_imx7sabre.cfg index 25b7b8781..c595e3a67 100644 --- a/tcl/board/nxp_imx7sabre.cfg +++ b/tcl/board/nxp_imx7sabre.cfg @@ -3,12 +3,12 @@ transport select jtag # set a safe speed, can be overridden -adapter_khz 1000 +adapter speed 1000 # reset configuration has TRST and SRST support reset_config trst_and_srst srst_push_pull # need at least 100ms delay after SRST release for JTAG -adapter_nsrst_delay 100 +adapter srst delay 100 # source the target file source [find target/imx7.cfg] diff --git a/tcl/board/nxp_mcimx8m-evk.cfg b/tcl/board/nxp_mcimx8m-evk.cfg index e2d63ce7c..dd9bd53ac 100644 --- a/tcl/board/nxp_mcimx8m-evk.cfg +++ b/tcl/board/nxp_mcimx8m-evk.cfg @@ -6,13 +6,13 @@ transport select jtag # set a safe JTAG clock speed, can be overridden -adapter_khz 1000 +adapter speed 1000 # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive -adapter_nsrst_delay 70 +adapter srst delay 70 # board has an i.MX8MQ with 4 Cortex-A53 cores set CHIPNAME imx8mq diff --git a/tcl/board/olimex_LPC2378STK.cfg b/tcl/board/olimex_LPC2378STK.cfg index a4b422dcc..7e9e58e70 100644 --- a/tcl/board/olimex_LPC2378STK.cfg +++ b/tcl/board/olimex_LPC2378STK.cfg @@ -8,4 +8,3 @@ # source [find target/lpc2378.cfg] - diff --git a/tcl/board/olimex_lpc_h2148.cfg b/tcl/board/olimex_lpc_h2148.cfg index 7833fdec6..d8fb5bef9 100644 --- a/tcl/board/olimex_lpc_h2148.cfg +++ b/tcl/board/olimex_lpc_h2148.cfg @@ -5,4 +5,3 @@ # source [find target/lpc2148.cfg] - diff --git a/tcl/board/olimex_sam7_ex256.cfg b/tcl/board/olimex_sam7_ex256.cfg index 5f83629de..426ead6aa 100644 --- a/tcl/board/olimex_sam7_ex256.cfg +++ b/tcl/board/olimex_sam7_ex256.cfg @@ -1,4 +1,3 @@ # Olimex SAM7-EX256 has a single Atmel at91sam7ex256 on it. source [find target/sam7x256.cfg] - diff --git a/tcl/board/olimex_sam7_la2.cfg b/tcl/board/olimex_sam7_la2.cfg index 89d2b5a59..038fe67b6 100644 --- a/tcl/board/olimex_sam7_la2.cfg +++ b/tcl/board/olimex_sam7_la2.cfg @@ -2,7 +2,7 @@ source [find target/at91sam7a2.cfg] # delays needed to get stable reads of cpu state jtag_ntrst_delay 10 -adapter_nsrst_delay 200 +adapter srst delay 200 # board uses pullup and connects only srst reset_config srst_open_drain @@ -10,9 +10,9 @@ reset_config srst_open_drain # srst is connected to NRESET of CPU and fully resets everything... reset_config srst_only srst_pulls_trst -adapter_khz 1 +adapter speed 1 $_TARGETNAME configure -event reset-start { - adapter_khz 1 + adapter speed 1 } $_TARGETNAME configure -event reset-init { @@ -61,7 +61,7 @@ $_TARGETNAME configure -event reset-init { echo "set up pll" sleep 100 - adapter_khz 5000 + adapter speed 5000 } $_TARGETNAME arm7_9 dcc_downloads enable diff --git a/tcl/board/olimex_sam9_l9260.cfg b/tcl/board/olimex_sam9_l9260.cfg index ad2f850a1..72dce87b1 100644 --- a/tcl/board/olimex_sam9_l9260.cfg +++ b/tcl/board/olimex_sam9_l9260.cfg @@ -23,15 +23,15 @@ $_TARGETNAME configure -event reset-start { # RCLK is not supported. jtag_rclk 5 halt - - # RSTC_MR : enable user reset, reset length is 64 slow clock cycles. MMU may + + # RSTC_MR : enable user reset, reset length is 64 slow clock cycles. MMU may # be enabled... use physical address. mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog - + ## # Clock configuration for 99.328 MHz main clock. ## @@ -45,23 +45,23 @@ $_TARGETNAME configure -event reset-init { mww 0xfffffc30 0x00000101 ;# PMC_MCKR : no scale on proc clock, master is proc / 2 sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : switch to PLLA (99.328 MHz) - + # Increase JTAG speed to 6 MHz if RCLK is not supported. jtag_rclk 6000 - + arm7_9 dcc_downloads enable ;# Enable faster DCC downloads. - + ## # SDRAM configuration for 2 x Samsung K4S561632J-UC75, 4M x 16Bit x 4 Banks. ## echo "Configuring SDRAM" mww 0xfffff870 0xffff0000 ;# PIOC_ASR : select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIOC_PDR : disable PIO function for D15..D31 - + mww 0xffffef1c 0x00010002 ;# EBI_CSA : assign EBI CS1 to SDRAM, VDDIOMSEL set for +3V3 memory - + mww 0xffffea08 0x85237259 ;# SDRAMC_CR : configure SDRAM for Samsung chips - + mww 0xffffea00 0x1 ;# SDRAMC_MR : issue NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command @@ -86,7 +86,7 @@ $_TARGETNAME configure -event reset-init { mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 - + mww 0xffffea04 0x2b6 ;# SDRAMC_TR : set refresh timer count to 7 us ## @@ -99,37 +99,37 @@ $_TARGETNAME configure -event reset-init { mww 0xfffff814 0x00002000 ;# PIOC_ODR : disable output on 13 mww 0xfffff830 0x00004000 ;# PIOC_SODR : set 14 to disable NAND mww 0xfffff864 0x00002000 ;# PIOC_PUER : enable pull-up on 13 - + mww 0xffffef1c 0x0001000A ;# EBI_CSA : assign EBI CS3 to NAND, same settings as before - + mww 0xffffec30 0x00010001 ;# SMC_SETUP3 : 1 clock cycle setup for NRD and NWE mww 0xffffec34 0x03030303 ;# SMC_PULSE3 : 3 clock cycle pulse for all signals mww 0xffffec38 0x00050005 ;# SMC_CYCLE3 : 5 clock cycle NRD and NWE cycle - mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, + mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, # 3 TDF cycles, no optimization - + mww 0xffffe800 0x00000001 ;# ECC_CR : reset the ECC parity registers mww 0xffffe804 0x00000002 ;# ECC_MR : page size is 2112 words (word is 8 bits) - + nand probe at91sam9260.flash - + ## # Dataflash configuration for 1 x Atmel AT45DB161D, 16Mbit ## echo "Setting up dataflash" - mww 0xfffff404 0x00000807 ;# PIOA_PDR : disable PIO function for 0(SPI0_MISO), 1(SPI0_MOSI), + mww 0xfffff404 0x00000807 ;# PIOA_PDR : disable PIO function for 0(SPI0_MISO), 1(SPI0_MOSI), # 2(SPI0_SPCK), and 11(SPI0_NPCS1) mww 0xfffff470 0x00000007 ;# PIOA_ASR : select peripheral A function for 0, 1, and 2 mww 0xfffff474 0x00000800 ;# PIOA_BSR : select peripheral B function for 11 mww 0xfffffc10 0x00001000 ;# PMC_PCER : enable SPI0 clock - + mww 0xfffc8000 0x00000080 ;# SPI0_CR : software reset SPI0 mww 0xfffc8000 0x00000080 ;# SPI0_CR : again to be sure mww 0xfffc8004 0x000F0011 ;# SPI0_MR : master mode with nothing selected - - mww 0xfffc8034 0x011a0302 ;# SPI0_CSR1 : capture on leading edge, 8-bits/tx. 33MHz baud, + + mww 0xfffc8034 0x011a0302 ;# SPI0_CSR1 : capture on leading edge, 8-bits/tx. 33MHz baud, # 250ns delay before SPCK, 250ns b/n tx - + mww 0xfffc8004 0x000D0011 ;# SPI0_MR : same config, select NPCS1 mww 0xfffc8000 0x00000001 ;# SPI0_CR : enable SPI0 } diff --git a/tcl/board/openrd.cfg b/tcl/board/openrd.cfg index db3cb0326..fda01d129 100644 --- a/tcl/board/openrd.cfg +++ b/tcl/board/openrd.cfg @@ -3,7 +3,7 @@ source [find interface/ftdi/openrd.cfg] source [find target/feroceon.cfg] -adapter_khz 2000 +adapter speed 2000 $_TARGETNAME configure \ -work-area-phys 0x10000000 \ @@ -25,10 +25,10 @@ proc openrd_init { } { # possible that initial tap examination failed. So let's # re-examine the target again here when nSRST is asserted which # should then succeed. - jtag_reset 0 1 + adapter assert srst feroceon.cpu arp_examine halt 0 - jtag_reset 0 0 + adapter deassert srst wait_halt arm mcr 15 0 0 1 0 0x00052078 @@ -122,4 +122,3 @@ proc openrd_load_uboot { } { resume 0x00600000 } - diff --git a/tcl/board/or1k_generic.cfg b/tcl/board/or1k_generic.cfg index c543ebe25..7c1956563 100644 --- a/tcl/board/or1k_generic.cfg +++ b/tcl/board/or1k_generic.cfg @@ -17,7 +17,7 @@ source [find target/or1k.cfg] poll_period 1 # Set the adapter speed -adapter_khz 3000 +adapter speed 3000 # Enable the target description feature gdb_target_description enable diff --git a/tcl/board/phone_se_j100i.cfg b/tcl/board/phone_se_j100i.cfg index 632659027..ec61425ac 100644 --- a/tcl/board/phone_se_j100i.cfg +++ b/tcl/board/phone_se_j100i.cfg @@ -1,7 +1,7 @@ # # Sony Ericsson J100I Phone # -# more informations can be found on +# more information can be found on # http://bb.osmocom.org/trac/wiki/SonyEricssonJ100i # source [find target/ti_calypso.cfg] diff --git a/tcl/board/phytec_lpc3250.cfg b/tcl/board/phytec_lpc3250.cfg index 6a7e8e923..cee28cdd2 100644 --- a/tcl/board/phytec_lpc3250.cfg +++ b/tcl/board/phytec_lpc3250.cfg @@ -1,8 +1,8 @@ source [find target/lpc3250.cfg] -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 1 -adapter_khz 200 +adapter speed 200 reset_config trst_and_srst separate arm7_9 dcc_downloads enable @@ -11,11 +11,11 @@ $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-start { arm7_9 fast_memory_access disable - adapter_khz 200 + adapter speed 200 } $_TARGETNAME configure -event reset-end { - adapter_khz 6000 + adapter speed 6000 arm7_9 fast_memory_access enable } @@ -23,12 +23,12 @@ $_TARGETNAME configure -event reset-init { phytec_lpc3250_init } # Bare-bones initialization of core clocks and SDRAM proc phytec_lpc3250_init { } { - # Set clock dividers + # Set clock dividers # ARMCLK = 266.5 MHz # HCLK = 133.25 MHz # PERIPHCLK = 13.325 MHz mww 0x400040BC 0 - mww 0x40004050 0x140 + mww 0x40004050 0x140 mww 0x40004040 0x4D mww 0x40004058 0x16250 @@ -37,7 +37,7 @@ proc phytec_lpc3250_init { } { sleep 1 busy mww 0x40004044 0x106 sleep 1 busy - mww 0x40004044 0x006 + mww 0x40004044 0x006 sleep 1 busy mww 0x40004048 0x2 @@ -49,7 +49,7 @@ proc phytec_lpc3250_init { } { mww 0x31080008 0 mww 0x40004068 0x1C000 mww 0x31080028 0x11 - + mww 0x31080400 0 mww 0x31080440 0 mww 0x31080460 0 @@ -66,7 +66,7 @@ proc phytec_lpc3250_init { } { mww 0x31080054 1 mww 0x31080058 1 mww 0x3108005C 0 - + mww 0x31080100 0x5680 mww 0x31080104 0x302 diff --git a/tcl/board/pxa255_sst.cfg b/tcl/board/pxa255_sst.cfg index 49cad5db7..2b44a0541 100644 --- a/tcl/board/pxa255_sst.cfg +++ b/tcl/board/pxa255_sst.cfg @@ -93,7 +93,7 @@ $_TARGETNAME configure -event reset-init {pxa255_sst_init} reset_config trst_and_srst -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 #xscale debug_handler 0 0xFFFF0800 ;# debug handler base address diff --git a/tcl/board/quark_d2000_refboard.cfg b/tcl/board/quark_d2000_refboard.cfg index d1388bbaa..8b8314a0e 100644 --- a/tcl/board/quark_d2000_refboard.cfg +++ b/tcl/board/quark_d2000_refboard.cfg @@ -1,7 +1,7 @@ # Intel Quark microcontroller D2000 Reference Board (web search for doc num 333582) # the board has an onboard FTDI FT232H chip -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6014 ftdi_channel 0 @@ -10,6 +10,6 @@ ftdi_layout_signal nTRST -data 0x0100 -noe 0x0100 source [find target/quark_d20xx.cfg] -adapter_khz 1000 +adapter speed 1000 reset_config trst_only diff --git a/tcl/board/quark_x10xx_board.cfg b/tcl/board/quark_x10xx_board.cfg index 8dc600b80..4ecf30ed8 100644 --- a/tcl/board/quark_x10xx_board.cfg +++ b/tcl/board/quark_x10xx_board.cfg @@ -4,6 +4,6 @@ source [find target/quark_x10xx.cfg] #default frequency but this can be adjusted at runtime -adapter_khz 4000 +adapter speed 4000 reset_config trst_only diff --git a/tcl/board/renesas_porter.cfg b/tcl/board/renesas_porter.cfg index c8032f512..7f23fb63c 100644 --- a/tcl/board/renesas_porter.cfg +++ b/tcl/board/renesas_porter.cfg @@ -1,4 +1,4 @@ # Renesas R-Car M2 Evaluation Board -source [find target/renesas_r8a7791.cfg] -source [find board/renesas_gen2_common.cfg] +set SOC M2 +source [find target/renesas_rcar_gen2.cfg] diff --git a/tcl/board/renesas_salvator-xs.cfg b/tcl/board/renesas_salvator-xs.cfg index 1558a5274..6d3096ec1 100644 --- a/tcl/board/renesas_salvator-xs.cfg +++ b/tcl/board/renesas_salvator-xs.cfg @@ -7,17 +7,3 @@ if { ![info exists SOC] } { set SOC H3 } source [find target/renesas_rcar_gen3.cfg] - -reset_config trst_and_srst srst_nogate - -proc init_reset {mode} { - # Assert both resets: equivalent to a power-on reset - jtag_reset 1 1 - - # Deassert TRST to begin TAP communication - jtag_reset 0 1 - - # TAP should now be responsive, validate the scan-chain - jtag arp_init -} - diff --git a/tcl/board/renesas_silk.cfg b/tcl/board/renesas_silk.cfg index a026537d4..08bcb666f 100644 --- a/tcl/board/renesas_silk.cfg +++ b/tcl/board/renesas_silk.cfg @@ -1,4 +1,4 @@ # Renesas R-Car E2 Evaluation Board -source [find target/renesas_r8a7794.cfg] -source [find board/renesas_gen2_common.cfg] +set SOC E2 +source [find target/renesas_rcar_gen2.cfg] diff --git a/tcl/board/renesas_stout.cfg b/tcl/board/renesas_stout.cfg index d35f8744f..51b53e154 100644 --- a/tcl/board/renesas_stout.cfg +++ b/tcl/board/renesas_stout.cfg @@ -1,4 +1,4 @@ # Renesas R-Car H2 Evaluation Board -source [find target/renesas_r8a7790.cfg] -source [find board/renesas_gen2_common.cfg] +set SOC H2 +source [find target/renesas_rcar_gen2.cfg] diff --git a/tcl/board/rigado_bmd300_ek.cfg b/tcl/board/rigado_bmd300_ek.cfg index 04e5e1f45..8e1e65ed0 100644 --- a/tcl/board/rigado_bmd300_ek.cfg +++ b/tcl/board/rigado_bmd300_ek.cfg @@ -6,6 +6,6 @@ source [find interface/jlink.cfg] transport select swd -adapter_khz 1000 +adapter speed 1000 source [find target/nrf52.cfg] diff --git a/tcl/board/rsc-w910.cfg b/tcl/board/rsc-w910.cfg index 636a05399..574de0c07 100644 --- a/tcl/board/rsc-w910.cfg +++ b/tcl/board/rsc-w910.cfg @@ -12,8 +12,8 @@ source [find target/nuc910.cfg] # reset_config trst_and_srst srst_pulls_trst -adapter_khz 1000 -adapter_nsrst_delay 100 +adapter speed 1000 +adapter srst delay 100 jtag_ntrst_delay 100 $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x04000000 -work-area-backup 0 @@ -28,12 +28,12 @@ nand device $_NANDNAME nuc910 $_TARGETNAME # Target events # -$_TARGETNAME configure -event reset-start {adapter_khz 1000} +$_TARGETNAME configure -event reset-start {adapter speed 1000} $_TARGETNAME configure -event reset-init { # switch on PLL for 200MHz operation # running from 15MHz input clock - + mww 0xB0000200 0x00000030 ;# CLKEN mww 0xB0000204 0x00000f3c ;# CLKSEL mww 0xB0000208 0x05007000 ;# CLKDIV @@ -41,17 +41,17 @@ $_TARGETNAME configure -event reset-init { mww 0xB0000210 0x00002b63 ;# PLLCON1 mww 0xB000000C 0x08817fa6 ;# MFSEL sleep 10 - + # we are now running @ 200MHz # enable all openocd speed tweaks - + arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable - adapter_khz 15000 - + adapter speed 15000 + # map nor flash to 0x20000000 # map sdram to 0x00000000 - + mww 0xb0001000 0x000530c1 ;# EBICON mww 0xb0001004 0x40030084 ;# ROMCON mww 0xb0001008 0x000010ee ;# SDCONF0 diff --git a/tcl/board/sayma_amc.cfg b/tcl/board/sayma_amc.cfg index 5d338ed8a..009eb78c2 100644 --- a/tcl/board/sayma_amc.cfg +++ b/tcl/board/sayma_amc.cfg @@ -10,7 +10,7 @@ # Sayma AMC is usually combined with Sayma RTM (rear transition module) # which features an Artix 7 FPGA. -interface ftdi +adapter driver ftdi ftdi_device_desc "Quad RS232-HS" ftdi_vid_pid 0x0403 0x6011 ftdi_channel 0 @@ -26,7 +26,7 @@ ftdi_layout_init 0x0098 0x008b #ftdi_layout_signal nTRST -data 0x0010 reset_config none -adapter_khz 5000 +adapter speed 5000 transport select jtag diff --git a/tcl/board/sheevaplug.cfg b/tcl/board/sheevaplug.cfg index ff333ca77..455163777 100644 --- a/tcl/board/sheevaplug.cfg +++ b/tcl/board/sheevaplug.cfg @@ -3,7 +3,7 @@ source [find interface/ftdi/sheevaplug.cfg] source [find target/feroceon.cfg] -adapter_khz 2000 +adapter speed 2000 $_TARGETNAME configure \ -work-area-phys 0x10000000 \ @@ -25,10 +25,10 @@ proc sheevaplug_init { } { # possible that initial tap examination failed. So let's # re-examine the target again here when nSRST is asserted which # should then succeed. - jtag_reset 0 1 + adapter assert srst feroceon.cpu arp_examine halt 0 - jtag_reset 0 0 + adapter deassert srst wait_halt arm mcr 15 0 0 1 0 0x00052078 @@ -133,4 +133,3 @@ proc sheevaplug_load_uboot { } { resume 0x00600000 } - diff --git a/tcl/board/sifive-e31arty.cfg b/tcl/board/sifive-e31arty.cfg index ec10b27c3..b7a255ea2 100644 --- a/tcl/board/sifive-e31arty.cfg +++ b/tcl/board/sifive-e31arty.cfg @@ -1,7 +1,7 @@ # # Be sure you include the speed and interface before this file # Example: -# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" +# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive-e51arty.cfg index ffd83a058..20ad57551 100644 --- a/tcl/board/sifive-e51arty.cfg +++ b/tcl/board/sifive-e51arty.cfg @@ -1,7 +1,7 @@ # # Be sure you include the speed and interface before this file # Example: -# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" +# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 diff --git a/tcl/board/sifive-hifive1-revb.cfg b/tcl/board/sifive-hifive1-revb.cfg index 662811fce..7f2a2122a 100644 --- a/tcl/board/sifive-hifive1-revb.cfg +++ b/tcl/board/sifive-hifive1-revb.cfg @@ -1,6 +1,6 @@ -adapter_khz 4000 +adapter speed 4000 -interface jlink +adapter driver jlink transport select jtag set _CHIPNAME riscv diff --git a/tcl/board/sifive-hifive1.cfg b/tcl/board/sifive-hifive1.cfg index 9bc66701c..196f540bb 100644 --- a/tcl/board/sifive-hifive1.cfg +++ b/tcl/board/sifive-hifive1.cfg @@ -1,6 +1,6 @@ -adapter_khz 10000 +adapter speed 10000 -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 @@ -10,7 +10,7 @@ ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 #Reset Stretcher logic on FE310 is ~1 second long #This doesn't apply if you use # ftdi_set_signal, but still good to document -#adapter_nsrst_delay 1500 +#adapter srst delay 1500 set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 diff --git a/tcl/board/snps_em_sk.cfg b/tcl/board/snps_em_sk.cfg new file mode 100644 index 000000000..3d9340735 --- /dev/null +++ b/tcl/board/snps_em_sk.cfg @@ -0,0 +1,22 @@ +# Copyright (C) 2014-2016,2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Synopsys DesignWare ARC EM Starter Kit v2.x +# + +# Configure JTAG cable +# EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. +source [find interface/ftdi/digilent-hs1.cfg] + +# 5MHz seems to work good with all cores that might happen in 2.x +adapter speed 5000 + +# ARCs support only JTAG. +transport select jtag + +# Configure FPGA. This script supports both LX45 and LX150. +source [find target/snps_em_sk_fpga.cfg] diff --git a/tcl/board/snps_em_sk_v1.cfg b/tcl/board/snps_em_sk_v1.cfg new file mode 100644 index 000000000..0c1539ee5 --- /dev/null +++ b/tcl/board/snps_em_sk_v1.cfg @@ -0,0 +1,20 @@ +# Copyright (C) 2014-2016,2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Synopsys DesignWare ARC EM Starter Kit v1.0 and v1.1 +# + +# Configure JTAG cable +# EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. +source [find interface/ftdi/digilent-hs1.cfg] +adapter speed 10000 + +# ARCs support only JTAG. +transport select jtag + +# Configure FPGA. This script supports both LX45 and LX150. +source [find target/snps_em_sk_fpga.cfg] diff --git a/tcl/board/snps_em_sk_v2.1.cfg b/tcl/board/snps_em_sk_v2.1.cfg new file mode 100644 index 000000000..c1fb232d5 --- /dev/null +++ b/tcl/board/snps_em_sk_v2.1.cfg @@ -0,0 +1,23 @@ +# Copyright (C) 2014-2016,2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Synopsys DesignWare ARC EM Starter Kit v2.1 +# + +# Configure JTAG cable +# EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. +source [find interface/ftdi/digilent-hs1.cfg] + +# JTAG 10MHz is too fast for EM7D FPU in EM SK 2.1 which has core frequency +# 20MHz. 7.5 MHz seems to work fine. +adapter speed 7500 + +# ARCs support only JTAG. +transport select jtag + +# Configure FPGA. This script supports both LX45 and LX150. +source [find target/snps_em_sk_fpga.cfg] diff --git a/tcl/board/snps_em_sk_v2.2.cfg b/tcl/board/snps_em_sk_v2.2.cfg new file mode 100644 index 000000000..674d9f65c --- /dev/null +++ b/tcl/board/snps_em_sk_v2.2.cfg @@ -0,0 +1,22 @@ +# Copyright (C) 2016,2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Synopsys DesignWare ARC EM Starter Kit v2.2 +# + +# Configure JTAG cable +# EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. +source [find interface/ftdi/digilent-hs1.cfg] + +# EM11D reportedly requires 5 MHz. Other cores and board can work faster. +adapter speed 5000 + +# ARCs support only JTAG. +transport select jtag + +# Configure FPGA. This script supports both LX45 and LX150. +source [find target/snps_em_sk_fpga.cfg] diff --git a/tcl/board/st_nucleo_8l152r8.cfg b/tcl/board/st_nucleo_8l152r8.cfg new file mode 100644 index 000000000..d3372693d --- /dev/null +++ b/tcl/board/st_nucleo_8l152r8.cfg @@ -0,0 +1,10 @@ +# This is a ST NUCLEO 8L152R8 board with a single STM8L152R8T6 chip. +# http://www.st.com/en/evaluation-tools/nucleo-8l152r8.html + +source [find interface/stlink-dap.cfg] + +transport select swim + +source [find target/stm8l152.cfg] + +reset_config srst_only diff --git a/tcl/board/st_nucleo_h745zi.cfg b/tcl/board/st_nucleo_h745zi.cfg new file mode 100644 index 000000000..22d36f686 --- /dev/null +++ b/tcl/board/st_nucleo_h745zi.cfg @@ -0,0 +1,14 @@ +# This is an ST NUCLEO-H745ZI-Q board with single STM32H745ZITx chip. + +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd + +# STM32H745xx devices are dual core (Cortex-M7 and Cortex-M4) +set DUAL_CORE 1 + +# enable CTI for cross halting both cores +set USE_CTI 1 + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only diff --git a/tcl/board/st_nucleo_wb55.cfg b/tcl/board/st_nucleo_wb55.cfg new file mode 100644 index 000000000..5b5b8f779 --- /dev/null +++ b/tcl/board/st_nucleo_wb55.cfg @@ -0,0 +1,11 @@ +# +# Configuration for STM32WB55 Nucleo board (STM32WB55RGV6) +# + +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wbx.cfg] + +reset_config srst_only diff --git a/tcl/board/steval-idb011v1.cfg b/tcl/board/steval-idb011v1.cfg new file mode 100644 index 000000000..5988c6386 --- /dev/null +++ b/tcl/board/steval-idb011v1.cfg @@ -0,0 +1,3 @@ +# This is an evaluation board with a single BlueNRG-LP chip. +set CHIPNAME bluenrg-lp +source [find target/bluenrg-x.cfg] diff --git a/tcl/board/steval_pcc010.cfg b/tcl/board/steval_pcc010.cfg index ddfdbb36f..94108d1ca 100644 --- a/tcl/board/steval_pcc010.cfg +++ b/tcl/board/steval_pcc010.cfg @@ -1,5 +1,5 @@ # Use for the STM207VG plug-in board (1 MiB Flash and 112+16 KiB Ram -# comming with the STEVAL-PCC010 board +# coming with the STEVAL-PCC010 board # http://www.st.com/internet/evalboard/product/251530.jsp # or any other board with only a STM32F2x in the JTAG chain diff --git a/tcl/board/stm3210e_eval.cfg b/tcl/board/stm3210e_eval.cfg index 91807ce30..f30253c11 100644 --- a/tcl/board/stm3210e_eval.cfg +++ b/tcl/board/stm3210e_eval.cfg @@ -17,11 +17,11 @@ flash bank $_FLASHNAME cfi 0x64000000 0x01000000 2 2 $_TARGETNAME proc stm32_enable_fsmc {} { echo "Enabling FSMC Bank 1 (NOR/PSRAM Bank 2)" - + # enable gpio (defg) clocks for fsmc # RCC_APB2ENR mww 0x40021018 0x000001E0 - + # enable fsmc clock # RCC_AHBENR mww 0x40021014 0x00000114 @@ -31,29 +31,29 @@ proc stm32_enable_fsmc {} { mww 0x40011400 0x44BB44BB # GPIOD_CRH mww 0x40011404 0xBBBBBBBB - + # GPIOE_CRL mww 0x40011800 0xBBBBB444 # GPIOE_CRH mww 0x40011804 0xBBBBBBBB - + # GPIOF_CRL mww 0x40011C00 0x44BBBBBB # GPIOF_CRH mww 0x40011C04 0xBBBB4444 - + # GPIOG_CRL mww 0x40012000 0x44BBBBBB # GPIOG_CRH mww 0x40012004 0x444444B4 - + # setup fsmc timings # FSMC_BCR1 mww 0xA0000008 0x00001058 - + # FSMC_BTR1 mww 0xA000000C 0x10000502 - + # FSMC_BCR1 - enable fsmc mww 0xA0000008 0x00001059 } diff --git a/tcl/board/stm32f7discovery.cfg b/tcl/board/stm32f7discovery.cfg old mode 100755 new mode 100644 diff --git a/tcl/board/stm32mp15x_dk2.cfg b/tcl/board/stm32mp15x_dk2.cfg new file mode 100644 index 000000000..0233c6d75 --- /dev/null +++ b/tcl/board/stm32mp15x_dk2.cfg @@ -0,0 +1,11 @@ +# board MB1272B +# http://www.st.com/en/evaluation-tools/stm32mp157a-dk1.html +# http://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html + +source [find interface/stlink-dap.cfg] + +transport select dapdirect_swd + +source [find target/stm32mp15x.cfg] + +reset_config srst_only diff --git a/tcl/board/telo.cfg b/tcl/board/telo.cfg index 1d3afdf0b..2c98ca3bd 100644 --- a/tcl/board/telo.cfg +++ b/tcl/board/telo.cfg @@ -1,5 +1,5 @@ source [find target/c100.cfg] -# basic register defintion for C100 +# basic register definition for C100 source [find target/c100regs.tcl] # board-config info source [find target/c100config.tcl] @@ -10,10 +10,10 @@ source [find target/c100helper.tcl] # Telo board & C100 support trst and srst # make the reset asserted to # allow RC circuit to discharge for: [ms] -adapter_nsrst_assert_width 100 +adapter srst pulse_width 100 jtag_ntrst_assert_width 100 # don't talk to JTAG after reset for: [ms] -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate @@ -23,11 +23,11 @@ reset_config trst_and_srst separate # issue telnet: reset init # issue gdb: monitor reset init $_TARGETNAME configure -event reset-init { - adapter_khz 100 + adapter speed 100 # this will setup Telo board setupTelo #turn up the JTAG speed - adapter_khz 3000 + adapter speed 3000 echo "JTAG speek now 3MHz" echo "type helpC100 to get help on C100" } diff --git a/tcl/board/ti_am437x_idk.cfg b/tcl/board/ti_am437x_idk.cfg index 65e2094e8..fc2b81b29 100644 --- a/tcl/board/ti_am437x_idk.cfg +++ b/tcl/board/ti_am437x_idk.cfg @@ -4,7 +4,7 @@ source [find interface/ftdi/xds100v2.cfg] transport select jtag -adapter_khz 30000 +adapter speed 30000 source [find target/am437x.cfg] $_TARGETNAME configure -event reset-init { init_platform 0x61a11b32 } diff --git a/tcl/board/ti_am43xx_evm.cfg b/tcl/board/ti_am43xx_evm.cfg index d536314ba..dbc37ae82 100644 --- a/tcl/board/ti_am43xx_evm.cfg +++ b/tcl/board/ti_am43xx_evm.cfg @@ -1,6 +1,6 @@ # Works on both AM437x GP EVM and AM438x ePOS EVM transport select jtag -adapter_khz 16000 +adapter speed 16000 source [find target/am437x.cfg] diff --git a/tcl/board/ti_beagleboard_xm.cfg b/tcl/board/ti_beagleboard_xm.cfg index e4e93e333..683f583b2 100644 --- a/tcl/board/ti_beagleboard_xm.cfg +++ b/tcl/board/ti_beagleboard_xm.cfg @@ -9,4 +9,3 @@ source [find target/amdm37x.cfg] reset_config trst_only # "amdm37x_dbginit dm37x.cpu" needs to be run after init. - diff --git a/tcl/board/ti_beaglebone.cfg b/tcl/board/ti_beaglebone.cfg index a54ad6275..7ba8c50f2 100644 --- a/tcl/board/ti_beaglebone.cfg +++ b/tcl/board/ti_beaglebone.cfg @@ -4,10 +4,8 @@ # The JTAG interface is built directly on the board. source [find interface/ftdi/xds100v2.cfg] -adapter_khz 16000 +adapter speed 16000 reset_config trst_and_srst source [find board/ti_beaglebone-base.cfg] - - diff --git a/tcl/board/ti_beaglebone_black.cfg b/tcl/board/ti_beaglebone_black.cfg index 79fc1e8a8..c730814cc 100644 --- a/tcl/board/ti_beaglebone_black.cfg +++ b/tcl/board/ti_beaglebone_black.cfg @@ -1,7 +1,7 @@ # AM335x Beaglebone Black # http://beagleboard.org/bone -adapter_khz 1000 +adapter speed 1000 reset_config trst_and_srst diff --git a/tcl/board/ti_blaze.cfg b/tcl/board/ti_blaze.cfg index c9bbe25c0..488138982 100644 --- a/tcl/board/ti_blaze.cfg +++ b/tcl/board/ti_blaze.cfg @@ -3,4 +3,3 @@ jtag_rclk 6000 source [find target/omap4430.cfg] reset_config trst_and_srst - diff --git a/tcl/board/ti_cc13x0_launchpad.cfg b/tcl/board/ti_cc13x0_launchpad.cfg index 9e1c1ea37..4fbce4120 100644 --- a/tcl/board/ti_cc13x0_launchpad.cfg +++ b/tcl/board/ti_cc13x0_launchpad.cfg @@ -3,5 +3,5 @@ # source [find interface/xds110.cfg] transport select jtag -adapter_khz 2500 +adapter speed 5500 source [find target/ti_cc13x0.cfg] diff --git a/tcl/board/ti_cc13x2_launchpad.cfg b/tcl/board/ti_cc13x2_launchpad.cfg index 18c5ce51c..dc0c18230 100644 --- a/tcl/board/ti_cc13x2_launchpad.cfg +++ b/tcl/board/ti_cc13x2_launchpad.cfg @@ -2,6 +2,6 @@ # TI CC13x2 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] -adapter_khz 2500 +adapter speed 5500 transport select jtag source [find target/ti_cc13x2.cfg] diff --git a/tcl/board/ti_cc26x0_launchpad.cfg b/tcl/board/ti_cc26x0_launchpad.cfg index 3613a47f7..372e57ceb 100644 --- a/tcl/board/ti_cc26x0_launchpad.cfg +++ b/tcl/board/ti_cc26x0_launchpad.cfg @@ -2,6 +2,6 @@ # TI CC26x0 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] -adapter_khz 2500 +adapter speed 5500 transport select jtag source [find target/ti_cc26x0.cfg] diff --git a/tcl/board/ti_cc26x2_launchpad.cfg b/tcl/board/ti_cc26x2_launchpad.cfg index 2f2b34b4b..c8057ad3d 100644 --- a/tcl/board/ti_cc26x2_launchpad.cfg +++ b/tcl/board/ti_cc26x2_launchpad.cfg @@ -2,6 +2,6 @@ # TI CC26x2 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] -adapter_khz 2500 +adapter speed 5500 transport select jtag source [find target/ti_cc26x2.cfg] diff --git a/tcl/board/ti_cc3200_launchxl.cfg b/tcl/board/ti_cc3200_launchxl.cfg index b78b09b7c..b37b406ad 100644 --- a/tcl/board/ti_cc3200_launchxl.cfg +++ b/tcl/board/ti_cc3200_launchxl.cfg @@ -12,9 +12,10 @@ if { [info exists TRANSPORT] } { transport select jtag } -adapter_khz 2500 +adapter speed 2500 set WORKAREASIZE 0x40000 source [find target/ti_cc32xx.cfg] reset_config srst_only +adapter srst delay 1100 diff --git a/tcl/board/ti_cc3220sf_launchpad.cfg b/tcl/board/ti_cc3220sf_launchpad.cfg index a3dac620d..7c8310af0 100644 --- a/tcl/board/ti_cc3220sf_launchpad.cfg +++ b/tcl/board/ti_cc3220sf_launchpad.cfg @@ -2,6 +2,6 @@ # TI CC3220SF-LaunchXL LaunchPad Evaluation Kit # source [find interface/xds110.cfg] -adapter_khz 2500 +adapter speed 8500 transport select swd source [find target/ti_cc3220sf.cfg] diff --git a/tcl/board/ti_cc32xx_launchpad.cfg b/tcl/board/ti_cc32xx_launchpad.cfg index f657bdfdb..d0f2a831c 100644 --- a/tcl/board/ti_cc32xx_launchpad.cfg +++ b/tcl/board/ti_cc32xx_launchpad.cfg @@ -2,6 +2,9 @@ # TI CC32xx-LaunchXL LaunchPad Evaluation Kit # source [find interface/xds110.cfg] -adapter_khz 2500 +adapter speed 8500 transport select swd source [find target/ti_cc32xx.cfg] + +reset_config srst_only +adapter srst delay 1100 diff --git a/tcl/board/ti_dk-tm4c129.cfg b/tcl/board/ti_dk-tm4c129.cfg new file mode 100644 index 000000000..f1171af12 --- /dev/null +++ b/tcl/board/ti_dk-tm4c129.cfg @@ -0,0 +1,14 @@ +# +# TI Tiva C DK-TM4C129X Connected Development Kit +# +# http://www.ti.com/tool/dk-tm4c129x +# + +source [find interface/ti-icdi.cfg] + +transport select hla_jtag + +set WORKAREASIZE 0x8000 +set CHIPNAME tm4c129xnczad + +source [find target/stellaris.cfg] diff --git a/tcl/board/ti_ek-tm4c123gxl.cfg b/tcl/board/ti_ek-tm4c123gxl.cfg new file mode 100644 index 000000000..4fc1050c7 --- /dev/null +++ b/tcl/board/ti_ek-tm4c123gxl.cfg @@ -0,0 +1,13 @@ +# +# TI Tiva C Series ek-tm4c123gxl Launchpad Evaluation Kit +# +# http://www.ti.com/tool/ek-tm4c123gxl +# + +source [find interface/ti-icdi.cfg] + +transport select hla_jtag + +set WORKAREASIZE 0x8000 +set CHIPNAME tm4c123gh6pm +source [find target/stellaris.cfg] diff --git a/tcl/board/ti_ek-tm4c1294xl.cfg b/tcl/board/ti_ek-tm4c1294xl.cfg new file mode 100644 index 000000000..b3f384c0e --- /dev/null +++ b/tcl/board/ti_ek-tm4c1294xl.cfg @@ -0,0 +1,14 @@ +# +# TI Tiva C Series ek-tm4c1294xl Launchpad Evaluation Kit +# +# http://www.ti.com/tool/ek-tm4c1294xl +# + +source [find interface/ti-icdi.cfg] + +transport select hla_jtag + +set WORKAREASIZE 0x8000 +set CHIPNAME tm4c1294ncpdt + +source [find target/stellaris.cfg] diff --git a/tcl/board/ti_msp432_launchpad.cfg b/tcl/board/ti_msp432_launchpad.cfg index bfad32235..6d2b15dd4 100644 --- a/tcl/board/ti_msp432_launchpad.cfg +++ b/tcl/board/ti_msp432_launchpad.cfg @@ -2,6 +2,6 @@ # TI MSP432 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] -adapter_khz 2500 +adapter speed 10000 transport select swd source [find target/ti_msp432.cfg] diff --git a/tcl/board/ti_pandaboard.cfg b/tcl/board/ti_pandaboard.cfg index bd2cd3703..bc9259610 100644 --- a/tcl/board/ti_pandaboard.cfg +++ b/tcl/board/ti_pandaboard.cfg @@ -3,4 +3,3 @@ jtag_rclk 6000 source [find target/omap4430.cfg] reset_config trst_only - diff --git a/tcl/board/ti_pandaboard_es.cfg b/tcl/board/ti_pandaboard_es.cfg index 2abd7e97a..756fa33ee 100644 --- a/tcl/board/ti_pandaboard_es.cfg +++ b/tcl/board/ti_pandaboard_es.cfg @@ -3,4 +3,3 @@ jtag_rclk 6000 source [find target/omap4460.cfg] reset_config trst_only - diff --git a/tcl/board/ti_tmdx570ls31usb.cfg b/tcl/board/ti_tmdx570ls31usb.cfg index 550244429..6d7350297 100644 --- a/tcl/board/ti_tmdx570ls31usb.cfg +++ b/tcl/board/ti_tmdx570ls31usb.cfg @@ -1,4 +1,4 @@ -adapter_khz 1500 +adapter speed 1500 source [find interface/ftdi/xds100v2.cfg] source [find target/ti_tms570.cfg] diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg index d8b833004..d0951ce64 100644 --- a/tcl/board/tocoding_poplar.cfg +++ b/tcl/board/tocoding_poplar.cfg @@ -5,7 +5,7 @@ # board does not feature anything but JTAG transport select jtag -adapter_khz 10000 +adapter speed 10000 # SRST-only reset configuration reset_config srst_only srst_push_pull diff --git a/tcl/board/topas910.cfg b/tcl/board/topas910.cfg index 90c18c484..9f994c8ea 100644 --- a/tcl/board/topas910.cfg +++ b/tcl/board/topas910.cfg @@ -30,7 +30,7 @@ proc topas910_init { } { # Init SDRAM # _PMCDRV = 0x00000071; # // -# // Initialize SDRAM timing paramater +# // Initialize SDRAM timing parameter # // # _DMC_CAS_LATENCY = 0x00000006; # _DMC_T_DQSS = 0x00000000; @@ -99,7 +99,7 @@ proc topas910_init { } { mww 0xf4300004 0x00000000 sleep 10 -# adapter_khz NNNN +# adapter speed NNNN # remap off in case of IROM boot mww 0xf0000004 0x00000001 diff --git a/tcl/board/topasa900.cfg b/tcl/board/topasa900.cfg index 2a388d511..4fa63831b 100644 --- a/tcl/board/topasa900.cfg +++ b/tcl/board/topasa900.cfg @@ -37,7 +37,7 @@ proc topasa900_init { } { # Init SDRAM # _PMCDRV = 0x00000071; # // -# // Initialize SDRAM timing paramater +# // Initialize SDRAM timing parameter # // # _DMC_CAS_LATENCY = 0x00000006; # _DMC_T_DQSS = 0x00000000; @@ -105,7 +105,7 @@ proc topasa900_init { } { mww 0xf4300004 0x00000000 sleep 10 -# adapter_khz NNNN +# adapter speed NNNN # remap off in case of IROM boot mww 0xf0000004 0x00000001 @@ -123,4 +123,3 @@ arm7_9 dcc_downloads enable ;# Enable faster DCC downloads #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x1000000 2 2 $_TARGETNAME - diff --git a/tcl/board/twr-k60f120m.cfg b/tcl/board/twr-k60f120m.cfg index e96d04526..c4d87db26 100644 --- a/tcl/board/twr-k60f120m.cfg +++ b/tcl/board/twr-k60f120m.cfg @@ -5,7 +5,7 @@ source [find target/k60.cfg] $_TARGETNAME configure -event reset-init { - puts "-event reset-init occured" + puts "-event reset-init occurred" } # diff --git a/tcl/board/twr-k60n512.cfg b/tcl/board/twr-k60n512.cfg index d2312cf14..5babeb8c1 100644 --- a/tcl/board/twr-k60n512.cfg +++ b/tcl/board/twr-k60n512.cfg @@ -5,7 +5,7 @@ source [find target/k60.cfg] $_TARGETNAME configure -event reset-init { - puts "-event reset-init occured" + puts "-event reset-init occurred" } # diff --git a/tcl/board/twr-vf65gs10.cfg b/tcl/board/twr-vf65gs10.cfg index a80407f38..0d6d3329a 100644 --- a/tcl/board/twr-vf65gs10.cfg +++ b/tcl/board/twr-vf65gs10.cfg @@ -198,4 +198,4 @@ proc board_init { } { # hook the init function into the reset-init event ${_TARGETNAME}0 configure -event reset-init { board_init } # set a slow default JTAG clock, can be overridden later -adapter_khz 1000 +adapter speed 1000 diff --git a/tcl/board/twr-vf65gs10_cmsisdap.cfg b/tcl/board/twr-vf65gs10_cmsisdap.cfg index e8db75491..ab4548f99 100644 --- a/tcl/board/twr-vf65gs10_cmsisdap.cfg +++ b/tcl/board/twr-vf65gs10_cmsisdap.cfg @@ -12,4 +12,4 @@ transport select swd source [find board/twr-vf65gs10.cfg] # override reset configuration -reset_config srst_only \ No newline at end of file +reset_config srst_only diff --git a/tcl/board/unknown_at91sam9260.cfg b/tcl/board/unknown_at91sam9260.cfg index de49a69f5..5570ef04b 100644 --- a/tcl/board/unknown_at91sam9260.cfg +++ b/tcl/board/unknown_at91sam9260.cfg @@ -93,5 +93,3 @@ $_TARGETNAME configure -event reset-init { #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x01000000 2 2 $_TARGETNAME - - diff --git a/tcl/board/uptech_2410.cfg b/tcl/board/uptech_2410.cfg index 950f2a7c1..227cf42f6 100644 --- a/tcl/board/uptech_2410.cfg +++ b/tcl/board/uptech_2410.cfg @@ -11,28 +11,28 @@ proc init_pll_sdram { } { #echo "---------- Initializing PLL and SDRAM ---------" #watchdog timer disable mww phys 0x53000000 0x00000000 - + #disable all interrupts mww phys 0x4a000008 0xffffffff - + #disable all sub-interrupts mww phys 0x4a00001c 0x000007ff - + #clear all source pending bits mww phys 0x4a000000 0xffffffff - + #clear all sub-source pending bits mww phys 0x4a000018 0x000007ff - + #clear interrupt pending bit mww phys 0x4a000010 0xffffffff - + #PLL locktime counter mww phys 0x4c000000 0x00ffffff - + #Fin=12MHz Fout=202.8MHz #mww phys 0x4c000004 0x000a1031 - + #FCLK:HCLK:PCLK = 1:2:4 mww phys 0x4c000014 0x00000003 @@ -61,5 +61,3 @@ proc uptech2410_init { } { set _NANDNAME $_CHIPNAME.nand nand device $_NANDNAME s3c2410 $_TARGETNAME - - diff --git a/tcl/board/verdex.cfg b/tcl/board/verdex.cfg index 6da987528..dd267fcbe 100644 --- a/tcl/board/verdex.cfg +++ b/tcl/board/verdex.cfg @@ -8,7 +8,7 @@ source [find target/pxa270.cfg] reset_config trst_and_srst separate # XM4 = 400MHz, XL6P = 600MHz...let's run at 0.1*400MHz=40MHz -adapter_khz 40000 +adapter speed 40000 # flash bank # XL6P has 32 MB flash diff --git a/tcl/board/voltcraft_dso-3062c.cfg b/tcl/board/voltcraft_dso-3062c.cfg index 01e37e9a4..f300cf2b6 100644 --- a/tcl/board/voltcraft_dso-3062c.cfg +++ b/tcl/board/voltcraft_dso-3062c.cfg @@ -13,7 +13,7 @@ source [find target/samsung_s3c2440.cfg] -adapter_khz 16000 +adapter speed 16000 # Samsung K9F1208U0C NAND flash chip (64MiB, 3.3V, 8-bit) nand device $_CHIPNAME.nand s3c2440 $_TARGETNAME @@ -28,4 +28,3 @@ scan_chain targets nand probe 0 nand list - diff --git a/tcl/board/zy1000.cfg b/tcl/board/zy1000.cfg index 57deaa837..e0d1ccf84 100644 --- a/tcl/board/zy1000.cfg +++ b/tcl/board/zy1000.cfg @@ -72,7 +72,7 @@ $_TARGETNAME configure -event gdb-attach { # other things than flash programming. $_TARGETNAME configure -work-area-phys 0x00020000 -work-area-size 0x20000 -work-area-backup 0 -adapter_khz 16000 +adapter speed 16000 proc production_info {} { diff --git a/tcl/chip/atmel/at91/aic.tcl b/tcl/chip/atmel/at91/aic.tcl index 6dae36ad6..ba0f2a91b 100644 --- a/tcl/chip/atmel/at91/aic.tcl +++ b/tcl/chip/atmel/at91/aic.tcl @@ -98,4 +98,3 @@ proc show_AIC { } { } } } - diff --git a/tcl/chip/atmel/at91/at91sam9263_matrix.cfg b/tcl/chip/atmel/at91/at91sam9263_matrix.cfg index ad3d9a2a3..f287cd9bf 100644 --- a/tcl/chip/atmel/at91/at91sam9263_matrix.cfg +++ b/tcl/chip/atmel/at91/at91sam9263_matrix.cfg @@ -108,5 +108,3 @@ set AT91_MATRIX_EBI1_DBPUC [expr (1 << 8)] ;# Data Bus Pull-up Configuration set AT91_MATRIX_EBI1_VDDIOMSEL [expr (1 << 16)] ;# Memory voltage selection set AT91_MATRIX_EBI1_VDDIOMSEL_1_8V [expr (0 << 16)] set AT91_MATRIX_EBI1_VDDIOMSEL_3_3V [expr (1 << 16)] - - diff --git a/tcl/chip/atmel/at91/pmc.tcl b/tcl/chip/atmel/at91/pmc.tcl index 584acb80b..7cb1d093e 100644 --- a/tcl/chip/atmel/at91/pmc.tcl +++ b/tcl/chip/atmel/at91/pmc.tcl @@ -14,4 +14,3 @@ if [info exists AT91C_SLOWOSC_FREQ] { set AT91C_SLOWOSC_FREQ 32768 } global AT91C_SLOWOSC_FREQ - diff --git a/tcl/chip/atmel/at91/rtt.tcl b/tcl/chip/atmel/at91/rtt.tcl index 8be6a56b0..2dd74fab9 100644 --- a/tcl/chip/atmel/at91/rtt.tcl +++ b/tcl/chip/atmel/at91/rtt.tcl @@ -53,4 +53,3 @@ proc show_RTTC { } { show_mmr32_reg RTTC_RTVR show_mmr32_reg RTTC_RTSR } - diff --git a/tcl/chip/atmel/at91/usarts.tcl b/tcl/chip/atmel/at91/usarts.tcl index 68420292e..ecc4f6034 100644 --- a/tcl/chip/atmel/at91/usarts.tcl +++ b/tcl/chip/atmel/at91/usarts.tcl @@ -130,6 +130,3 @@ proc show_DBGU { } $str unset str proc show_DBGU_MR_helper { NAME ADDR VAL } { show_mmr_USx_MR_helper $NAME $ADDR $VAL } - - - diff --git a/tcl/cpu/arc/common.tcl b/tcl/cpu/arc/common.tcl new file mode 100644 index 000000000..e9a915717 --- /dev/null +++ b/tcl/cpu/arc/common.tcl @@ -0,0 +1,40 @@ +# Copyright (C) 2015, 2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# Things common to all ARCs + +# It is assumed that target is already halted. +proc arc_common_reset { {target ""} } { + if { $target != "" } { + targets $target + } + + halt + + # 1. Interrupts are disabled (STATUS32.IE) + # 2. The status register flags are cleared. + # All fields, except the H bit, are set to 0 when the processor is Reset. + + arc jtag set-aux-reg 0xA 0x1 + + # 3. The loop count, loop start, and loop end registers are cleared. + arc jtag set-core-reg 60 0 + arc jtag set-aux-reg 0x2 0 + arc jtag set-aux-reg 0x3 0 + + # Program execution begins at the address referenced by the four byte reset + # vector located at the interrupt vector base address, which is the first + # entry (offset 0x00) in the vector table. + set int_vector_base [arc jtag get-aux-reg 0x25] + set start_pc "" + mem2array start_pc 32 $int_vector_base 1 + arc jtag set-aux-reg 0x6 $start_pc(0) + + # It is OK to do uncached writes - register cache will be invalidated by + # the reset_assert() function. +} + +# vim:expandtab: diff --git a/tcl/cpu/arc/em.tcl b/tcl/cpu/arc/em.tcl new file mode 100644 index 000000000..f0455bb74 --- /dev/null +++ b/tcl/cpu/arc/em.tcl @@ -0,0 +1,32 @@ +# Copyright (C) 2015, 2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +source [find cpu/arc/v2.tcl] + +proc arc_em_examine_target { {target ""} } { + # Will set current target + arc_v2_examine_target $target +} + +proc arc_em_init_regs { } { + arc_v2_init_regs + + [target current] configure \ + -event examine-end "arc_em_examine_target [target current]" +} + +# Scripts in "target" folder should call this function instead of direct +# invocation of arc_common_reset. +proc arc_em_reset { {target ""} } { + arc_v2_reset $target + + # Set DEBUG.ED bit to enable clock in actionpoint module. + # This is specific to ARC EM. + set debug [arc jtag get-aux-reg 5] + if { !($debug & (1 << 20)) } { + arc jtag set-aux-reg 5 [expr $debug | (1 << 20)] + } +} diff --git a/tcl/cpu/arc/v2.tcl b/tcl/cpu/arc/v2.tcl new file mode 100644 index 000000000..ad55361a5 --- /dev/null +++ b/tcl/cpu/arc/v2.tcl @@ -0,0 +1,288 @@ +# Copyright (C) 2015, 2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +source [find cpu/arc/common.tcl] + +# Currently 'examine_target' can only read JTAG registers and set properties - +# but it shouldn't write any of registers - writes will be cached, but cache +# will be invalidated before flushing after examine_target, and changes will be +# lost. Perhaps that would be fixed later - perhaps writes shouldn't be cached +# after all. But if write to register is really needed from TCL - then it +# should be done via "arc jtag" for now. +proc arc_v2_examine_target { {target ""} } { + # Set current target, because OpenOCD event handlers don't do this for us. + if { $target != "" } { + targets $target + } + + # Those registers always exist. DEBUG and DEBUGI are formally optional, + # however they come with JTAG interface, and so far there is no way + # OpenOCD can communicate with target without JTAG interface. + arc set-reg-exists identity pc status32 bta debug lp_start lp_end \ + eret erbta erstatus ecr efa + + # 32 core registers + arc set-reg-exists \ + r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 \ + r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 \ + gp fp sp ilink r30 blink lp_count pcl + + # DCCM + set dccm_version [arc get-reg-field dccm_build version] + if { $dccm_version == 3 || $dccm_version == 4 } { + arc set-reg-exists aux_dccm + } + + # ICCM + if { [arc get-reg-field iccm_build version] == 4 } { + arc set-reg-exists aux_iccm + } + + # MPU + if { [arc get-reg-field mpu_build version] >= 2 && + [arc get-reg-field mpu_build version] <= 4 } { + arc set-reg-exists mpu_en mpu_ecr + set mpu_regions [arc get-reg-field mpu_build regions] + for {set i 0} {$i < $mpu_regions} {incr i} { + arc set-reg-exists mpu_rdp$i mpu_rdb$i + } + + # Secure MPU + if { [arc get-reg-field mpu_build version] == 4 } { + arc set-reg-exists mpu_index mpu_rstart mpu_rend mpu_rper + } + } +} + +proc arc_v2_init_regs { } { + # XML features + set core_feature "org.gnu.gdb.arc.core.v2" + set aux_min_feature "org.gnu.gdb.arc.aux-minimal" + set aux_other_feature "org.gnu.gdb.arc.aux-other" + + # Describe types + # Types are sorted alphabetically according to their name. + arc add-reg-type-struct -name ap_build_t -bitfield version 0 7 \ + -bitfield type 8 11 + arc add-reg-type-struct -name ap_control_t -bitfield at 0 3 -bitfield tt 4 5 \ + -bitfield m 6 6 -bitfield p 7 7 -bitfield aa 8 8 -bitfield q 9 9 + # Cycles field added in version 4. + arc add-reg-type-struct -name dccm_build_t -bitfield version 0 7 \ + -bitfield size0 8 11 -bitfield size1 12 15 -bitfield cycles 17 19 + + arc add-reg-type-struct -name debug_t \ + -bitfield fh 1 1 -bitfield ah 2 2 -bitfield asr 3 10 \ + -bitfield is 11 11 -bitfield ep 19 19 -bitfield ed 20 20 \ + -bitfield eh 21 21 -bitfield ra 22 22 -bitfield zz 23 23 \ + -bitfield sm 24 26 -bitfield ub 28 28 -bitfield bh 29 29 \ + -bitfield sh 30 30 -bitfield ld 31 31 + + arc add-reg-type-struct -name ecr_t \ + -bitfield parameter 0 7 \ + -bitfield cause 8 15 \ + -bitfield vector 16 23 \ + -bitfield U 30 30 \ + -bitfield P 31 31 + arc add-reg-type-struct -name iccm_build_t -bitfield version 0 7 \ + -bitfield iccm0_size0 8 11 -bitfield iccm1_size0 12 15 \ + -bitfield iccm0_size1 16 19 -bitfield iccm1_size1 20 23 + arc add-reg-type-struct -name identity_t \ + -bitfield arcver 0 7 -bitfield arcnum 8 15 -bitfield chipid 16 31 + arc add-reg-type-struct -name isa_config_t -bitfield version 0 7 \ + -bitfield pc_size 8 11 -bitfield lpc_size 12 15 -bitfield addr_size 16 19 \ + -bitfield b 20 20 -bitfield a 21 21 -bitfield n 22 22 -bitfield l 23 23 \ + -bitfield c 24 27 -bitfield d 28 31 + arc add-reg-type-struct -name mpu_build_t -bitfield version 0 7 \ + -bitfield regions 8 15 \ + -bitfield s 16 16 \ + -bitfield i 17 17 + arc add-reg-type-struct -name mpu_ecr_t \ + -bitfield MR 0 7 \ + -bitfield VT 8 9 \ + -bitfield EC_CODE 16 31 + arc add-reg-type-struct -name mpu_en_t \ + -bitfield UE 3 3 -bitfield UW 4 4 -bitfield UR 5 5 \ + -bitfield KE 6 6 -bitfield KW 7 7 -bitfield KR 8 8 \ + -bitfield S 15 15 -bitfield SID 16 23 \ + -bitfield EN 30 30 + arc add-reg-type-struct -name mpu_index_t \ + -bitfield I 0 3 -bitfield M 30 30 -bitfield D 31 31 + arc add-reg-type-struct -name mpu_rper_t \ + -bitfield V 0 0 \ + -bitfield UE 3 3 -bitfield UW 4 4 -bitfield UR 5 5 \ + -bitfield KE 6 6 -bitfield KW 7 7 -bitfield KR 8 8 \ + -bitfield S 15 15 -bitfield SID 16 23 + arc add-reg-type-flags -name status32_t \ + -flag H 0 -flag E0 1 -flag E1 2 -flag E2 3 \ + -flag E3 4 -flag AE 5 -flag DE 6 -flag U 7 \ + -flag V 8 -flag C 9 -flag N 10 -flag Z 11 \ + -flag L 12 -flag DZ 13 -flag SC 14 -flag ES 15 \ + -flag RB0 16 -flag RB1 17 -flag RB2 18 \ + -flag AD 19 -flag US 20 -flag IE 31 + + # Core registers + set core_regs { + r0 0 uint32 + r1 1 uint32 + r2 2 uint32 + r3 3 uint32 + r4 4 uint32 + r5 5 uint32 + r6 6 uint32 + r7 7 uint32 + r8 8 uint32 + r9 9 uint32 + r10 10 uint32 + r11 11 uint32 + r12 12 uint32 + r13 13 uint32 + r14 14 uint32 + r15 15 uint32 + r16 16 uint32 + r17 17 uint32 + r18 18 uint32 + r19 19 uint32 + r20 20 uint32 + r21 21 uint32 + r22 23 uint32 + r23 24 uint32 + r24 24 uint32 + r25 25 uint32 + gp 26 data_ptr + fp 27 data_ptr + sp 28 data_ptr + ilink 29 code_ptr + r30 30 uint32 + blink 31 code_ptr + r32 32 uint32 + r33 33 uint32 + r34 34 uint32 + r35 35 uint32 + r36 36 uint32 + r37 37 uint32 + r38 38 uint32 + r39 39 uint32 + r40 40 uint32 + r41 41 uint32 + r42 42 uint32 + r43 43 uint32 + r44 44 uint32 + r45 45 uint32 + r46 46 uint32 + r47 47 uint32 + r48 48 uint32 + r49 49 uint32 + r50 50 uint32 + r51 51 uint32 + r52 52 uint32 + r53 53 uint32 + r54 54 uint32 + r55 55 uint32 + r56 56 uint32 + r57 57 uint32 + accl 58 uint32 + acch 59 uint32 + lp_count 60 uint32 + limm 61 uint32 + reserved 62 uint32 + pcl 63 code_ptr + } + foreach {reg count type} $core_regs { + arc add-reg -name $reg -num $count -core -type $type -g \ + -feature $core_feature + } + + # AUX min + set aux_min { + 0x6 pc code_ptr + 0x2 lp_start code_ptr + 0x3 lp_end code_ptr + 0xA status32 status32_t + } + foreach {num name type} $aux_min { + arc add-reg -name $name -num $num -type $type -feature $aux_min_feature -g + } + + # AUX other + set aux_other { + 0x004 identity identity_t + 0x005 debug debug_t + 0x018 aux_dccm int + 0x208 aux_iccm int + + + 0x400 eret code_ptr + 0x401 erbta code_ptr + 0x402 erstatus status32_t + 0x403 ecr ecr_t + 0x404 efa data_ptr + + 0x409 mpu_en mpu_en_t + + 0x412 bta code_ptr + + 0x420 mpu_ecr mpu_ecr_t + 0x422 mpu_rdb0 int + 0x423 mpu_rdp0 int + 0x424 mpu_rdb1 int + 0x425 mpu_rdp1 int + 0x426 mpu_rdb2 int + 0x427 mpu_rdp2 int + 0x428 mpu_rdb3 int + 0x429 mpu_rdp3 int + 0x42A mpu_rdb4 int + 0x42B mpu_rdp4 int + 0x42C mpu_rdb5 int + 0x42D mpu_rdp5 int + 0x42E mpu_rdb6 int + 0x42F mpu_rdp6 int + 0x430 mpu_rdb7 int + 0x431 mpu_rdp7 int + 0x432 mpu_rdb8 int + 0x433 mpu_rdp8 int + 0x434 mpu_rdb9 int + 0x435 mpu_rdp9 int + 0x436 mpu_rdb10 int + 0x437 mpu_rdp10 int + 0x438 mpu_rdb11 int + 0x439 mpu_rdp11 int + 0x43A mpu_rdb12 int + 0x43B mpu_rdp12 int + 0x43C mpu_rdb13 int + 0x43D mpu_rdp13 int + 0x43E mpu_rdb14 int + 0x43F mpu_rdp14 int + 0x440 mpu_rdb15 int + 0x441 mpu_rdp15 int + 0x448 mpu_index mpu_index_t + 0x449 mpu_rstart uint32 + 0x44A mpu_rend uint32 + 0x44B mpu_rper mpu_rper_t + 0x44C mpu_probe uint32 + } + foreach {num name type} $aux_other { + arc add-reg -name $name -num $num -type $type -feature $aux_other_feature + } + + # AUX BCR + set bcr { + 0x6D mpu_build + 0x74 dccm_build + 0x76 ap_build + 0x78 iccm_build + 0xC1 isa_config + } + foreach {num reg} $bcr { + arc add-reg -name $reg -num $num -type ${reg}_t -bcr -feature $aux_other_feature + } + + [target current] configure \ + -event examine-end "arc_v2_examine_target [target current]" +} + +proc arc_v2_reset { {target ""} } { + arc_common_reset $target +} diff --git a/tcl/cpu/arm/arm7tdmi.tcl b/tcl/cpu/arm/arm7tdmi.tcl index 37db26618..a1d4a1f46 100644 --- a/tcl/cpu/arm/arm7tdmi.tcl +++ b/tcl/cpu/arm/arm7tdmi.tcl @@ -3,4 +3,3 @@ set CPU_NAME arm7tdmi set CPU_ARCH armv4t set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 - diff --git a/tcl/cpu/arm/arm920.tcl b/tcl/cpu/arm/arm920.tcl index f19b20b3c..c01f602f2 100644 --- a/tcl/cpu/arm/arm920.tcl +++ b/tcl/cpu/arm/arm920.tcl @@ -3,4 +3,3 @@ set CPU_NAME arm920 set CPU_ARCH armv4t set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 - diff --git a/tcl/cpu/arm/arm946.tcl b/tcl/cpu/arm/arm946.tcl index 520410178..a6110a53f 100644 --- a/tcl/cpu/arm/arm946.tcl +++ b/tcl/cpu/arm/arm946.tcl @@ -3,4 +3,3 @@ set CPU_NAME arm946 set CPU_ARCH armv5te set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 - diff --git a/tcl/cpu/arm/arm966.tcl b/tcl/cpu/arm/arm966.tcl index 83ce0f673..1fffbc092 100644 --- a/tcl/cpu/arm/arm966.tcl +++ b/tcl/cpu/arm/arm966.tcl @@ -3,4 +3,3 @@ set CPU_NAME arm966 set CPU_ARCH armv5te set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 - diff --git a/tcl/cpu/arm/cortex_m3.tcl b/tcl/cpu/arm/cortex_m3.tcl index 166af847d..c9950261f 100644 --- a/tcl/cpu/arm/cortex_m3.tcl +++ b/tcl/cpu/arm/cortex_m3.tcl @@ -3,4 +3,3 @@ set CPU_NAME cortex_m3 set CPU_ARCH armv7 set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 - diff --git a/tcl/fpga/xilinx-xadc.cfg b/tcl/fpga/xilinx-xadc.cfg index 38691045c..d4be4f541 100644 --- a/tcl/fpga/xilinx-xadc.cfg +++ b/tcl/fpga/xilinx-xadc.cfg @@ -5,7 +5,7 @@ # voltages. The XADC is available both from fabric as well as through the # JTAG TAP. # -# This code implements access throught the JTAG TAP. +# This code implements access through the JTAG TAP. # # https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf diff --git a/tcl/interface/altera-usb-blaster.cfg b/tcl/interface/altera-usb-blaster.cfg index 1bfef9dc4..84e77b13c 100644 --- a/tcl/interface/altera-usb-blaster.cfg +++ b/tcl/interface/altera-usb-blaster.cfg @@ -4,7 +4,7 @@ # http://www.altera.com/literature/ug/ug_usb_blstr.pdf # -interface usb_blaster +adapter driver usb_blaster usb_blaster_lowlevel_driver ftdi # These are already the defaults. # usb_blaster_vid_pid 0x09FB 0x6001 diff --git a/tcl/interface/altera-usb-blaster2.cfg b/tcl/interface/altera-usb-blaster2.cfg index c35be1970..4642b1dcf 100644 --- a/tcl/interface/altera-usb-blaster2.cfg +++ b/tcl/interface/altera-usb-blaster2.cfg @@ -2,7 +2,7 @@ # Altera USB-Blaster II # -interface usb_blaster +adapter driver usb_blaster usb_blaster_vid_pid 0x09fb 0x6010 0x09fb 0x6810 usb_blaster_lowlevel_driver ublast2 usb_blaster_firmware /path/to/quartus/blaster_6810.hex diff --git a/tcl/interface/arm-jtag-ew.cfg b/tcl/interface/arm-jtag-ew.cfg index 2e8b57e4c..797bb7121 100644 --- a/tcl/interface/arm-jtag-ew.cfg +++ b/tcl/interface/arm-jtag-ew.cfg @@ -4,5 +4,4 @@ # http://www.olimex.com/dev/arm-jtag-ew.html # -interface arm-jtag-ew - +adapter driver arm-jtag-ew diff --git a/tcl/interface/at91rm9200.cfg b/tcl/interface/at91rm9200.cfg index 20826478d..b66e060d1 100644 --- a/tcl/interface/at91rm9200.cfg +++ b/tcl/interface/at91rm9200.cfg @@ -4,6 +4,5 @@ # TODO: URL? # -interface at91rm9200 +adapter driver at91rm9200 at91rm9200_device rea_ecr - diff --git a/tcl/interface/buspirate.cfg b/tcl/interface/buspirate.cfg index c2f3a83c4..265e37e06 100644 --- a/tcl/interface/buspirate.cfg +++ b/tcl/interface/buspirate.cfg @@ -4,7 +4,7 @@ # http://dangerousprototypes.com/bus-pirate-manual/ # -interface buspirate +adapter driver buspirate # you need to specify port on which BP lives #buspirate_port /dev/ttyUSB0 @@ -23,4 +23,3 @@ buspirate_speed normal ;# or fast # this depends on the cable, you are safe with this option reset_config srst_only - diff --git a/tcl/interface/calao-usb-a9260.cfg b/tcl/interface/calao-usb-a9260.cfg index 5fae2f3b3..01b426b89 100644 --- a/tcl/interface/calao-usb-a9260.cfg +++ b/tcl/interface/calao-usb-a9260.cfg @@ -6,6 +6,5 @@ # See calao-usb-a9260-c01.cfg and calao-usb-a9260-c02.cfg. # -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 - diff --git a/tcl/interface/chameleon.cfg b/tcl/interface/chameleon.cfg index 2fb74681c..1cb1d6151 100644 --- a/tcl/interface/chameleon.cfg +++ b/tcl/interface/chameleon.cfg @@ -4,6 +4,5 @@ # http://www.amontec.com/chameleon.shtml # -interface parport +adapter driver parport parport_cable chameleon - diff --git a/tcl/interface/cmsis-dap.cfg b/tcl/interface/cmsis-dap.cfg index ab5c187eb..887d2d713 100644 --- a/tcl/interface/cmsis-dap.cfg +++ b/tcl/interface/cmsis-dap.cfg @@ -4,7 +4,7 @@ # http://www.keil.com/support/man/docs/dapdebug/ # -interface cmsis-dap +adapter driver cmsis-dap # Optionally specify the serial number of CMSIS-DAP usb device. #cmsis_dap_serial 02200201E6661E601B98E3B9 diff --git a/tcl/interface/dummy.cfg b/tcl/interface/dummy.cfg index 1c148c0cb..154c872cf 100644 --- a/tcl/interface/dummy.cfg +++ b/tcl/interface/dummy.cfg @@ -2,5 +2,4 @@ # Dummy interface (for testing purposes) # -interface dummy - +adapter driver dummy diff --git a/tcl/interface/estick.cfg b/tcl/interface/estick.cfg index adefcb73f..75e6ea8e5 100644 --- a/tcl/interface/estick.cfg +++ b/tcl/interface/estick.cfg @@ -4,4 +4,4 @@ # http://code.google.com/p/estick-jtag/ # -interface opendous +adapter driver opendous diff --git a/tcl/interface/flashlink.cfg b/tcl/interface/flashlink.cfg index 56dc35e20..e0a4b97d0 100644 --- a/tcl/interface/flashlink.cfg +++ b/tcl/interface/flashlink.cfg @@ -11,6 +11,6 @@ if { [info exists PARPORTADDR] } { set _PARPORTADDR 0 } -interface parport +adapter driver parport parport_port $_PARPORTADDR parport_cable flashlink diff --git a/tcl/interface/ft232r.cfg b/tcl/interface/ft232r.cfg index b4f71c8d4..2c705c335 100644 --- a/tcl/interface/ft232r.cfg +++ b/tcl/interface/ft232r.cfg @@ -1,2 +1,2 @@ -interface ft232r -adapter_khz 1000 +adapter driver ft232r +adapter speed 1000 diff --git a/tcl/interface/ftdi/100ask-openjtag.cfg b/tcl/interface/ftdi/100ask-openjtag.cfg index 01ae2f7ea..3cbd37e06 100644 --- a/tcl/interface/ftdi/100ask-openjtag.cfg +++ b/tcl/interface/ftdi/100ask-openjtag.cfg @@ -7,7 +7,7 @@ # https://blog.matthiasbock.net/wp-content/uploads/2015/04/100ask-JTAGv3.pdf # -interface ftdi +adapter driver ftdi ftdi_device_desc "USB<=>JTAG&RS232" ftdi_vid_pid 0x1457 0x5118 diff --git a/tcl/interface/ftdi/axm0432.cfg b/tcl/interface/ftdi/axm0432.cfg index 0c24a333e..6cc1752e2 100644 --- a/tcl/interface/ftdi/axm0432.cfg +++ b/tcl/interface/ftdi/axm0432.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Symphony SoundBite" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/c232hm.cfg b/tcl/interface/ftdi/c232hm.cfg index 387abbb05..27cf76674 100644 --- a/tcl/interface/ftdi/c232hm.cfg +++ b/tcl/interface/ftdi/c232hm.cfg @@ -1,4 +1,3 @@ -# # FTDI USB Hi-Speed to MPSSE Cable # # http://www.ftdichip.com/Products/Cables/USBMPSSE.htm @@ -6,10 +5,52 @@ # C232HM-DDHSL-0 and C232HM-EDSL-0 provide 3.3V and 5V on pin 1 (Red), # respectively. # +# Adapter: http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_C232HM_MPSSE_CABLE.PDF +# Chip: http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf +# See pinout/colors at end of this file. +# +# Tech notes: +# http://www.ftdichip.com/Support/Documents/AppNotes/AN_135_MPSSE_Basics.pdf +# http://www.ftdichip.com/Support/Documents/AppNotes/AN_129_FTDI_Hi_Speed_USB_To_JTAG_Example.pdf -interface ftdi +adapter driver ftdi #ftdi_device_desc "C232HM-DDHSL-0" #ftdi_device_desc "C232HM-EDHSL-0" + +# Common PID for FT232H ftdi_vid_pid 0x0403 0x6014 -ftdi_layout_init 0x0008 0x000b +# Layout +# High data byte 0x40 configures red LED on ACBUS6 initially high (unlit, since active-low) +# Low data byte 0x08 configures TMS on ACBUS3 initially high (asserted); TCK, TDI low +# High direction byte 0x40 configures red LED on ACBUS6 as high (output) +# Low direction byte 0x0b configures TDO on ACBUS2 as low (input) +ftdi_layout_init 0x4008 0x400b + +# ---A*BUS-------CCCCCCCC|DDDDDDDD +# --------\______76543210|76543210 +# LED 0x4000 = 01000000|00000000 = ACBUS6 +#GPIOL0 0x0010 = 00000000|00010000 = ADBUS4 +#GPIOL1 0x0020 = 00000000|00100000 = ADBUS5 +#GPIOL2 0x0040 = 00000000|01000000 = ADBUS6 +#GPIOL3 0x0080 = 00000000|10000000 = ADBUS7 +# -ndata treats the LED as active-low for expected behavior (toggle when transferring) +ftdi_layout_signal LED -ndata 0x4000 +# Available for aliasing as desired +ftdi_layout_signal GPIOL0 -data 0x0010 -oe 0x0010 +ftdi_layout_signal GPIOL1 -data 0x0020 -oe 0x0020 +ftdi_layout_signal GPIOL2 -data 0x0040 -oe 0x0040 +ftdi_layout_signal GPIOL3 -data 0x0080 -oe 0x0080 + +# C232HM FT232H JTAG/Other +# Num Color Name Func +# 1 Red VCC Optionally, can power the board if it is not using its own power supply. +# 2 Orange ADBUS0 TCK +# 3 Yellow ADBUS1 TDI +# 4 Green ADBUS2 TDO +# 5 Brown ADBUS3 TMS +# 6 Grey ADBUS4 GPIOL0 +# 7 Purple ADBUS5 GPIOL1 +# 8 White ADBUS6 GPIOL2 +# 9 Blue ADBUS7 GPIOL3 +# 10 Black GND Connect to ground diff --git a/tcl/interface/ftdi/calao-usb-a9260-c01.cfg b/tcl/interface/ftdi/calao-usb-a9260-c01.cfg index d3da6b7ec..a23ddbfb5 100644 --- a/tcl/interface/ftdi/calao-usb-a9260-c01.cfg +++ b/tcl/interface/ftdi/calao-usb-a9260-c01.cfg @@ -10,7 +10,7 @@ echo "interface uses the same layout as configs that were verified. Please repor echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "USB-A9260" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/calao-usb-a9260-c02.cfg b/tcl/interface/ftdi/calao-usb-a9260-c02.cfg index dc4dca8f7..67427c5c0 100644 --- a/tcl/interface/ftdi/calao-usb-a9260-c02.cfg +++ b/tcl/interface/ftdi/calao-usb-a9260-c02.cfg @@ -10,7 +10,7 @@ echo "interface uses the same layout as configs that were verified. Please repor echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "USB-A9260" ftdi_vid_pid 0x0403 0x6001 diff --git a/tcl/interface/ftdi/cortino.cfg b/tcl/interface/ftdi/cortino.cfg index 16ede6129..2bc516cc6 100644 --- a/tcl/interface/ftdi/cortino.cfg +++ b/tcl/interface/ftdi/cortino.cfg @@ -4,7 +4,7 @@ # http://www.hitex.com/index.php?id=cortino # -interface ftdi +adapter driver ftdi ftdi_device_desc "Cortino" ftdi_vid_pid 0x0640 0x0032 diff --git a/tcl/interface/ftdi/digilent-hs1.cfg b/tcl/interface/ftdi/digilent-hs1.cfg index e27249b3b..dfba3393a 100644 --- a/tcl/interface/ftdi/digilent-hs1.cfg +++ b/tcl/interface/ftdi/digilent-hs1.cfg @@ -1,7 +1,7 @@ # this supports JTAG-HS1 and JTAG-SMT1 # (the later being the OEM on-board version) -interface ftdi +adapter driver ftdi ftdi_device_desc "Digilent Adept USB Device" ftdi_vid_pid 0x0403 0x6010 # channel 1 does not have any functionality diff --git a/tcl/interface/ftdi/digilent-hs2.cfg b/tcl/interface/ftdi/digilent-hs2.cfg index 2005b66af..ae6ba01bb 100644 --- a/tcl/interface/ftdi/digilent-hs2.cfg +++ b/tcl/interface/ftdi/digilent-hs2.cfg @@ -1,6 +1,6 @@ # this supports JTAG-HS2 (and apparently Nexys4 as well) -interface ftdi +adapter driver ftdi ftdi_device_desc "Digilent Adept USB Device" ftdi_vid_pid 0x0403 0x6014 diff --git a/tcl/interface/ftdi/digilent_jtag_hs3.cfg b/tcl/interface/ftdi/digilent_jtag_hs3.cfg index f7b8e570c..7160bed8e 100644 --- a/tcl/interface/ftdi/digilent_jtag_hs3.cfg +++ b/tcl/interface/ftdi/digilent_jtag_hs3.cfg @@ -2,7 +2,7 @@ # Digilent JTAG-HS3 # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6014 ftdi_device_desc "Digilent USB Device" diff --git a/tcl/interface/ftdi/digilent_jtag_smt2.cfg b/tcl/interface/ftdi/digilent_jtag_smt2.cfg index 014fe1475..493ed6af5 100644 --- a/tcl/interface/ftdi/digilent_jtag_smt2.cfg +++ b/tcl/interface/ftdi/digilent_jtag_smt2.cfg @@ -7,7 +7,7 @@ # http://electronix.ru/forum/index.php?showtopic=114633&view=findpost&p=1215497 and ZedBoard schematics # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6014 ftdi_layout_init 0x2088 0x3f8b diff --git a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg index a83a0081e..bc783a46c 100644 --- a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg +++ b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg @@ -10,7 +10,7 @@ # Note that the digilent_jtag_smt2 layout does not work and hangs while # the ftdi_device_desc from digilent_hs2 is wrong. -interface ftdi +adapter driver ftdi ftdi_device_desc "Digilent USB Device" ftdi_vid_pid 0x0403 0x6014 ftdi_channel 0 diff --git a/tcl/interface/ftdi/dlp-usb1232h.cfg b/tcl/interface/ftdi/dlp-usb1232h.cfg index f447771e3..9ddc2c80a 100644 --- a/tcl/interface/ftdi/dlp-usb1232h.cfg +++ b/tcl/interface/ftdi/dlp-usb1232h.cfg @@ -12,7 +12,7 @@ echo "This file was not tested with real interface, it is based on schematics an echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/dp_busblaster.cfg b/tcl/interface/ftdi/dp_busblaster.cfg index 73827cfb8..86ab4d840 100644 --- a/tcl/interface/ftdi/dp_busblaster.cfg +++ b/tcl/interface/ftdi/dp_busblaster.cfg @@ -11,7 +11,7 @@ echo "Info : If you need SWD support, flash KT-Link buffer from https://github.com/bharrisau/busblaster and use dp_busblaster_kt-link.cfg instead" -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg index 2d27519d4..d49a4c98f 100644 --- a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg +++ b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg @@ -9,7 +9,7 @@ # http://dangerousprototypes.com/docs/Bus_Blaster # -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/flossjtag-noeeprom.cfg b/tcl/interface/ftdi/flossjtag-noeeprom.cfg index 18046e742..42ed18ec3 100644 --- a/tcl/interface/ftdi/flossjtag-noeeprom.cfg +++ b/tcl/interface/ftdi/flossjtag-noeeprom.cfg @@ -17,7 +17,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/flossjtag.cfg b/tcl/interface/ftdi/flossjtag.cfg index 13e1f0bb7..c4ad81dcc 100644 --- a/tcl/interface/ftdi/flossjtag.cfg +++ b/tcl/interface/ftdi/flossjtag.cfg @@ -17,7 +17,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_device_desc "FLOSS-JTAG" #ftdi_serial "FJ000001" diff --git a/tcl/interface/ftdi/flyswatter.cfg b/tcl/interface/ftdi/flyswatter.cfg index 56dab1f33..5e9d4816d 100644 --- a/tcl/interface/ftdi/flyswatter.cfg +++ b/tcl/interface/ftdi/flyswatter.cfg @@ -4,7 +4,7 @@ # http://www.tincantools.com/product.php?productid=16134 # -interface ftdi +adapter driver ftdi ftdi_device_desc "Flyswatter" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/flyswatter2.cfg b/tcl/interface/ftdi/flyswatter2.cfg index 8bd4db4b7..45dd0bacb 100644 --- a/tcl/interface/ftdi/flyswatter2.cfg +++ b/tcl/interface/ftdi/flyswatter2.cfg @@ -4,7 +4,7 @@ # http://www.tincantools.com/product.php?productid=16153 # -interface ftdi +adapter driver ftdi ftdi_device_desc "Flyswatter2" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/ft232h-module-swd.cfg b/tcl/interface/ftdi/ft232h-module-swd.cfg index d2bd1da61..98a8c844f 100644 --- a/tcl/interface/ftdi/ft232h-module-swd.cfg +++ b/tcl/interface/ftdi/ft232h-module-swd.cfg @@ -6,7 +6,7 @@ # # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6014 @@ -15,7 +15,7 @@ ftdi_vid_pid 0x0403 0x6014 ftdi_layout_init 0x0030 0x003b # 0xfff8 0xfffb # Those signal are only required on some platforms or may required to be -# enabled explicitely (e.g. nrf5x chips). +# enabled explicitly (e.g. nrf5x chips). ftdi_layout_signal nSRST -data 0x0010 -oe 0x0010 ftdi_layout_signal nTRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/gw16042.cfg b/tcl/interface/ftdi/gw16042.cfg index 90c6f7c12..1288f77b1 100644 --- a/tcl/interface/ftdi/gw16042.cfg +++ b/tcl/interface/ftdi/gw16042.cfg @@ -17,7 +17,7 @@ # BDBUS1 TXD (input) # -interface ftdi +adapter driver ftdi ftdi_device_desc "USB-JTAG" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg index b682333ed..3802f6d2c 100644 --- a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "NXHX 10-ETM" ftdi_vid_pid 0x0640 0x0028 diff --git a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg index 3483030c6..f2e64b4f5 100644 --- a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "NXHX 500-ETM" ftdi_vid_pid 0x0640 0x0028 diff --git a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg index b4cada055..38f3c690e 100644 --- a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "NXHX 500-RE" ftdi_vid_pid 0x0640 0x0028 diff --git a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg index 67074a263..bff081f18 100644 --- a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "NXHX 50-ETM" ftdi_vid_pid 0x0640 0x0028 diff --git a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg index 966dcd812..f9fbd015a 100644 --- a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "NXHX50-RE" ftdi_vid_pid 0x0640 0x0028 diff --git a/tcl/interface/ftdi/hitex_lpc1768stick.cfg b/tcl/interface/ftdi/hitex_lpc1768stick.cfg index f22d4f7b2..9fe80f126 100644 --- a/tcl/interface/ftdi/hitex_lpc1768stick.cfg +++ b/tcl/interface/ftdi/hitex_lpc1768stick.cfg @@ -5,11 +5,10 @@ # -interface ftdi +adapter driver ftdi ftdi_device_desc "LPC1768-Stick" ftdi_vid_pid 0x0640 0x0026 ftdi_layout_init 0x0388 0x038b ftdi_layout_signal nTRST -data 0x0100 ftdi_layout_signal nSRST -data 0x0080 -noe 0x200 - diff --git a/tcl/interface/ftdi/hitex_str9-comstick.cfg b/tcl/interface/ftdi/hitex_str9-comstick.cfg index c46f0322c..2b3dc3690 100644 --- a/tcl/interface/ftdi/hitex_str9-comstick.cfg +++ b/tcl/interface/ftdi/hitex_str9-comstick.cfg @@ -4,7 +4,7 @@ # http://www.hitex.com/index.php?id=383 # -interface ftdi +adapter driver ftdi ftdi_device_desc "STR9-comStick" ftdi_vid_pid 0x0640 0x002c diff --git a/tcl/interface/ftdi/icebear.cfg b/tcl/interface/ftdi/icebear.cfg index 2c03d417b..04c27319e 100644 --- a/tcl/interface/ftdi/icebear.cfg +++ b/tcl/interface/ftdi/icebear.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "ICEbear JTAG adapter" ftdi_vid_pid 0x0403 0xc140 diff --git a/tcl/interface/ftdi/imx8mp-evk.cfg b/tcl/interface/ftdi/imx8mp-evk.cfg new file mode 100644 index 000000000..4e04e8cd7 --- /dev/null +++ b/tcl/interface/ftdi/imx8mp-evk.cfg @@ -0,0 +1,28 @@ +# +# Configuration file for NXP MC-IMX8MP-EVK on-board internal JTAG +# +# Using this interface requires enabling "remote mode" for the board using the +# NXP bcu tool (see https://github.com/NXPmicro/bcu) +# +# bcu set_gpio remote_en 1 -board=imx8mpevk +# +# The REMOTE_EN gpio is accessible through the same FTDI adapter but it's +# behind an I2C GPIO expander. +# + +adapter driver ftdi +ftdi_vid_pid 0x0403 0x6011 +ftdi_channel 0 + +ftdi_layout_init 0x00f8 0x000b + +ftdi_layout_signal RESET_B -data 0x0010 -oe 0x0010 +# Called SYS_nRST in schematics +ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi_layout_signal IO_nRST -data 0x0040 -oe 0x0040 +ftdi_layout_signal ONOFF_B -data 0x0080 -oe 0x0080 + +ftdi_layout_signal GPIO1 -data 0x0100 -oe 0x0100 +ftdi_layout_signal GPIO2 -data 0x0200 -oe 0x0200 +ftdi_layout_signal GPIO3 -data 0x0400 -oe 0x0400 +ftdi_layout_signal GPIO4 -data 0x0800 -oe 0x0800 diff --git a/tcl/interface/ftdi/incircuit-icprog.cfg b/tcl/interface/ftdi/incircuit-icprog.cfg index 5e90a7035..e0bd5ef59 100644 --- a/tcl/interface/ftdi/incircuit-icprog.cfg +++ b/tcl/interface/ftdi/incircuit-icprog.cfg @@ -6,7 +6,7 @@ # http://wiki.in-circuit.de/images/0/06/610000158A_openocd.pdf # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_layout_init 0x0508 0x0f1b diff --git a/tcl/interface/ftdi/iotlab-usb.cfg b/tcl/interface/ftdi/iotlab-usb.cfg index fbbad0c86..caa0596fd 100644 --- a/tcl/interface/ftdi/iotlab-usb.cfg +++ b/tcl/interface/ftdi/iotlab-usb.cfg @@ -3,7 +3,7 @@ # https://github.com/iot-lab/iot-lab/wiki # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_layout_init 0x0008 0x000b diff --git a/tcl/interface/ftdi/isodebug.cfg b/tcl/interface/ftdi/isodebug.cfg new file mode 100644 index 000000000..ead28644c --- /dev/null +++ b/tcl/interface/ftdi/isodebug.cfg @@ -0,0 +1,27 @@ +# isodebug v1 +# 5 kV isolated JTAG/SWD + UART adapter by Unjo AB + +adapter driver ftdi +ftdi_vid_pid 0x22b7 0x150d + +ftdi_layout_init 0x0ff8 0xfffb + +ftdi_layout_signal LED -ndata 0x0100 +ftdi_layout_signal nTRST -data 0x0200 +ftdi_layout_signal nSRST -noe 0x0400 +ftdi_layout_signal SWDIO_OE -data 0x0008 + +# Mode signals, either of these needs to be high to drive the JTAG/SWD pins. +# The power-on state is low for both signals but the init setting above sets +# JTAG_EN high. +ftdi_layout_signal SWD_EN -data 0x1000 +ftdi_layout_signal JTAG_EN -data 0x0800 + +# In SWD mode, the JTAG_EN signal doubles as SWO_EN_N which switches the +# second FTDI channel UART RxD to the SWO pin instead of the separate RxD +# pin. Note that the default init state has this pin high so when OpenOCD +# starts in SWD mode, SWO is by default disabled. To enable SWO tracing, +# issue the command 'ftdi_set_signal SWO_EN 1' where tracing is configured. +# To switch back to using the separate UART, SWO_EN needs to be disabled +# before exiting OpenOCD, or the adapter replugged. +ftdi_layout_signal SWO_EN -nalias JTAG_EN diff --git a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg index c5e5db420..82eeaa7b5 100644 --- a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg +++ b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg @@ -4,7 +4,7 @@ # http://www.distortec.com # -interface ftdi +adapter driver ftdi ftdi_device_desc "JTAG-lock-pick Tiny 2" ftdi_vid_pid 0x0403 0x8220 diff --git a/tcl/interface/ftdi/jtagkey.cfg b/tcl/interface/ftdi/jtagkey.cfg index 7b87e6df1..06463ab91 100644 --- a/tcl/interface/ftdi/jtagkey.cfg +++ b/tcl/interface/ftdi/jtagkey.cfg @@ -4,7 +4,7 @@ # http://www.amontec.com/jtagkey.shtml # -interface ftdi +adapter driver ftdi ftdi_device_desc "Amontec JTAGkey" ftdi_vid_pid 0x0403 0xcff8 diff --git a/tcl/interface/ftdi/jtagkey2.cfg b/tcl/interface/ftdi/jtagkey2.cfg index c6c2b32f4..ba151d3b5 100644 --- a/tcl/interface/ftdi/jtagkey2.cfg +++ b/tcl/interface/ftdi/jtagkey2.cfg @@ -4,7 +4,7 @@ # http://www.amontec.com/jtagkey2.shtml # -interface ftdi +adapter driver ftdi ftdi_device_desc "Amontec JTAGkey-2" ftdi_vid_pid 0x0403 0xcff8 diff --git a/tcl/interface/ftdi/jtagkey2p.cfg b/tcl/interface/ftdi/jtagkey2p.cfg index dc9c4565e..acb5047e9 100644 --- a/tcl/interface/ftdi/jtagkey2p.cfg +++ b/tcl/interface/ftdi/jtagkey2p.cfg @@ -4,7 +4,7 @@ # http://www.amontec.com/jtagkey2p.shtml # -interface ftdi +adapter driver ftdi ftdi_device_desc "Amontec JTAGkey-2P" ftdi_vid_pid 0x0403 0xcff8 diff --git a/tcl/interface/ftdi/kt-link.cfg b/tcl/interface/ftdi/kt-link.cfg index 1f28d3a10..5fc5db9d0 100644 --- a/tcl/interface/ftdi/kt-link.cfg +++ b/tcl/interface/ftdi/kt-link.cfg @@ -4,7 +4,7 @@ # http://www.kristech.eu # -interface ftdi +adapter driver ftdi ftdi_device_desc "KT-LINK" ftdi_vid_pid 0x0403 0xbbe2 diff --git a/tcl/interface/ftdi/lisa-l.cfg b/tcl/interface/ftdi/lisa-l.cfg index 67002bb96..4e52f7b7e 100644 --- a/tcl/interface/ftdi/lisa-l.cfg +++ b/tcl/interface/ftdi/lisa-l.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on schematics an echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Lisa/L" ftdi_vid_pid 0x0403 0x6010 ftdi_channel 1 diff --git a/tcl/interface/ftdi/luminary-icdi.cfg b/tcl/interface/ftdi/luminary-icdi.cfg index 2eea806d6..8bc783e92 100644 --- a/tcl/interface/ftdi/luminary-icdi.cfg +++ b/tcl/interface/ftdi/luminary-icdi.cfg @@ -15,7 +15,7 @@ # http://www.luminarymicro.com/products/ek-lm3s9b92.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Luminary Micro ICDI Board" ftdi_vid_pid 0x0403 0xbcda diff --git a/tcl/interface/ftdi/luminary-lm3s811.cfg b/tcl/interface/ftdi/luminary-lm3s811.cfg index 543b1e08f..aac915e34 100644 --- a/tcl/interface/ftdi/luminary-lm3s811.cfg +++ b/tcl/interface/ftdi/luminary-lm3s811.cfg @@ -11,7 +11,7 @@ # need to use the "luminary_icdi" layout to work correctly. # -interface ftdi +adapter driver ftdi ftdi_device_desc "LM3S811 Evaluation Board" ftdi_vid_pid 0x0403 0xbcd9 diff --git a/tcl/interface/ftdi/luminary.cfg b/tcl/interface/ftdi/luminary.cfg index 20b54220e..5e34f8cea 100644 --- a/tcl/interface/ftdi/luminary.cfg +++ b/tcl/interface/ftdi/luminary.cfg @@ -24,7 +24,7 @@ # firmware via the ITM module as well as profile data. # -interface ftdi +adapter driver ftdi ftdi_device_desc "Stellaris Evaluation Board" ftdi_vid_pid 0x0403 0xbcd9 diff --git a/tcl/interface/ftdi/m53evk.cfg b/tcl/interface/ftdi/m53evk.cfg index 2b9727049..6597f2d30 100644 --- a/tcl/interface/ftdi/m53evk.cfg +++ b/tcl/interface/ftdi/m53evk.cfg @@ -4,7 +4,7 @@ # http://www.denx-cs.de/?q=M53EVK # -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/mbftdi.cfg b/tcl/interface/ftdi/mbftdi.cfg index d051cccb0..c0ff86574 100644 --- a/tcl/interface/ftdi/mbftdi.cfg +++ b/tcl/interface/ftdi/mbftdi.cfg @@ -9,7 +9,7 @@ # and http://www.marsohod.org/plata-marsokhod3 for details. # -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/minimodule-swd.cfg b/tcl/interface/ftdi/minimodule-swd.cfg index 5f0b212f5..7ab46503e 100644 --- a/tcl/interface/ftdi/minimodule-swd.cfg +++ b/tcl/interface/ftdi/minimodule-swd.cfg @@ -34,7 +34,7 @@ Supports SWD using the FT2232H or FT4232H minimodule. # CN2-22 - nRESET # -interface ftdi +adapter driver ftdi #Select your module type and channel diff --git a/tcl/interface/ftdi/minimodule.cfg b/tcl/interface/ftdi/minimodule.cfg index 7df096d9c..5dcce1fcf 100644 --- a/tcl/interface/ftdi/minimodule.cfg +++ b/tcl/interface/ftdi/minimodule.cfg @@ -4,7 +4,7 @@ # http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf # -interface ftdi +adapter driver ftdi ftdi_device_desc "FT2232H MiniModule" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/minispartan6.cfg b/tcl/interface/ftdi/minispartan6.cfg index 8f1601192..97a6abe04 100644 --- a/tcl/interface/ftdi/minispartan6.cfg +++ b/tcl/interface/ftdi/minispartan6.cfg @@ -1,6 +1,6 @@ # https://www.scarabhardware.com/minispartan6/ # https://github.com/scarabhardware/miniSpartan6-plus/raw/master/miniSpartan6%2B_Rev_B.pdf -interface ftdi +adapter driver ftdi # The miniSpartan6+ sadly doesn't have a custom device description, so we just # have to hope you got it right. #ftdi_device_desc "Dual RS232-HS" @@ -12,4 +12,4 @@ ftdi_layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion -adapter_khz 30000 +adapter speed 30000 diff --git a/tcl/interface/ftdi/neodb.cfg b/tcl/interface/ftdi/neodb.cfg index 6cc8ccf71..1cfb3526c 100644 --- a/tcl/interface/ftdi/neodb.cfg +++ b/tcl/interface/ftdi/neodb.cfg @@ -4,7 +4,7 @@ # http://wiki.openmoko.org/wiki/Debug_Board_v3 # -interface ftdi +adapter driver ftdi ftdi_device_desc "Debug Board for Neo1973" ftdi_vid_pid 0x1457 0x5118 diff --git a/tcl/interface/ftdi/ngxtech.cfg b/tcl/interface/ftdi/ngxtech.cfg index 9eaa3c5bc..3aa79ab31 100644 --- a/tcl/interface/ftdi/ngxtech.cfg +++ b/tcl/interface/ftdi/ngxtech.cfg @@ -10,7 +10,7 @@ echo "interface uses the same layout as configs that were verified. Please repor echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "NGX JTAG" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg index 5b27d38ba..c8e3befb7 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg @@ -4,7 +4,7 @@ # http://www.olimex.com/dev/arm-usb-ocd-h.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" ftdi_vid_pid 0x15ba 0x002b diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg index e1aeeeab6..f9126d40d 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg @@ -4,7 +4,7 @@ # http://www.olimex.com/dev/arm-usb-ocd.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Olimex OpenOCD JTAG" ftdi_vid_pid 0x15ba 0x0003 diff --git a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg index f77c24b2c..eac25b6da 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg @@ -4,7 +4,7 @@ # http://www.olimex.com/dev/arm-usb-tiny-h.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" ftdi_vid_pid 0x15ba 0x002a diff --git a/tcl/interface/ftdi/olimex-jtag-tiny.cfg b/tcl/interface/ftdi/olimex-jtag-tiny.cfg index b3c6a716e..4811f4dda 100644 --- a/tcl/interface/ftdi/olimex-jtag-tiny.cfg +++ b/tcl/interface/ftdi/olimex-jtag-tiny.cfg @@ -4,7 +4,7 @@ # http://www.olimex.com/dev/arm-usb-tiny.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Olimex OpenOCD JTAG TINY" ftdi_vid_pid 0x15ba 0x0004 diff --git a/tcl/interface/ftdi/oocdlink.cfg b/tcl/interface/ftdi/oocdlink.cfg index fc09a1636..deba4a504 100644 --- a/tcl/interface/ftdi/oocdlink.cfg +++ b/tcl/interface/ftdi/oocdlink.cfg @@ -10,7 +10,7 @@ echo "interface uses the same layout as configs that were verified. Please repor echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "OOCDLink" ftdi_vid_pid 0x0403 0xbaf8 diff --git a/tcl/interface/ftdi/opendous_ftdi.cfg b/tcl/interface/ftdi/opendous_ftdi.cfg index 6a12d7212..50f32fb3a 100644 --- a/tcl/interface/ftdi/opendous_ftdi.cfg +++ b/tcl/interface/ftdi/opendous_ftdi.cfg @@ -7,7 +7,7 @@ # (and it has a different pid number). # -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 ftdi_channel 1 diff --git a/tcl/interface/ftdi/openocd-usb-hs.cfg b/tcl/interface/ftdi/openocd-usb-hs.cfg index 37a717dc5..6f67689f6 100644 --- a/tcl/interface/ftdi/openocd-usb-hs.cfg +++ b/tcl/interface/ftdi/openocd-usb-hs.cfg @@ -4,7 +4,7 @@ # http://shop.embedded-projects.net/index.php?module=artikel&action=artikel&id=14 # -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/openocd-usb.cfg b/tcl/interface/ftdi/openocd-usb.cfg index ff537c7b6..ed80a05d9 100644 --- a/tcl/interface/ftdi/openocd-usb.cfg +++ b/tcl/interface/ftdi/openocd-usb.cfg @@ -4,7 +4,7 @@ # http://www.hs-augsburg.de/~hhoegl/proj/usbjtag/usbjtag.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Dual RS232" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/openrd.cfg b/tcl/interface/ftdi/openrd.cfg index 9ec5b5f65..535c5e896 100644 --- a/tcl/interface/ftdi/openrd.cfg +++ b/tcl/interface/ftdi/openrd.cfg @@ -4,7 +4,7 @@ # http://www.marvell.com/products/embedded_processors/developer/kirkwood/openrd.jsp # -interface ftdi +adapter driver ftdi ftdi_device_desc "OpenRD JTAGKey FT2232D B" ftdi_vid_pid 0x0403 0x9e90 ftdi_channel 0 diff --git a/tcl/interface/ftdi/pipistrello.cfg b/tcl/interface/ftdi/pipistrello.cfg index 5ee5be5bb..2074924a3 100644 --- a/tcl/interface/ftdi/pipistrello.cfg +++ b/tcl/interface/ftdi/pipistrello.cfg @@ -1,6 +1,6 @@ # http://pipistrello.saanlima.com/ # http://www.saanlima.com/download/pipistrello-v2.0/pipistrello_v2_schematic.pdf -interface ftdi +adapter driver ftdi ftdi_device_desc "Pipistrello LX45" ftdi_vid_pid 0x0403 0x6010 # interface 1 is the uart @@ -10,4 +10,4 @@ ftdi_layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion -adapter_khz 10000 +adapter speed 10000 diff --git a/tcl/interface/ftdi/redbee-econotag.cfg b/tcl/interface/ftdi/redbee-econotag.cfg index 70c30d658..b6f6d23ba 100644 --- a/tcl/interface/ftdi/redbee-econotag.cfg +++ b/tcl/interface/ftdi/redbee-econotag.cfg @@ -13,7 +13,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_layout_init 0x0c08 0x0c2b diff --git a/tcl/interface/ftdi/redbee-usb.cfg b/tcl/interface/ftdi/redbee-usb.cfg index b79300d53..52ab93e02 100644 --- a/tcl/interface/ftdi/redbee-usb.cfg +++ b/tcl/interface/ftdi/redbee-usb.cfg @@ -13,7 +13,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_channel 1 diff --git a/tcl/interface/ftdi/sheevaplug.cfg b/tcl/interface/ftdi/sheevaplug.cfg index 625aad398..d4ec72e66 100644 --- a/tcl/interface/ftdi/sheevaplug.cfg +++ b/tcl/interface/ftdi/sheevaplug.cfg @@ -4,7 +4,7 @@ # http://www.marvell.com/products/embedded_processors/developer/kirkwood/sheevaplug.jsp # -interface ftdi +adapter driver ftdi ftdi_device_desc "SheevaPlug JTAGKey FT2232D B" ftdi_vid_pid 0x9e88 0x9e8f ftdi_channel 0 diff --git a/tcl/interface/ftdi/signalyzer-lite.cfg b/tcl/interface/ftdi/signalyzer-lite.cfg index 4988a3bfd..477842005 100644 --- a/tcl/interface/ftdi/signalyzer-lite.cfg +++ b/tcl/interface/ftdi/signalyzer-lite.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Signalyzer LITE" ftdi_vid_pid 0x0403 0xbca1 diff --git a/tcl/interface/ftdi/signalyzer.cfg b/tcl/interface/ftdi/signalyzer.cfg index e2629beec..243929835 100644 --- a/tcl/interface/ftdi/signalyzer.cfg +++ b/tcl/interface/ftdi/signalyzer.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on code in ft223 echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Signalyzer" ftdi_vid_pid 0x0403 0xbca0 diff --git a/tcl/interface/ftdi/stm32-stick.cfg b/tcl/interface/ftdi/stm32-stick.cfg index 2aff1fe8f..7ae02bd80 100644 --- a/tcl/interface/ftdi/stm32-stick.cfg +++ b/tcl/interface/ftdi/stm32-stick.cfg @@ -4,7 +4,7 @@ # http://www.hitex.com/index.php?id=340 # -interface ftdi +adapter driver ftdi ftdi_device_desc "STM32-PerformanceStick" ftdi_vid_pid 0x0640 0x002d diff --git a/tcl/interface/ftdi/ti-icdi.cfg b/tcl/interface/ftdi/ti-icdi.cfg index 6af809cd9..55085eaee 100644 --- a/tcl/interface/ftdi/ti-icdi.cfg +++ b/tcl/interface/ftdi/ti-icdi.cfg @@ -6,7 +6,7 @@ # support) but the USB IDs are different. # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0451 0xc32a ftdi_layout_init 0x00a8 0x00eb diff --git a/tcl/interface/ftdi/tumpa-lite.cfg b/tcl/interface/ftdi/tumpa-lite.cfg index 657515a91..7f576e91d 100644 --- a/tcl/interface/ftdi/tumpa-lite.cfg +++ b/tcl/interface/ftdi/tumpa-lite.cfg @@ -4,7 +4,7 @@ # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-lite-jtag-spi-i2c-serial.html # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x8a99 ftdi_layout_init 0x0038 0x087b diff --git a/tcl/interface/ftdi/tumpa.cfg b/tcl/interface/ftdi/tumpa.cfg index e4b59b118..1a4e3cdfa 100644 --- a/tcl/interface/ftdi/tumpa.cfg +++ b/tcl/interface/ftdi/tumpa.cfg @@ -4,7 +4,7 @@ # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0x8a98 0x0403 0x6010 ftdi_layout_init 0x0038 0x087b diff --git a/tcl/interface/ftdi/turtelizer2-revB.cfg b/tcl/interface/ftdi/turtelizer2-revB.cfg index 45840402a..34ae86129 100644 --- a/tcl/interface/ftdi/turtelizer2-revB.cfg +++ b/tcl/interface/ftdi/turtelizer2-revB.cfg @@ -9,7 +9,7 @@ echo "This file was not tested with real interface, it is based on schematics an echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "Turtelizer JTAG/RS232 Adapter" ftdi_vid_pid 0x0403 0xbdc8 diff --git a/tcl/interface/ftdi/turtelizer2-revC.cfg b/tcl/interface/ftdi/turtelizer2-revC.cfg index 918ac497b..f5192fb31 100644 --- a/tcl/interface/ftdi/turtelizer2-revC.cfg +++ b/tcl/interface/ftdi/turtelizer2-revC.cfg @@ -4,7 +4,7 @@ # http://www.ethernut.de/en/hardware/turtelizer/index.html # -interface ftdi +adapter driver ftdi ftdi_device_desc "Turtelizer JTAG/RS232 Adapter" ftdi_vid_pid 0x0403 0xbdc8 diff --git a/tcl/interface/ftdi/um232h.cfg b/tcl/interface/ftdi/um232h.cfg index 6ba6f43b2..2dabbec4a 100644 --- a/tcl/interface/ftdi/um232h.cfg +++ b/tcl/interface/ftdi/um232h.cfg @@ -7,7 +7,7 @@ # Note that UM232H and UM232H-B are 3.3V only. # -interface ftdi +adapter driver ftdi #ftdi_device_desc "UM232H" ftdi_vid_pid 0x0403 0x6014 diff --git a/tcl/interface/ftdi/vpaclink.cfg b/tcl/interface/ftdi/vpaclink.cfg index 205761964..ed4895a6b 100644 --- a/tcl/interface/ftdi/vpaclink.cfg +++ b/tcl/interface/ftdi/vpaclink.cfg @@ -10,7 +10,7 @@ echo "interface uses the same layout as configs that were verified. Please repor echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." -interface ftdi +adapter driver ftdi ftdi_device_desc "VPACLink" ftdi_vid_pid 0x0403 0x6010 diff --git a/tcl/interface/ftdi/xds100v2.cfg b/tcl/interface/ftdi/xds100v2.cfg index 2628aa086..860a7585d 100644 --- a/tcl/interface/ftdi/xds100v2.cfg +++ b/tcl/interface/ftdi/xds100v2.cfg @@ -7,7 +7,7 @@ # to the registered TI users. # -interface ftdi +adapter driver ftdi ftdi_vid_pid 0x0403 0xa6d0 0x0403 0x6010 ftdi_layout_init 0x0038 0x597b diff --git a/tcl/interface/imx-native.cfg b/tcl/interface/imx-native.cfg index c2f80eb59..9e1f38d03 100644 --- a/tcl/interface/imx-native.cfg +++ b/tcl/interface/imx-native.cfg @@ -7,7 +7,7 @@ # # -interface imx_gpio +adapter driver imx_gpio # For most IMX processors 0x0209c000 imx_gpio_peripheral_base 0x0209c000 @@ -32,4 +32,4 @@ imx_gpio_swd_nums 1 6 # reset_config srst_only srst_push_pull # or if you have both connected, -# reset_config trst_and_srst srst_push_pull \ No newline at end of file +# reset_config trst_and_srst srst_push_pull diff --git a/tcl/interface/jlink.cfg b/tcl/interface/jlink.cfg index a4f9dddd7..51f420b7f 100644 --- a/tcl/interface/jlink.cfg +++ b/tcl/interface/jlink.cfg @@ -4,7 +4,7 @@ # http://www.segger.com/jlink.html # -interface jlink +adapter driver jlink # The serial number can be used to select a specific device in case more than # one is connected to the host. diff --git a/tcl/interface/jtag_vpi.cfg b/tcl/interface/jtag_vpi.cfg index a37a11ed0..e665a6331 100644 --- a/tcl/interface/jtag_vpi.cfg +++ b/tcl/interface/jtag_vpi.cfg @@ -1,4 +1,4 @@ -interface jtag_vpi +adapter driver jtag_vpi # Set the VPI JTAG server port if { [info exists VPI_PORT] } { diff --git a/tcl/interface/kitprog.cfg b/tcl/interface/kitprog.cfg index 94497147f..29fce489b 100644 --- a/tcl/interface/kitprog.cfg +++ b/tcl/interface/kitprog.cfg @@ -6,7 +6,7 @@ # interface driver or switch the KitProg to KitProg mode. # -interface kitprog +adapter driver kitprog # Optionally specify the serial number of the KitProg you want to use. #kitprog_serial 1926402735485200 diff --git a/tcl/interface/nds32-aice.cfg b/tcl/interface/nds32-aice.cfg index 5363b4c1d..3b21025b5 100644 --- a/tcl/interface/nds32-aice.cfg +++ b/tcl/interface/nds32-aice.cfg @@ -4,12 +4,12 @@ # http://www.andestech.com # -interface aice +adapter driver aice aice desc "Andes AICE adapter" aice serial "C001-42163" aice vid_pid 0x1CFC 0x0000 aice port aice_usb reset_config trst_and_srst -adapter_khz 24000 +adapter speed 24000 aice retry_times 50 aice count_to_check_dbger 30 diff --git a/tcl/interface/opendous.cfg b/tcl/interface/opendous.cfg index 21ced6fbe..23fddc69c 100644 --- a/tcl/interface/opendous.cfg +++ b/tcl/interface/opendous.cfg @@ -4,4 +4,4 @@ # http://code.google.com/p/opendous-jtag/ # -interface opendous +adapter driver opendous diff --git a/tcl/interface/openjtag.cfg b/tcl/interface/openjtag.cfg index b20c22b6c..9a5827b14 100644 --- a/tcl/interface/openjtag.cfg +++ b/tcl/interface/openjtag.cfg @@ -4,5 +4,5 @@ # www.openjtag.org # -interface openjtag -openjtag_device_desc "Open JTAG Project" \ No newline at end of file +adapter driver openjtag +openjtag_device_desc "Open JTAG Project" diff --git a/tcl/interface/osbdm.cfg b/tcl/interface/osbdm.cfg index e88ce50b5..6e88c0736 100644 --- a/tcl/interface/osbdm.cfg +++ b/tcl/interface/osbdm.cfg @@ -3,5 +3,5 @@ # # http://pemicro.com/osbdm/ # -interface osbdm +adapter driver osbdm reset_config srst_only diff --git a/tcl/interface/parport.cfg b/tcl/interface/parport.cfg index ae3f8f158..4c0b260b9 100644 --- a/tcl/interface/parport.cfg +++ b/tcl/interface/parport.cfg @@ -14,6 +14,6 @@ if { [info exists PARPORTADDR] } { } } -interface parport +adapter driver parport parport_port $_PARPORTADDR parport_cable wiggler diff --git a/tcl/interface/parport_dlc5.cfg b/tcl/interface/parport_dlc5.cfg index 98345808e..e9beaaf41 100644 --- a/tcl/interface/parport_dlc5.cfg +++ b/tcl/interface/parport_dlc5.cfg @@ -10,7 +10,6 @@ if { [info exists PARPORTADDR] } { set _PARPORTADDR 0 } -interface parport +adapter driver parport parport_port $_PARPORTADDR parport_cable dlc5 - diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg index c63dfdbc7..2d0547f31 100644 --- a/tcl/interface/raspberrypi-native.cfg +++ b/tcl/interface/raspberrypi-native.cfg @@ -8,7 +8,7 @@ # Do not forget the GND connection, pin 6 of the expansion header. # -interface bcm2835gpio +adapter driver bcm2835gpio bcm2835gpio_peripheral_base 0x20000000 diff --git a/tcl/interface/raspberrypi2-native.cfg b/tcl/interface/raspberrypi2-native.cfg index 26a31c55e..e53b0f3b0 100644 --- a/tcl/interface/raspberrypi2-native.cfg +++ b/tcl/interface/raspberrypi2-native.cfg @@ -8,7 +8,7 @@ # Do not forget the GND connection, pin 6 of the expansion header. # -interface bcm2835gpio +adapter driver bcm2835gpio bcm2835gpio_peripheral_base 0x3F000000 diff --git a/tcl/interface/rlink.cfg b/tcl/interface/rlink.cfg index 2f13cc489..29d3ce599 100644 --- a/tcl/interface/rlink.cfg +++ b/tcl/interface/rlink.cfg @@ -4,5 +4,4 @@ # http://www.mcu-raisonance.com/~rlink-debugger-programmer__microcontrollers__tool~tool__T018:4cn9ziz4bnx6.html # -interface rlink - +adapter driver rlink diff --git a/tcl/interface/rshim.cfg b/tcl/interface/rshim.cfg new file mode 100644 index 000000000..accabf534 --- /dev/null +++ b/tcl/interface/rshim.cfg @@ -0,0 +1,6 @@ +# +# BlueField SoC in-circuit debugger/programmer +# + +adapter driver rshim +transport select dapdirect_swd diff --git a/tcl/interface/stlink-dap.cfg b/tcl/interface/stlink-dap.cfg new file mode 100644 index 000000000..ac4de18f9 --- /dev/null +++ b/tcl/interface/stlink-dap.cfg @@ -0,0 +1,20 @@ +# +# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit +# debugger/programmer +# +# This new interface driver creates a ST-Link wrapper for ARM-DAP named "dapdirect" +# Old ST-LINK/V1 and ST-LINK/V2 pre version V2J24 don't support "dapdirect" +# +# SWIM transport is natively supported +# + +adapter driver st-link +st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 + +# transport select dapdirect_jtag +# transport select dapdirect_swd +# transport select swim + +# Optionally specify the serial number of usb device +# e.g. +# st-link serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg index 735ad5a4e..54cd63eb6 100644 --- a/tcl/interface/stlink.cfg +++ b/tcl/interface/stlink.cfg @@ -3,7 +3,7 @@ # debugger/programmer # -interface hla +adapter driver hla hla_layout stlink hla_device_desc "ST-LINK" hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 @@ -14,4 +14,3 @@ hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374 # number reset issues. # eg. #hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" - diff --git a/tcl/interface/sysfsgpio-raspberrypi.cfg b/tcl/interface/sysfsgpio-raspberrypi.cfg index 9f5b87c38..ebb150219 100644 --- a/tcl/interface/sysfsgpio-raspberrypi.cfg +++ b/tcl/interface/sysfsgpio-raspberrypi.cfg @@ -8,7 +8,7 @@ # Do not forget the GND connection, pin 6 of the expansion header. # -interface sysfsgpio +adapter driver sysfsgpio # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg index 0fc3a9b67..9b46b437c 100644 --- a/tcl/interface/ti-icdi.cfg +++ b/tcl/interface/ti-icdi.cfg @@ -7,7 +7,7 @@ # http://www.ti.com/tool/ek-lm4f232 # -interface hla +adapter driver hla hla_layout ti-icdi hla_vid_pid 0x1cbe 0x00fd diff --git a/tcl/interface/ulink.cfg b/tcl/interface/ulink.cfg index 3b1fad071..164b990a1 100644 --- a/tcl/interface/ulink.cfg +++ b/tcl/interface/ulink.cfg @@ -5,4 +5,4 @@ # http://article.gmane.org/gmane.comp.debugging.openocd.devel/17362 # -interface ulink +adapter driver ulink diff --git a/tcl/interface/usb-jtag.cfg b/tcl/interface/usb-jtag.cfg index cb4d29bbc..8617c78c3 100644 --- a/tcl/interface/usb-jtag.cfg +++ b/tcl/interface/usb-jtag.cfg @@ -29,7 +29,7 @@ # level driver. Loading firmware is currently only supported on the ublast2 # driver but ixo-usb-jtag requires the ftdi driver. -interface usb_blaster +adapter driver usb_blaster usb_blaster_vid_pid 0x16C0 0x06AD usb_blaster_device_desc "Van Ooijen Technische Informatica" # ixo-usb-jtag is only compatible with the ublast1 protocol implemented via the diff --git a/tcl/interface/usbprog.cfg b/tcl/interface/usbprog.cfg index b4f0da328..f65c1d473 100644 --- a/tcl/interface/usbprog.cfg +++ b/tcl/interface/usbprog.cfg @@ -4,7 +4,7 @@ # http://embedded-projects.net/index.php?page_id=135 # -interface usbprog +adapter driver usbprog # USBprog is broken w/short TMS sequences, this is a workaround # until the C code can be fixed. tms_sequence long diff --git a/tcl/interface/vsllink.cfg b/tcl/interface/vsllink.cfg index fad793490..d40dbb429 100644 --- a/tcl/interface/vsllink.cfg +++ b/tcl/interface/vsllink.cfg @@ -4,5 +4,4 @@ # http://www.versaloon.com/ # -interface vsllink - +adapter driver vsllink diff --git a/tcl/interface/xds110.cfg b/tcl/interface/xds110.cfg index 495e20258..edc438d3b 100644 --- a/tcl/interface/xds110.cfg +++ b/tcl/interface/xds110.cfg @@ -5,7 +5,7 @@ # http://processors.wiki.ti.com/index.php/Emulation_Software_Package#XDS110_Support_Utilities # -interface xds110 +adapter driver xds110 # Use serial number option to use a specific XDS110 # when more than one are connected to the host. diff --git a/tcl/memory.tcl b/tcl/memory.tcl index 83c96d6c9..3066c1113 100644 --- a/tcl/memory.tcl +++ b/tcl/memory.tcl @@ -58,7 +58,7 @@ set ACCESS_WIDTH_ANY [expr $ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_3 set UNKNOWN(0,ACCESS_WIDTH) $ACCESS_WIDTH_NONE proc iswithin { ADDRESS BASE LEN } { - return [expr ((($ADDRESS - $BASE) > 0) && (($ADDRESS - $BASE + $LEN) > 0))] + return [expr ((($ADDRESS - $BASE) >= 0) && (($BASE + $LEN - $ADDRESS) > 0))] } proc address_info { ADDRESS } { diff --git a/tcl/mmr_helpers.tcl b/tcl/mmr_helpers.tcl index ce116e459..e6b1c6704 100644 --- a/tcl/mmr_helpers.tcl +++ b/tcl/mmr_helpers.tcl @@ -28,7 +28,7 @@ proc show_mmr32_reg { NAME } { } -# Give: NAMES - an array of names accessable +# Give: NAMES - an array of names accessible # in the callers symbol-scope. # VAL - the bits to display. diff --git a/tcl/target/1986Be1T.cfg b/tcl/target/1986Be1T.cfg index ecb3f8ae1..b7c9d6331 100644 --- a/tcl/target/1986Be1T.cfg +++ b/tcl/target/1986Be1T.cfg @@ -50,9 +50,9 @@ if { [info exists IMEMORY] && [string equal $IMEMORY true] } { } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/K1879x61R.cfg b/tcl/target/K1879x61R.cfg index 7d8c11358..0a8467f49 100644 --- a/tcl/target/K1879x61R.cfg +++ b/tcl/target/K1879x61R.cfg @@ -1,7 +1,7 @@ # СБИС К1879ХБ1Я # http://www.module.ru/catalog/micro/mikroshema_dekodera_cifrovogo_televizionnogo_signala_sbis_k1879hb1ya/ -adapter_khz 1000 +adapter speed 1000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/adsp-sc58x.cfg b/tcl/target/adsp-sc58x.cfg index 8c9ef1240..6073bb212 100644 --- a/tcl/target/adsp-sc58x.cfg +++ b/tcl/target/adsp-sc58x.cfg @@ -50,4 +50,3 @@ proc sc58x_enabledebug {} { # it is not possible to halt the target unless these bits have been set ap0.mem mww 0x31131000 0xFFFF } - diff --git a/tcl/target/aduc702x.cfg b/tcl/target/aduc702x.cfg index fca0a7f96..9c756be3f 100644 --- a/tcl/target/aduc702x.cfg +++ b/tcl/target/aduc702x.cfg @@ -17,7 +17,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x3f0f0f0f } -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 ## JTAG scan chain diff --git a/tcl/target/aducm360.cfg b/tcl/target/aducm360.cfg old mode 100755 new mode 100644 index ca4bc68de..b381728f1 --- a/tcl/target/aducm360.cfg +++ b/tcl/target/aducm360.cfg @@ -10,7 +10,7 @@ if { [info exists CHIPNAME] } { set _CHIPNAME aducm360 } -# Endianess +# Endianness if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { @@ -36,7 +36,7 @@ swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPU dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # SWD/JTAG speed -adapter_khz 1000 +adapter speed 1000 ## ## Target configuration @@ -51,6 +51,6 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME aducm360 0x00 0 0 0 $_TARGETNAME -adapter_nsrst_delay 100 +adapter srst delay 100 cortex_m reset_config sysresetreq diff --git a/tcl/target/allwinner_v3s.cfg b/tcl/target/allwinner_v3s.cfg index 32fd18872..d8d78bdc7 100644 --- a/tcl/target/allwinner_v3s.cfg +++ b/tcl/target/allwinner_v3s.cfg @@ -34,7 +34,7 @@ # 0220ms JTAG pins switched to SD mode # # The time frame of 20ms can be not enough to init and halt the CPU. In this -# case I would recommend to set: "adapter_khz 15000" +# case I would recommend to set: "adapter speed 15000" # To get more or less precise timings, the board should provide reset pin, # or some bench power supply with remote function. In my case I used # EEZ H24005 with this command to power on and halt the target: diff --git a/tcl/target/altera_fpgasoc.cfg b/tcl/target/altera_fpgasoc.cfg index 9a83b5ccb..0fc8d6735 100644 --- a/tcl/target/altera_fpgasoc.cfg +++ b/tcl/target/altera_fpgasoc.cfg @@ -36,7 +36,7 @@ jtag newtap $_CHIPNAME.fpga tap -irlen 10 -ircapture 0x01 -irmask 0x3 -expected- # core 1 - 0x80112000 # Slow speed to be sure it will work -adapter_khz 1000 +adapter speed 1000 set _TARGETNAME1 $_CHIPNAME.cpu.0 set _TARGETNAME2 $_CHIPNAME.cpu.1 @@ -46,7 +46,7 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80110000 -$_TARGETNAME1 configure -event reset-start { adapter_khz 1000 } +$_TARGETNAME1 configure -event reset-start { adapter speed 1000 } $_TARGETNAME1 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME1" @@ -54,7 +54,7 @@ $_TARGETNAME1 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME1" #target create $_TARGETNAME2 cortex_a -dap $_CHIPNAME.dap \ # -coreid 1 -dbgbase 0x80112000 -#$_TARGETNAME2 configure -event reset-start { adapter_khz 1000 } +#$_TARGETNAME2 configure -event reset-start { adapter speed 1000 } #$_TARGETNAME2 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME2" proc cycv_dbginit {target} { diff --git a/tcl/target/amdm37x.cfg b/tcl/target/amdm37x.cfg index 5c4e3151d..3db24b458 100644 --- a/tcl/target/amdm37x.cfg +++ b/tcl/target/amdm37x.cfg @@ -45,7 +45,7 @@ if { [info exists CHIPTYPE] } { # Run the adapter at the fastest acceptable speed with the slowest possible # core clock. -adapter_khz 10 +adapter speed 10 ############################################################################### # JTAG setup @@ -157,7 +157,7 @@ $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 # slowest possible core clock (16.8MHz/2 = 8.4MHz). It is OK to speed up # *after* PLL and clock tree setup. -$_TARGETNAME configure -event "reset-start" { adapter_khz 10 } +$_TARGETNAME configure -event "reset-start" { adapter speed 10 } # Describe the reset assert process for openocd - this is asserted with the # ICEPick @@ -176,7 +176,7 @@ $_TARGETNAME configure -event reset-assert-post { global _TARGETNAME amdm37x_dbginit $_TARGETNAME - adapter_khz 1000 + adapter speed 1000 } $_TARGETNAME configure -event gdb-attach { @@ -209,4 +209,3 @@ proc amdm37x_dbginit {target} { # at this address and this bit. $target mww phys 0x5401d030 0x00002000 } - diff --git a/tcl/target/ar71xx.cfg b/tcl/target/ar71xx.cfg index 196b04868..57833f418 100644 --- a/tcl/target/ar71xx.cfg +++ b/tcl/target/ar71xx.cfg @@ -1,7 +1,7 @@ # Atheros AR71xx MIPS 24Kc SoC. # tested on PB44 refererence board -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst @@ -54,4 +54,3 @@ $_TARGETNAME configure -work-area-phys 0xa0600000 -work-area-size 0x20000 # serial SPI capable flash # flash bank - diff --git a/tcl/target/armada370.cfg b/tcl/target/armada370.cfg index 5b84637a2..3b4be9f08 100644 --- a/tcl/target/armada370.cfg +++ b/tcl/target/armada370.cfg @@ -31,4 +31,3 @@ $_TARGETNAME configure -event reset-assert-post "armada370_dbginit $_TARGETNAME" # We need to init now, so we can run the apsel command. init dap apsel 1 - diff --git a/tcl/target/at91rm9200.cfg b/tcl/target/at91rm9200.cfg index 2e8c1e091..3d9a8d9b5 100644 --- a/tcl/target/at91rm9200.cfg +++ b/tcl/target/at91rm9200.cfg @@ -28,7 +28,7 @@ if { $_CPUTAPID == 0x15b0203f } { echo "- ERROR: -" echo "- ERROR: In one position (0x05b0203f) it selects the -" echo "- ERROR: ARM CPU, in the other position (0x1b0203f) -" - echo "- ERROR: it selects boundry-scan not the ARM -" + echo "- ERROR: it selects boundary-scan not the ARM -" echo "- ERROR: -" echo "-------------------------------------------------------" } diff --git a/tcl/target/at91sam3XXX.cfg b/tcl/target/at91sam3XXX.cfg index e7dec4b3e..7d01ccdb0 100644 --- a/tcl/target/at91sam3XXX.cfg +++ b/tcl/target/at91sam3XXX.cfg @@ -74,9 +74,9 @@ $_TARGETNAME configure -event gdb-flash-erase-start { # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. -adapter_khz 500 +adapter speed 500 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/at91sam3ax_8x.cfg b/tcl/target/at91sam3ax_8x.cfg index e2493837d..2bb66fbc4 100644 --- a/tcl/target/at91sam3ax_8x.cfg +++ b/tcl/target/at91sam3ax_8x.cfg @@ -7,5 +7,3 @@ flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 512K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x0000C0000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3ax_xx.cfg b/tcl/target/at91sam3ax_xx.cfg index e56177122..5e01d665d 100644 --- a/tcl/target/at91sam3ax_xx.cfg +++ b/tcl/target/at91sam3ax_xx.cfg @@ -8,4 +8,3 @@ # at91sam3X8E # at91sam3X8H source [find target/at91sam3XXX.cfg] - diff --git a/tcl/target/at91sam3u1c.cfg b/tcl/target/at91sam3u1c.cfg index 47c227b26..dc5c82c07 100644 --- a/tcl/target/at91sam3u1c.cfg +++ b/tcl/target/at91sam3u1c.cfg @@ -4,5 +4,3 @@ source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3u1e.cfg b/tcl/target/at91sam3u1e.cfg index 47c227b26..dc5c82c07 100644 --- a/tcl/target/at91sam3u1e.cfg +++ b/tcl/target/at91sam3u1e.cfg @@ -4,5 +4,3 @@ source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3u2c.cfg b/tcl/target/at91sam3u2c.cfg index 47c227b26..dc5c82c07 100644 --- a/tcl/target/at91sam3u2c.cfg +++ b/tcl/target/at91sam3u2c.cfg @@ -4,5 +4,3 @@ source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3u2e.cfg b/tcl/target/at91sam3u2e.cfg index 47c227b26..dc5c82c07 100644 --- a/tcl/target/at91sam3u2e.cfg +++ b/tcl/target/at91sam3u2e.cfg @@ -4,5 +4,3 @@ source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3u4c.cfg b/tcl/target/at91sam3u4c.cfg index 5cacbcbef..14af008b6 100644 --- a/tcl/target/at91sam3u4c.cfg +++ b/tcl/target/at91sam3u4c.cfg @@ -7,5 +7,3 @@ flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip, it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x000100000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3u4e.cfg b/tcl/target/at91sam3u4e.cfg index a48f99265..fbe2dd94b 100644 --- a/tcl/target/at91sam3u4e.cfg +++ b/tcl/target/at91sam3u4e.cfg @@ -7,5 +7,3 @@ flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x000100000 0 1 1 $_TARGETNAME - - diff --git a/tcl/target/at91sam3uxx.cfg b/tcl/target/at91sam3uxx.cfg index b42ae19cf..5b1748ba4 100644 --- a/tcl/target/at91sam3uxx.cfg +++ b/tcl/target/at91sam3uxx.cfg @@ -8,4 +8,3 @@ # at91sam3u1c source [find target/at91sam3XXX.cfg] - diff --git a/tcl/target/at91sam4XXX.cfg b/tcl/target/at91sam4XXX.cfg index ff7367040..ebb7eed3e 100644 --- a/tcl/target/at91sam4XXX.cfg +++ b/tcl/target/at91sam4XXX.cfg @@ -50,9 +50,9 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. -adapter_khz 500 +adapter speed 500 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/at91sam4lXX.cfg b/tcl/target/at91sam4lXX.cfg index 4aee7d081..b73babcbb 100644 --- a/tcl/target/at91sam4lXX.cfg +++ b/tcl/target/at91sam4lXX.cfg @@ -21,7 +21,7 @@ reset_config srst_gates_jtag # Datasheet does not specify SYSCLK to JTAG/SWD clock ratio. # Usually used SYSCLK/6 is hell slow, testing shows that debugging can work @ SYSCLK/2 # but your mileage may vary. -adapter_khz 50 +adapter speed 50 # System RC oscillator RCSYS starts in 3 cycles -adapter_nsrst_delay 0 +adapter srst delay 0 diff --git a/tcl/target/at91sam7se512.cfg b/tcl/target/at91sam7se512.cfg index ab0970128..61b47816b 100644 --- a/tcl/target/at91sam7se512.cfg +++ b/tcl/target/at91sam7se512.cfg @@ -36,4 +36,3 @@ $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-a #flash bank [ ] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 - diff --git a/tcl/target/at91sam9.cfg b/tcl/target/at91sam9.cfg index bf99fb2fa..e0ea31617 100644 --- a/tcl/target/at91sam9.cfg +++ b/tcl/target/at91sam9.cfg @@ -24,10 +24,10 @@ reset_config trst_and_srst separate trst_push_pull srst_open_drain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -adapter_nsrst_delay 300 +adapter srst delay 300 jtag_ntrst_delay 200 -adapter_khz 3 +adapter speed 3 ###################### # Target configuration diff --git a/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg b/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg index 9ab740904..3e4b7d76b 100644 --- a/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg +++ b/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg @@ -6,15 +6,15 @@ source [find target/at91sam9261.cfg] reset_config trst_and_srst -adapter_khz 4 +adapter speed 4 -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 scan_chain $_TARGETNAME configure -event reset-start { # at reset chip runs at 32khz - adapter_khz 8 + adapter speed 8 } $_TARGETNAME configure -event reset-init {at91sam_init} @@ -46,7 +46,7 @@ proc at91sam_init { } { sleep 10 ;# wait 10 ms # Now run at anything fast... ie: 10mhz! - adapter_khz 10000 ;# Increase JTAG Speed to 6 MHz + adapter speed 10000 ;# Increase JTAG Speed to 6 MHz mww 0xffffec00 0x0a0a0a0a ;# SMC_SETUP0 : Setup SMC for Intel NOR Flash JS28F128P30T85 128MBit mww 0xffffec04 0x0b0b0b0b ;# SMC_PULSE0 diff --git a/tcl/target/at91sam9g20.cfg b/tcl/target/at91sam9g20.cfg index 3f5e3c626..6e45df20a 100644 --- a/tcl/target/at91sam9g20.cfg +++ b/tcl/target/at91sam9g20.cfg @@ -12,7 +12,7 @@ source [find target/at91sam9.cfg] # Set fallback clock to 1/6 of worst-case clock speed (which would be the 32.768 kHz slow clock). -adapter_khz 5 +adapter speed 5 # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G20 has two SRAM areas, one starting at 0x00200000 and the other starting at 0x00300000. diff --git a/tcl/target/at91samdXX.cfg b/tcl/target/at91samdXX.cfg index f0644d177..9a396fa13 100644 --- a/tcl/target/at91samdXX.cfg +++ b/tcl/target/at91samdXX.cfg @@ -66,12 +66,12 @@ reset_config srst_gates_jtag # This limit is most probably imposed by incorrectly handled SWD WAIT # on some SWD adapters. -adapter_khz 400 +adapter speed 400 # Atmel's EDBG (on-board cmsis-dap adapter of Xplained kits) works # without problem at maximal clock speed. Atmel recommends # adapter speed less than 10 * CPU clock. -# adapter_khz 5000 +# adapter speed 5000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to diff --git a/tcl/target/atheros_ar9331.cfg b/tcl/target/atheros_ar9331.cfg index bea37ed3c..6ab238c88 100644 --- a/tcl/target/atheros_ar9331.cfg +++ b/tcl/target/atheros_ar9331.cfg @@ -41,12 +41,12 @@ reset_config none srst_pulls_trst # For SRST based variant we still need proper timings. # For ETH part the reset should be asserted at least for 10ms # Since there is no other information let's take 100ms to be sure. -adapter_nsrst_assert_width 100 +adapter srst pulse_width 100 # according to the SoC documentation it should take at least 5ms from # reset end till bootstrap end. In the practice we need 8ms to get JTAG back # to live. -adapter_nsrst_delay 8 +adapter srst delay 8 if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME diff --git a/tcl/target/atmega128.cfg b/tcl/target/atmega128.cfg index b8f7d0175..07161d572 100644 --- a/tcl/target/atmega128.cfg +++ b/tcl/target/atmega128.cfg @@ -4,10 +4,10 @@ set _ENDIAN little # jtag speed -adapter_khz 4500 +adapter speed 4500 reset_config srst_only -adapter_nsrst_delay 100 +adapter srst delay 100 #jtag scan chain if { [info exists CPUTAPID] } { @@ -27,7 +27,7 @@ flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME #to use it, script will be like: #init -#adapter_khz 4500 +#adapter speed 4500 #reset init #verify_ircapture disable # diff --git a/tcl/target/atmega128rfa1.cfg b/tcl/target/atmega128rfa1.cfg index 2c12a6109..cda439d77 100644 --- a/tcl/target/atmega128rfa1.cfg +++ b/tcl/target/atmega128rfa1.cfg @@ -2,7 +2,7 @@ set _CHIPNAME avr set _ENDIAN little # jtag speed -adapter_khz 4500 +adapter speed 4500 # avr jtag docs never connect RSTN reset_config none diff --git a/tcl/target/atsame5x.cfg b/tcl/target/atsame5x.cfg index 61949cf5a..351a2ca2c 100644 --- a/tcl/target/atsame5x.cfg +++ b/tcl/target/atsame5x.cfg @@ -63,7 +63,7 @@ reset_config srst_gates_jtag # Atmel's EDBG (on-board cmsis-dap adapter of Xplained kits) works # without problem at clock speed over 5000 khz. Atmel recommends # adapter speed less than 10 * CPU clock. -adapter_khz 2000 +adapter speed 2000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index 43962de31..fdd835473 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -39,7 +39,7 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -adapter_khz 1800 +adapter speed 1800 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to @@ -57,4 +57,3 @@ if {![using_hla]} { set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME - diff --git a/tcl/target/avr32.cfg b/tcl/target/avr32.cfg index f5ee1a486..8295f5e68 100644 --- a/tcl/target/avr32.cfg +++ b/tcl/target/avr32.cfg @@ -3,7 +3,7 @@ set _ENDIAN big set _CPUTAPID 0x21e8203f -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate @@ -14,4 +14,3 @@ jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_CP set _TARGETNAME [format "%s.cpu" $_CHIPNAME] target create $_TARGETNAME avr32_ap7k -endian $_ENDIAN -chain-position $_TARGETNAME - diff --git a/tcl/target/bcm6348.cfg b/tcl/target/bcm6348.cfg index 2540b51af..a9be55913 100644 --- a/tcl/target/bcm6348.cfg +++ b/tcl/target/bcm6348.cfg @@ -1,7 +1,7 @@ set _CHIPNAME bcm6348 set _CPUID 0x0634817f -adapter_khz 1000 +adapter speed 1000 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID diff --git a/tcl/target/bluefield.cfg b/tcl/target/bluefield.cfg new file mode 100644 index 000000000..b31dfe8d6 --- /dev/null +++ b/tcl/target/bluefield.cfg @@ -0,0 +1,78 @@ +# BlueField SoC Target + +set _CHIPNAME bluefield + +# Specify the target device +#rshim device /dev/rshim0/rshim + +# Main DAP +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +adapter speed 1500 + +swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# Initialize the target name and command variable. +set _TARGETNAME $_CHIPNAME.cpu +set _smp_command "" + +# CTI relative address +set $_TARGETNAME.cti(0) 0xC4020000 +set $_TARGETNAME.cti(1) 0xC4120000 +set $_TARGETNAME.cti(2) 0xC8020000 +set $_TARGETNAME.cti(3) 0xC8120000 +set $_TARGETNAME.cti(4) 0xCC020000 +set $_TARGETNAME.cti(5) 0xCC120000 +set $_TARGETNAME.cti(6) 0xD0020000 +set $_TARGETNAME.cti(7) 0xD0120000 +set $_TARGETNAME.cti(8) 0xD4020000 +set $_TARGETNAME.cti(9) 0xD4120000 +set $_TARGETNAME.cti(10) 0xD8020000 +set $_TARGETNAME.cti(11) 0xD8120000 +set $_TARGETNAME.cti(12) 0xDC020000 +set $_TARGETNAME.cti(13) 0xDC120000 +set $_TARGETNAME.cti(14) 0xE0020000 +set $_TARGETNAME.cti(15) 0xE0120000 + +# Create debug targets for a number of cores starting from core '_core_start'. +# Adjust the numbers according to board configuration. +set _core_start 0 +set _cores 16 + +# Create each core +for { set _core $_core_start } { $_core < $_core_start + $_cores } { incr _core 1 } { + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + + set _command "target create ${_TARGETNAME}$_core aarch64 \ + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" + + if { $_core != $_core_start } { + set _smp_command "$_smp_command ${_TARGETNAME}$_core" + } else { + set _smp_command "target smp ${_TARGETNAME}$_core" + } + + eval $_command +} + +# Configure SMP +if { $_cores > 1 } { + eval $_smp_command +} + +# Make sure the default target is the boot core +targets ${_TARGETNAME}0 + +proc core_up { args } { + global _TARGETNAME + + # Examine remaining cores + foreach _core [set args] { + ${_TARGETNAME}$_core arp_examine + } +} diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg index b0dd61ae9..a9d321ee6 100644 --- a/tcl/target/bluenrg-x.cfg +++ b/tcl/target/bluenrg-x.cfg @@ -1,8 +1,9 @@ # -# bluenrg-1/2 devices support only SWD transports. +# bluenrg-1/2 and bluenrg-lp devices support only SWD transports. # source [find target/swj-dp.tcl] +source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -20,15 +21,9 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x5F00 } -adapter_khz 4000 +adapter speed 4000 -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x0bb11477 -} - -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swj_newdap $_CHIPNAME cpu -expected-id 0x0bb11477 -expected-id 0x0bc11477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu @@ -53,22 +48,27 @@ if {![using_hla]} { } $_TARGETNAME configure -event halted { - global WDOG_VALUE - global WDOG_VALUE_SET - # Stop watchdog during halt, if enabled - mem2array value 32 0x40700008 1 - set WDOG_VALUE [expr ($value(0))] - if [expr ($value(0) & (1 << 1))] { - set WDOG_VALUE_SET 1 - mww 0x40700008 [expr ($value(0) & 0xFFFFFFFD)] - } + global WDOG_VALUE + global WDOG_VALUE_SET + set _JTAG_IDCODE [mrw 0x40000004] + if {$_JTAG_IDCODE != 0x0201E041} { + # Stop watchdog during halt, if enabled. Only Bluenrg-1/2 + set WDOG_VALUE [mrw 0x40700008] + if [expr ($WDOG_VALUE & (1 << 1))] { + set WDOG_VALUE_SET 1 + mww 0x40700008 [expr ($WDOG_VALUE & 0xFFFFFFFD)] + } + } } $_TARGETNAME configure -event resumed { - global WDOG_VALUE - global WDOG_VALUE_SET - if [expr $WDOG_VALUE_SET] { - # Restore watchdog enable value after resume - mww 0x40700008 $WDOG_VALUE - set WDOG_VALUE_SET 0 - } + global WDOG_VALUE + global WDOG_VALUE_SET + set _JTAG_IDCODE [mrw 0x40000004] + if {$_JTAG_IDCODE != 0x0201E041} { + if [expr $WDOG_VALUE_SET] { + # Restore watchdog enable value after resume. Only Bluenrg-1/2 + mww 0x40700008 $WDOG_VALUE + set WDOG_VALUE_SET 0 + } + } } diff --git a/tcl/target/c100.cfg b/tcl/target/c100.cfg index 1eaa8fe8a..5b4354e90 100644 --- a/tcl/target/c100.cfg +++ b/tcl/target/c100.cfg @@ -3,7 +3,7 @@ # this script only configures one core (that is used to run Linux) # assume no PLL lock, start slowly -adapter_khz 100 +adapter speed 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/c100config.tcl b/tcl/target/c100config.tcl index 52efa83c2..53b2c5d48 100644 --- a/tcl/target/c100config.tcl +++ b/tcl/target/c100config.tcl @@ -1,5 +1,5 @@ -# board(-config) specfic parameters file. +# board(-config) specific parameters file. # set CFG_REFCLKFREQ [configC100 CFG_REFCLKFREQ] proc config {label} { @@ -409,4 +409,4 @@ proc flashUBOOT {file} { putsUART0 "done.\n" putsUART0 "Rebooting, please wait!\n" reboot -} \ No newline at end of file +} diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl index c9124cbc6..725ba709c 100644 --- a/tcl/target/c100helper.tcl +++ b/tcl/target/c100helper.tcl @@ -15,7 +15,7 @@ proc helpC100 {} { echo "12) ooma_board_detect: will show which version of Telo you have" echo "13) setupDDR2: will configure DDR2 controller, you must have PLLs configureg" echo "14) showDDR2: will show DDR2 config registers" - echo "15) showWatchdog: will show current regster config for watchdog" + echo "15) showWatchdog: will show current register config for watchdog" echo "16) reboot: will trigger watchdog and reboot Telo (hw reset)" echo "17) bootNOR: will boot Telo from NOR" echo "18) setupUART0: will configure UART0 for 115200 8N1, PLLs have to be confiured" @@ -176,7 +176,7 @@ proc setupAmbaClk {} { mmw $CLKCORE_AHB_CLK_CNTRL 0x0 0xFFFFFF mmw $CLKCORE_AHB_CLK_CNTRL [expr (($x << 16) + ($w << 8) + $y)] 0x0 # wait for PLL to lock - echo "Wating for Amba PLL to lock" + echo "Waiting for Amba PLL to lock" while {[expr [mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK] == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $AHB_PLL_BY_CTRL @@ -250,7 +250,7 @@ proc setupArmClk {} { mmw $CLKCORE_ARM_CLK_CNTRL 0x0 0xFFFFFF mmw $CLKCORE_ARM_CLK_CNTRL [expr (($x << 16) + ($w << 8) + $y)] 0x0 # wait for PLL to lock - echo "Wating for Amba PLL to lock" + echo "Waiting for Amba PLL to lock" while {[expr [mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK] == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $ARM_PLL_BY_CTRL @@ -300,7 +300,7 @@ proc setupDDR2 {} { # Memory setup register mww $MEMORY_MAX_ADDR [expr ($ddr_size - 1) + $MEMORY_BASE_ADDR] - # disbale ROM remap + # disable ROM remap mww $MEMORY_CR 0x0 # Take DDR controller out of reset mmw $BLOCK_RESET_REG $DDR_RST 0x0 @@ -486,15 +486,15 @@ proc reboot {} { set TIMER_WDT_CURRENT_COUNT [regs TIMER_WDT_CURRENT_COUNT] # allow the counter to count to high value before triggering - # this is because regsiter writes are slow over JTAG and + # this is because register writes are slow over JTAG and # I don't want to miss the high_bound==curr_count condition mww $TIMER_WDT_HIGH_BOUND 0xffffff mww $TIMER_WDT_CURRENT_COUNT 0x0 echo "JTAG speed lowered to 100kHz" - adapter_khz 100 + adapter speed 100 mww $TIMER_WDT_CONTROL 0x1 # wait until the reset - echo -n "Wating for watchdog to trigger..." + echo -n "Waiting for watchdog to trigger..." #while {[mrw $TIMER_WDT_CONTROL] == 1} { # echo [format "TIMER_WDT_CURRENT_COUNT (0x%x): 0x%x" $TIMER_WDT_CURRENT_COUNT [mrw $TIMER_WDT_CURRENT_COUNT]] # sleep 1 diff --git a/tcl/target/cc2538.cfg b/tcl/target/cc2538.cfg old mode 100755 new mode 100644 index 63fd9c267..8d232f41f --- a/tcl/target/cc2538.cfg +++ b/tcl/target/cc2538.cfg @@ -1,7 +1,7 @@ # Config for Texas Instruments low power RF SoC CC2538 # http://www.ti.com/lit/pdf/swru319 -adapter_khz 100 +adapter speed 100 source [find target/icepick.cfg] source [find target/ti-cjtag.cfg] diff --git a/tcl/target/cs351x.cfg b/tcl/target/cs351x.cfg index cb05da2cf..8fabda67f 100644 --- a/tcl/target/cs351x.cfg +++ b/tcl/target/cs351x.cfg @@ -28,4 +28,3 @@ target create $_TARGETNAME fa526 -endian $_ENDIAN -chain-position $_TARGETNAME # This chip has a DCC ... use it arm7_9 dcc_downloads enable - diff --git a/tcl/target/dragonite.cfg b/tcl/target/dragonite.cfg index 750fd6437..b9d73a285 100644 --- a/tcl/target/dragonite.cfg +++ b/tcl/target/dragonite.cfg @@ -26,6 +26,5 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dragonite -endian $_ENDIAN -chain-position $_TARGETNAME reset_config trst_and_srst -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 - diff --git a/tcl/target/dsp56321.cfg b/tcl/target/dsp56321.cfg index 6f3222373..78ecb3bd2 100644 --- a/tcl/target/dsp56321.cfg +++ b/tcl/target/dsp56321.cfg @@ -1,13 +1,13 @@ # Script for freescale DSP56321 # -if { [info exists CHIPNAME] } { +if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp56321 } -if { [info exists ENDIAN] } { +if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian @@ -21,7 +21,7 @@ if { [info exists CPUTAPID] } { } #jtag speed -adapter_khz 4500 +adapter speed 4500 #has only srst reset_config srst_only diff --git a/tcl/target/dsp568013.cfg b/tcl/target/dsp568013.cfg index 0c491fa95..67d44192e 100644 --- a/tcl/target/dsp568013.cfg +++ b/tcl/target/dsp568013.cfg @@ -1,12 +1,12 @@ # Script for freescale DSP568013 -if { [info exists CHIPNAME] } { +if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp568013 } -if { [info exists ENDIAN] } { +if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian @@ -20,7 +20,7 @@ if { [info exists CPUTAPID] } { } #jtag speed -adapter_khz 800 +adapter speed 800 reset_config srst_only @@ -35,7 +35,7 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp5680xx -endian $_ENDIAN -chain-position $_TARGETNAME # Setup the interesting tap -# Disable polling to be able to get idcode from core tap. If re enabled, can be re enabled, but it should be disabled to correctly unlock flash (operations requiere certain instruction to be in the IR register during reset, and polling would change this) +# Disable polling to be able to get idcode from core tap. If re enabled, can be re enabled, but it should be disabled to correctly unlock flash (operations require certain instruction to be in the IR register during reset, and polling would change this) jtag configure $_CHIPNAME.chp -event setup " jtag tapenable $_TARGETNAME poll off @@ -73,4 +73,3 @@ $_TARGETNAME configure -work-area-virt 0 #setup flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME dsp5680xx_flash 0 0 2 1 $_TARGETNAME - diff --git a/tcl/target/dsp568037.cfg b/tcl/target/dsp568037.cfg index 01194d002..fc57bd435 100644 --- a/tcl/target/dsp568037.cfg +++ b/tcl/target/dsp568037.cfg @@ -20,7 +20,7 @@ if { [info exists CPUTAPID] } { } #jtag speed -adapter_khz 800 +adapter speed 800 reset_config srst_only @@ -69,4 +69,3 @@ $_TARGETNAME configure -work-area-virt 0 #setup flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME dsp5680xx_flash 0 0 2 1 $_TARGETNAME - diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index e22ce5cba..c789efc72 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -34,7 +34,7 @@ if { [info exists CPUTAPID] } { swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -adapter_khz 1000 +adapter speed 1000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/epc9301.cfg b/tcl/target/epc9301.cfg index f186d37dc..252bbab11 100644 --- a/tcl/target/epc9301.cfg +++ b/tcl/target/epc9301.cfg @@ -20,7 +20,7 @@ if { [info exists CPUTAPID] } { } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/esi32xx.cfg b/tcl/target/esi32xx.cfg index d32af39bd..6be84ab07 100644 --- a/tcl/target/esi32xx.cfg +++ b/tcl/target/esi32xx.cfg @@ -26,7 +26,7 @@ if { [info exists CACHEARCH] } { $_TARGETNAME esirisc cache_arch $CACHEARCH } -adapter_khz 2000 +adapter speed 2000 reset_config none diff --git a/tcl/target/feroceon.cfg b/tcl/target/feroceon.cfg index 389576e55..d4f710e00 100644 --- a/tcl/target/feroceon.cfg +++ b/tcl/target/feroceon.cfg @@ -26,6 +26,5 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME feroceon -endian $_ENDIAN -chain-position $_TARGETNAME reset_config trst_and_srst -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 - diff --git a/tcl/target/fm3.cfg b/tcl/target/fm3.cfg index a0610ce17..544cff9d6 100644 --- a/tcl/target/fm3.cfg +++ b/tcl/target/fm3.cfg @@ -22,7 +22,7 @@ if { [info exists CPUTAPID] } { } # delays on reset lines -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -36,16 +36,16 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -# MB9BF506 has 64kB of SRAM on its main system bus +# MB9BF506 has 64kB of SRAM on its main system bus $_TARGETNAME configure -work-area-phys 0x1FFF8000 -work-area-size 0x10000 -work-area-backup 0 -# MB9BF506 has 512kB internal FLASH +# MB9BF506 has 512kB internal FLASH set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME # 4MHz / 6 = 666kHz, so use 500 -adapter_khz 500 +adapter speed 500 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to diff --git a/tcl/target/fm4.cfg b/tcl/target/fm4.cfg index b79634d96..bfe7115ca 100644 --- a/tcl/target/fm4.cfg +++ b/tcl/target/fm4.cfg @@ -24,7 +24,7 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap -adapter_khz 500 +adapter speed 500 if {![using_hla]} { cortex_m reset_config sysresetreq diff --git a/tcl/target/gp326xxxa.cfg b/tcl/target/gp326xxxa.cfg index feb7554b7..df42c4485 100644 --- a/tcl/target/gp326xxxa.cfg +++ b/tcl/target/gp326xxxa.cfg @@ -33,11 +33,11 @@ $_TARGETNAME configure -work-area-phys 0xf8000000 -work-area-size 0x8000 -work-a reset_config trst_and_srst srst_pulls_trst # This delay is needed otherwise communication with the target would # be unreliable -adapter_nsrst_delay 100 +adapter srst delay 100 # Set the adapter speed ridiculously low just in case we are # running off of a 32kHz clock -adapter_khz 2 +adapter speed 2 proc gp32xxxa_halt_and_reset_control_registers {} { # System control registers @@ -57,7 +57,7 @@ proc gp32xxxa_halt_and_reset_control_registers {} { # Set the adapter speed ridiculously low just in case we are # running off of a 32kHz clock - adapter_khz 2 + adapter speed 2 # Disable any advanced features at this stage arm7_9 dcc_downloads disable @@ -86,7 +86,7 @@ proc gp32xxxa_halt_and_reset_control_registers {} { # Now that we know that we are running at 48Mhz # Increase JTAG speed and enable speed optimization features - adapter_khz 5000 + adapter speed 5000 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable } diff --git a/tcl/target/hilscher_netx10.cfg b/tcl/target/hilscher_netx10.cfg index 3f96607c6..668de8fee 100644 --- a/tcl/target/hilscher_netx10.cfg +++ b/tcl/target/hilscher_netx10.cfg @@ -28,4 +28,3 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CP # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME - diff --git a/tcl/target/icepick.cfg b/tcl/target/icepick.cfg index a945bea8a..d1250711b 100644 --- a/tcl/target/icepick.cfg +++ b/tcl/target/icepick.cfg @@ -75,9 +75,22 @@ proc icepick_c_setup {jrc} { } # jrc == TAP name for the ICEpick -# port == a port number, 0..15 +# port == a port number, 0..15 for debug tap, 16..31 for test tap proc icepick_c_tapenable {jrc port} { + if { ($port >= 0) && ($port < 16) } { + # Debug tap" + set tap $port + set block 0x2 + } elseif { $port < 32 } { + # Test tap + set tap [expr ($port - 16)] + set block 0x1 + } else { + echo "ERROR: Invalid ICEPick C port number: $port" + return + } + # First CONNECT to the ICEPick # echo "Connecting to ICEPick" icepick_c_connect $jrc @@ -90,18 +103,18 @@ proc icepick_c_tapenable {jrc port} { # And never to enter RESET, which will disable the TAPs. # first enable power and clock for TAP - icepick_c_router $jrc 1 0x2 $port 0x110048 + icepick_c_router $jrc 1 $block $tap 0x110048 # TRM states that the register should be read back here, skipped for now # enable debug "default" mode - icepick_c_router $jrc 1 0x2 $port 0x112048 + icepick_c_router $jrc 1 $block $tap 0x112048 # TRM states that debug enable and debug mode should be read back and # confirmed - skipped for now # Finally select the tap - icepick_c_router $jrc 1 0x2 $port 0x112148 + icepick_c_router $jrc 1 $block $tap 0x112148 # Enter the bypass state irscan $jrc [CONST IR_BYPASS] -endstate RUN/IDLE @@ -119,6 +132,7 @@ proc icepick_d_set_core_control {jrc coreid value } { # Follow the sequence described in # http://processors.wiki.ti.com/images/f/f6/Router_Scan_Sequence-ICEpick-D.pdf proc icepick_d_tapenable {jrc port coreid { value 0x2008 } } { + # First CONNECT to the ICEPick icepick_c_connect $jrc icepick_c_setup $jrc @@ -140,4 +154,3 @@ proc icepick_c_wreset {jrc} { # send a router write, block is 0, register is 1, value is 0x2100 icepick_c_router $jrc 1 0x0 0x1 0x002101 } - diff --git a/tcl/target/imx.cfg b/tcl/target/imx.cfg index 9eea53eef..ccfddb6f7 100644 --- a/tcl/target/imx.cfg +++ b/tcl/target/imx.cfg @@ -6,7 +6,7 @@ set TARGETNAME $_TARGETNAME # rewrite commands of the form below to arm11 mcr... # Data.Set c15:0x042f %long 0x40000015 proc setc15 {regs value} { - global TARGETNAME + global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] diff --git a/tcl/target/imx28.cfg b/tcl/target/imx28.cfg index 4cc3950be..1fea3fa37 100644 --- a/tcl/target/imx28.cfg +++ b/tcl/target/imx28.cfg @@ -4,7 +4,7 @@ reset_config trst_and_srst #jtag nTRST and nSRST delay -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 if { [info exists CHIPNAME] } { diff --git a/tcl/target/imx31.cfg b/tcl/target/imx31.cfg index ca639515f..d850657da 100644 --- a/tcl/target/imx31.cfg +++ b/tcl/target/imx31.cfg @@ -3,7 +3,7 @@ reset_config trst_and_srst srst_gates_jtag -adapter_nsrst_delay 5 +adapter srst delay 5 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/imx6.cfg b/tcl/target/imx6.cfg index f359346d7..29453346a 100644 --- a/tcl/target/imx6.cfg +++ b/tcl/target/imx6.cfg @@ -75,7 +75,7 @@ proc imx6_dbginit {target} { } # Slow speed to be sure it will work -adapter_khz 1000 -$_TARGETNAME configure -event reset-start { adapter_khz 1000 } +adapter speed 1000 +$_TARGETNAME configure -event reset-start { adapter speed 1000 } $_TARGETNAME configure -event reset-assert-post "imx6_dbginit $_TARGETNAME" diff --git a/tcl/target/infineon/tle987x.cfg b/tcl/target/infineon/tle987x.cfg new file mode 100644 index 000000000..84cc2380b --- /dev/null +++ b/tcl/target/infineon/tle987x.cfg @@ -0,0 +1,36 @@ +# +# Infineon TLE987x family (Arm Cortex-M3 @ up to 40 MHz) +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME tle987x +} + +source [find target/swj-dp.tcl] + +if { [info exists CPU_SWD_TAPID] } { + set _CPU_SWD_TAPID $CPU_SWD_TAPID +} else { + set _CPU_SWD_TAPID 0x2BA01477 +} + +if { [using_jtag] } { + # JTAG not supported, only SWD + set _CPU_TAPID 0 +} else { + set _CPU_TAPID $_CPU_SWD_TAPID +} + +swj_newdap $_CHIPNAME dap -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +if { ![using_hla] } { + cortex_m reset_config sysresetreq +} + +adapter speed 1000 diff --git a/tcl/target/is5114.cfg b/tcl/target/is5114.cfg index 31f1aa1aa..1a06b091f 100644 --- a/tcl/target/is5114.cfg +++ b/tcl/target/is5114.cfg @@ -23,7 +23,7 @@ if { [info exists CPUTAPID] } { } # jtag speed. We need to stick to 16kHz until we've finished reset. -adapter_khz 16 +adapter speed 16 reset_config trst_and_srst @@ -38,9 +38,9 @@ jtag newtap $_CHIPNAME unknown2 -irlen 5 -ircapture 1 -irmask 1 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME -$_TARGETNAME configure -event reset-start { adapter_khz 16 } +$_TARGETNAME configure -event reset-start { adapter speed 16 } $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. - adapter_khz 3000 + adapter speed 3000 } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 1 diff --git a/tcl/target/ixp42x.cfg b/tcl/target/ixp42x.cfg index d7b5bf470..624fe29da 100644 --- a/tcl/target/ixp42x.cfg +++ b/tcl/target/ixp42x.cfg @@ -66,8 +66,8 @@ set IXP42x_SDRAM_256MB_32Mx16_2BANK 0x0015 # helper function to init SDRAM on IXP42x. # SDRAM_CFG: one of IXP42X_SDRAM_xxx -# REFRESH: refresh counter reload value (integer) -# CASLAT: 2 or 3 +# REFRESH: refresh counter reload value (integer) +# CASLAT: 2 or 3 proc ixp42x_init_sdram { SDRAM_CFG REFRESH CASLAT } { switch $CASLAT { @@ -104,4 +104,3 @@ proc ixp42x_init_sdram { SDRAM_CFG REFRESH CASLAT } { proc ixp42x_set_bigendian { } { reg XSCALE_CTRL 0xF8 } - diff --git a/tcl/target/k1921vk01t.cfg b/tcl/target/k1921vk01t.cfg old mode 100755 new mode 100644 index 1a8402106..926f3c726 --- a/tcl/target/k1921vk01t.cfg +++ b/tcl/target/k1921vk01t.cfg @@ -40,9 +40,9 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE flash bank $_CHIPNAME.flash niietcm4 0 0 0 0 $_TARGETNAME -adapter_khz 2000 +adapter speed 2000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/ke0x.cfg b/tcl/target/ke0x.cfg index 8239400d0..b92721f4c 100644 --- a/tcl/target/ke0x.cfg +++ b/tcl/target/ke0x.cfg @@ -35,7 +35,7 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME -adapter_khz 1000 +adapter speed 1000 reset_config srst_nogate diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index 5d9286a69..84f6535e3 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -40,7 +40,7 @@ kinetis create_banks # Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual # specifies up to 1MHz for VLPR mode and up to 24MHz for run mode; # Table 17 of Sub-Family Data Sheet rev4 lists 25MHz as the maximum frequency. -adapter_khz 1000 +adapter speed 1000 reset_config srst_nogate @@ -56,9 +56,9 @@ if {[using_hla]} { echo " it without mass erase. Don't set write protection on the first block." echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo "" -} { - # Detect secured MCU or boot lock-up in RESET/WDOG loop - $_CHIPNAME.cpu configure -event examine-start { +} else { + # Detect secured MCU + $_TARGETNAME configure -event examine-fail { kinetis mdm check_security } diff --git a/tcl/target/ks869x.cfg b/tcl/target/ks869x.cfg index 0f6829c91..78cc402b4 100644 --- a/tcl/target/ks869x.cfg +++ b/tcl/target/ks869x.cfg @@ -18,7 +18,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x00922f0f } -adapter_khz 6000 +adapter speed 6000 # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index 73ee62a79..9fda4edf4 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -41,7 +41,7 @@ set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME kinetis create_banks -adapter_khz 1000 +adapter speed 1000 reset_config srst_nogate @@ -58,9 +58,13 @@ if {[using_hla]} { echo " it without mass erase. Don't set write protection on the first block." echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo "" -} { +} else { # Detect secured MCU or boot lock-up in RESET/WDOG loop - $_CHIPNAME.cpu configure -event examine-start { + $_TARGETNAME configure -event examine-fail { + kinetis mdm check_security + } + # During RESET/WDOG loop the target is sometimes falsely examined + $_TARGETNAME configure -event examine-end { kinetis mdm check_security } @@ -75,4 +79,3 @@ if {[using_hla]} { $_TARGETNAME configure -event reset-init { kinetis disable_wdog } - diff --git a/tcl/target/lpc1850.cfg b/tcl/target/lpc1850.cfg index 925a0498d..481dc8aaf 100644 --- a/tcl/target/lpc1850.cfg +++ b/tcl/target/lpc1850.cfg @@ -1,6 +1,6 @@ source [find target/swj-dp.tcl] -adapter_khz 500 +adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/lpc1xxx.cfg b/tcl/target/lpc1xxx.cfg index 1969e464f..946d1ce16 100644 --- a/tcl/target/lpc1xxx.cfg +++ b/tcl/target/lpc1xxx.cfg @@ -145,10 +145,10 @@ if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "l # Run with *real slow* clock by default since the # boot rom could have been playing with the PLL, so # we have no idea what clock the target is running at. -adapter_khz 10 +adapter speed 10 # delays on reset lines -adapter_nsrst_delay 200 +adapter srst delay 200 if {[using_jtag]} { jtag_ntrst_delay 200 } diff --git a/tcl/target/lpc2103.cfg b/tcl/target/lpc2103.cfg index f55777f56..131b9ef89 100644 --- a/tcl/target/lpc2103.cfg +++ b/tcl/target/lpc2103.cfg @@ -15,7 +15,7 @@ proc setup_lpc2103 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2103 setup_lpc2103 12000 1500 } diff --git a/tcl/target/lpc2124.cfg b/tcl/target/lpc2124.cfg index 02517381a..ddbde22a5 100644 --- a/tcl/target/lpc2124.cfg +++ b/tcl/target/lpc2124.cfg @@ -15,7 +15,7 @@ proc setup_lpc2124 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2124 setup_lpc2124 12000 1500 } diff --git a/tcl/target/lpc2129.cfg b/tcl/target/lpc2129.cfg index 2c33cde31..a1c3fe7bb 100644 --- a/tcl/target/lpc2129.cfg +++ b/tcl/target/lpc2129.cfg @@ -15,7 +15,7 @@ proc setup_lpc2129 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2129 setup_lpc2129 12000 1500 } diff --git a/tcl/target/lpc2148.cfg b/tcl/target/lpc2148.cfg index f3a2011a8..503a68264 100644 --- a/tcl/target/lpc2148.cfg +++ b/tcl/target/lpc2148.cfg @@ -15,7 +15,7 @@ proc setup_lpc2148 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2148 setup_lpc2148 12000 1500 } diff --git a/tcl/target/lpc2294.cfg b/tcl/target/lpc2294.cfg index 83d595deb..1320cda3e 100644 --- a/tcl/target/lpc2294.cfg +++ b/tcl/target/lpc2294.cfg @@ -9,7 +9,7 @@ source [find target/lpc2xxx.cfg] proc setup_lpc2294 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx - + # !! TAPID unknown !! setup_lpc2xxx lpc2294 0xffffffff 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } @@ -17,7 +17,7 @@ proc setup_lpc2294 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2294 setup_lpc2294 12000 1500 } diff --git a/tcl/target/lpc2378.cfg b/tcl/target/lpc2378.cfg index 0b66b8255..235456a07 100644 --- a/tcl/target/lpc2378.cfg +++ b/tcl/target/lpc2378.cfg @@ -15,7 +15,7 @@ proc setup_lpc2378 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2378 setup_lpc2378 4000 500 } diff --git a/tcl/target/lpc2460.cfg b/tcl/target/lpc2460.cfg index 69fdc4aaf..c229f6dd6 100644 --- a/tcl/target/lpc2460.cfg +++ b/tcl/target/lpc2460.cfg @@ -15,7 +15,7 @@ proc setup_lpc2460 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2460 setup_lpc2460 4000 500 } diff --git a/tcl/target/lpc2478.cfg b/tcl/target/lpc2478.cfg index 48e5bdf3f..36b5c4693 100644 --- a/tcl/target/lpc2478.cfg +++ b/tcl/target/lpc2478.cfg @@ -15,7 +15,7 @@ proc setup_lpc2478 {core_freq_khz adapter_freq_khz} { proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." - + # setup_lpc2478 setup_lpc2478 4000 500 } diff --git a/tcl/target/lpc2900.cfg b/tcl/target/lpc2900.cfg index 53677873a..523bc211f 100644 --- a/tcl/target/lpc2900.cfg +++ b/tcl/target/lpc2900.cfg @@ -14,7 +14,7 @@ if { [info exists CPUTAPID] } { if { [info exists HAS_ETB] } { } else { # Set default (no ETB). - # Show a warning, because this should have been configured explicitely. + # Show a warning, because this should have been configured explicitly. set HAS_ETB 0 # TODO: warning? } diff --git a/tcl/target/lpc2xxx.cfg b/tcl/target/lpc2xxx.cfg index 11f1c48bc..f947c1b05 100644 --- a/tcl/target/lpc2xxx.cfg +++ b/tcl/target/lpc2xxx.cfg @@ -13,10 +13,10 @@ proc setup_lpc2xxx {chip_name cputapids flash_size flash_variant workarea_size c reset_config trst_and_srst # reset delays - adapter_nsrst_delay 100 + adapter srst delay 100 jtag_ntrst_delay 100 - adapter_khz $adapter_freq_khz + adapter speed $adapter_freq_khz foreach i $cputapids { append expected_ids "-expected-id " $i " " @@ -40,5 +40,5 @@ proc setup_lpc2xxx {chip_name cputapids flash_size flash_variant workarea_size c proc init_targets {} { # FIX!!! read out CPUTAPID here and choose right setup. In addition to the # CPUTAPID some querying of the target would be required. - return -error "This is a generic LPC2xxx configuration file, use a specific target file." + return -error "This is a generic LPC2xxx configuration file, use a specific target file." } diff --git a/tcl/target/lpc3131.cfg b/tcl/target/lpc3131.cfg index 27c1f6757..89bbf0265 100644 --- a/tcl/target/lpc3131.cfg +++ b/tcl/target/lpc3131.cfg @@ -22,7 +22,7 @@ if { [info exists CPUTAPID] } { } # Scan Tap -# Wired to seperate STDO pin on the lpc3131, externally muxed to TDO on ea3131 module +# Wired to separate STDO pin on the lpc3131, externally muxed to TDO on ea3131 module # JTAGSEL pin must be 0 to activate, which reassigns arm tdo to a pass through. if { [info exists SJCTAPID] } { set _SJCTAPID $SJCTAPID @@ -52,11 +52,11 @@ dict set lpc313x wdt 0x13002400 # Target configuration ################################################################## -adapter_nsrst_delay 1000 +adapter srst delay 1000 jtag_ntrst_delay 0 set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME invoke-event halted diff --git a/tcl/target/lpc4350.cfg b/tcl/target/lpc4350.cfg index 2b728840e..0c6d0ffdf 100644 --- a/tcl/target/lpc4350.cfg +++ b/tcl/target/lpc4350.cfg @@ -1,6 +1,6 @@ source [find target/swj-dp.tcl] -adapter_khz 500 +adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/lpc4370.cfg b/tcl/target/lpc4370.cfg index 1374ef275..9db2b9e92 100644 --- a/tcl/target/lpc4370.cfg +++ b/tcl/target/lpc4370.cfg @@ -2,7 +2,7 @@ # NXP LPC4370 - 1x ARM Cortex-M4 + 2x ARM Cortex-M0 @ up to 204 MHz each # -adapter_khz 500 +adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/lpc8nxx.cfg b/tcl/target/lpc8nxx.cfg index b9332909a..1bc77b20d 100644 --- a/tcl/target/lpc8nxx.cfg +++ b/tcl/target/lpc8nxx.cfg @@ -22,7 +22,7 @@ if {![using_hla]} { # If srst is not fitted use SYSRESETREQ to perform a soft reset cortex_m reset_config sysresetreq } -adapter_nsrst_delay 100 +adapter srst delay 100 $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size 0x1ff0 -work-area-backup 0 diff --git a/tcl/target/ls1012a.cfg b/tcl/target/ls1012a.cfg index 9a9e684d7..19d3e5838 100644 --- a/tcl/target/ls1012a.cfg +++ b/tcl/target/ls1012a.cfg @@ -32,4 +32,4 @@ target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -dbgbase 0x80410000 -cti target smp $_TARGETNAME -adapter_khz 2000 +adapter speed 2000 diff --git a/tcl/target/max32620.cfg b/tcl/target/max32620.cfg index 80cb25a47..6187bb996 100644 --- a/tcl/target/max32620.cfg +++ b/tcl/target/max32620.cfg @@ -2,7 +2,7 @@ # www.maximintegrated.com # adapter speed -adapter_khz 4000 +adapter speed 4000 # reset pin configuration reset_config srst_only diff --git a/tcl/target/max32625.cfg b/tcl/target/max32625.cfg index 7182b235f..159b36094 100644 --- a/tcl/target/max32625.cfg +++ b/tcl/target/max32625.cfg @@ -2,7 +2,7 @@ # www.maximintegrated.com # adapter speed -adapter_khz 4000 +adapter speed 4000 # reset pin configuration reset_config srst_only diff --git a/tcl/target/max3263x.cfg b/tcl/target/max3263x.cfg index f23b0b64d..fc7d11f5c 100644 --- a/tcl/target/max3263x.cfg +++ b/tcl/target/max3263x.cfg @@ -2,7 +2,7 @@ # www.maximintegrated.com # adapter speed -adapter_khz 4000 +adapter speed 4000 # reset pin configuration reset_config srst_only diff --git a/tcl/target/mc13224v.cfg b/tcl/target/mc13224v.cfg index 27ac8c3b2..f756dd963 100644 --- a/tcl/target/mc13224v.cfg +++ b/tcl/target/mc13224v.cfg @@ -35,8 +35,8 @@ reset_config srst_only jtag_ntrst_delay 200 # rclk hasn't been working well. This maybe the mc13224v or something else. -#adapter_khz 2000 -adapter_khz 2000 +#adapter speed 2000 +adapter speed 2000 ###################### # Target configuration diff --git a/tcl/target/mdr32f9q2i.cfg b/tcl/target/mdr32f9q2i.cfg index 67481024c..820d2dd45 100644 --- a/tcl/target/mdr32f9q2i.cfg +++ b/tcl/target/mdr32f9q2i.cfg @@ -49,9 +49,9 @@ if { [info exists IMEMORY] && [string equal $IMEMORY true] } { } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/nrf51.cfg b/tcl/target/nrf51.cfg index 4f2402033..d51a50e23 100644 --- a/tcl/target/nrf51.cfg +++ b/tcl/target/nrf51.cfg @@ -50,7 +50,7 @@ flash bank $_CHIPNAME.uicr nrf51 0x10001000 0 1 1 $_TARGETNAME # The chip should start up from internal 16Mhz RC, so setting adapter # clock to 1Mhz should be OK # -adapter_khz 1000 +adapter speed 1000 proc enable_all_ram {} { # nRF51822 Product Anomaly Notice (PAN) #16 explains that not all RAM banks diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index c29adbdd6..88f2c6912 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -30,13 +30,86 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap -adapter_khz 1000 +adapter speed 1000 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -if { ![using_hla] } { +if { [using_hla] } { + echo "" + echo "nRF52 device has a CTRL-AP dedicated to recover the device from AP lock." + echo "A high level adapter (like a ST-Link) you are currently using cannot access" + echo "the CTRL-AP so 'nrf52_recover' command will not work." + echo "Do not enable UICR APPROTECT." + echo "" +} else { cortex_m reset_config sysresetreq + + $_TARGETNAME configure -event examine-fail nrf52_check_ap_lock } flash bank $_CHIPNAME.flash nrf5 0x00000000 0 1 1 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME + +# Test if MEM-AP is locked by UICR APPROTECT +proc nrf52_check_ap_lock {} { + set dap [[target current] cget -dap] + set err [catch {set APPROTECTSTATUS [ocd_$dap apreg 1 0xc]}] + if {$err == 0 && $APPROTECTSTATUS != 1} { + echo "****** WARNING ******" + echo "nRF52 device has AP lock engaged (see UICR APPROTECT register)." + echo "Debug access is denied." + echo "Use 'nrf52_recover' to erase and unlock the device." + echo "" + poll off + } +} + +# Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #1) +# http://www.ebyte.com produces modules with nRF52 locked by default, +# use nrf52_recover to enable flashing and debug. +proc nrf52_recover {} { + set target [target current] + set dap [$target cget -dap] + + set IDR [ocd_$dap apreg 1 0xfc] + if {$IDR != 0x02880000} { + echo "Error: Cannot access nRF52 CTRL-AP!" + return + } + + poll off + + # Assert reset + $dap apreg 1 0 1 + + # Reset ERASEALLSTATUS event + $dap apreg 1 8 0 + + # Trigger ERASEALL task + $dap apreg 1 4 0 + $dap apreg 1 4 1 + + for {set i 0} {1} {incr i} { + set ERASEALLSTATUS [ocd_$dap apreg 1 8] + if {$ERASEALLSTATUS == 1} { + echo "$target device has been successfully erased and unlocked." + break + } + if {$i >= 5} { + echo "Error: $target recovery failed." + break + } + sleep 100 + } + + # Deassert reset + $dap apreg 1 0 0 + + if {$ERASEALLSTATUS == 1} { + sleep 100 + $target arp_examine + poll on + } +} + +add_help_text nrf52_recover "Mass erase and unlock nRF52 device" diff --git a/tcl/target/numicro.cfg b/tcl/target/numicro.cfg index c42dfbc2f..73022df47 100644 --- a/tcl/target/numicro.cfg +++ b/tcl/target/numicro.cfg @@ -48,7 +48,7 @@ set _FLASHNAME $_CHIPNAME.flash_config flash bank $_FLASHNAME numicro 0x00300000 0 0 0 $_TARGETNAME # set default SWCLK frequency -adapter_khz 1000 +adapter speed 1000 # set default srst setting "none" reset_config none diff --git a/tcl/target/omap3530.cfg b/tcl/target/omap3530.cfg index 078d7f24d..dcf7c5139 100644 --- a/tcl/target/omap3530.cfg +++ b/tcl/target/omap3530.cfg @@ -63,8 +63,8 @@ proc omap3_dbginit {target} { # be absolutely certain the JTAG clock will work with the worst-case # 16.8MHz/2 = 8.4MHz core clock, even before a bootloader kicks in. # OK to speed up *after* PLL and clock tree setup. -adapter_khz 1000 -$_TARGETNAME configure -event "reset-start" { adapter_khz 1000 } +adapter speed 1000 +$_TARGETNAME configure -event "reset-start" { adapter speed 1000 } # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. RST_GS (2) is a warm reset, like ICEpick diff --git a/tcl/target/omap5912.cfg b/tcl/target/omap5912.cfg index c4ff40e23..2f9338bc3 100644 --- a/tcl/target/omap5912.cfg +++ b/tcl/target/omap5912.cfg @@ -14,7 +14,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0692602f } -adapter_nsrst_delay 100 +adapter srst delay 100 # NOTE: presumes irlen 38 is the C55x DSP, matching BSDL for # its standalone siblings (like TMS320VC5502) of the same era diff --git a/tcl/target/omapl138.cfg b/tcl/target/omapl138.cfg index fd9ff4c2e..30cf23c9e 100644 --- a/tcl/target/omapl138.cfg +++ b/tcl/target/omapl138.cfg @@ -52,8 +52,8 @@ $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x2000 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. -adapter_khz 1500 -$_TARGETNAME configure -event "reset-start" { adapter_khz 1500 } +adapter speed 1500 +$_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable diff --git a/tcl/target/pic32mx.cfg b/tcl/target/pic32mx.cfg index d53b99a58..51a6bbddb 100644 --- a/tcl/target/pic32mx.cfg +++ b/tcl/target/pic32mx.cfg @@ -23,7 +23,7 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x4000 } -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 #jtag scan chain diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index 544e10987..b56828207 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -36,7 +36,7 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME -adapter_khz 1500 +adapter speed 1500 # Reset, bloody PSoC 4 reset # @@ -118,7 +118,7 @@ proc ocd_process_reset_inner { MODE } { } if { ! [info exists PSOC4_USE_ACQUIRE] } { - if { 0 == [string compare [adapter_name] kitprog ] } { + if { 0 == [string compare [adapter name] kitprog ] } { set PSOC4_USE_ACQUIRE 1 } else { set PSOC4_USE_ACQUIRE 0 @@ -138,7 +138,7 @@ proc ocd_process_reset_inner { MODE } { $t invoke-event reset-assert-pre if { $halt && $PSOC4_USE_ACQUIRE } { - catch { [adapter_name] acquire_psoc } + catch { [adapter name] acquire_psoc } $t arp_examine } else { if { $PSOC4_TEST_MODE_WORKAROUND } { diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg index fc0c71159..51d032b17 100644 --- a/tcl/target/psoc6.cfg +++ b/tcl/target/psoc6.cfg @@ -6,7 +6,7 @@ source [find target/swj-dp.tcl] -adapter_khz 1000 +adapter speed 1000 global _CHIPNAME if { [info exists CHIPNAME] } { diff --git a/tcl/target/pxa255.cfg b/tcl/target/pxa255.cfg index 386242597..73518bf7e 100644 --- a/tcl/target/pxa255.cfg +++ b/tcl/target/pxa255.cfg @@ -28,8 +28,8 @@ target create $_TARGETNAME xscale -endian $_ENDIAN \ # PXA255 comes out of reset using 3.6864 MHz oscillator. # Until the PLL kicks in, keep the JTAG clock slow enough # that we get no errors. -adapter_khz 300 -$_TARGETNAME configure -event "reset-start" { adapter_khz 300 } +adapter speed 300 +$_TARGETNAME configure -event "reset-start" { adapter speed 300 } # both TRST and SRST are *required* for debug # DCSR is often accessed with SRST active @@ -38,11 +38,11 @@ reset_config trst_and_srst separate srst_nogate # reset processing that works with PXA proc init_reset {mode} { # assert both resets; equivalent to power-on reset - jtag_reset 1 1 + adapter assert trst assert srst # drop TRST after at least 32 cycles sleep 1 - jtag_reset 0 1 + adapter deassert trst assert srst # minimum 32 TCK cycles to wake up the controller runtest 50 @@ -51,7 +51,7 @@ proc init_reset {mode} { jtag arp_init # ... and take it out of reset - jtag_reset 0 0 + adapter deassert trst deassert srst } proc jtag_init {} { diff --git a/tcl/target/pxa270.cfg b/tcl/target/pxa270.cfg index 95f7f16f0..bd904b5dd 100644 --- a/tcl/target/pxa270.cfg +++ b/tcl/target/pxa270.cfg @@ -34,9 +34,9 @@ if { [info exists CPUTAPID3] } { set _CPUTAPID3 0x89265013 } -# set adapter_nsrst_delay to the delay introduced by your reset circuit +# set adapter srst delay to the delay introduced by your reset circuit # the rest of the needed delays are built into the openocd program -adapter_nsrst_delay 260 +adapter srst delay 260 # set the jtag_ntrst_delay to the delay introduced by a reset circuit # the rest of the needed delays are built into the openocd program jtag_ntrst_delay 250 diff --git a/tcl/target/pxa3xx.cfg b/tcl/target/pxa3xx.cfg index c459f6eaa..1a4539ca9 100644 --- a/tcl/target/pxa3xx.cfg +++ b/tcl/target/pxa3xx.cfg @@ -59,9 +59,9 @@ if { [info exists CPUTAPID_PXA32X_C0] } { set _CPUTAPID_PXA32X_C0 0x7E642013 } -# set adapter_nsrst_delay to the delay introduced by your reset circuit +# set adapter srst delay to the delay introduced by your reset circuit # the rest of the needed delays are built into the openocd program -adapter_nsrst_delay 260 +adapter srst delay 260 # set the jtag_ntrst_delay to the delay introduced by a reset circuit # the rest of the needed delays are built into the openocd program diff --git a/tcl/target/qualcomm_qca4531.cfg b/tcl/target/qualcomm_qca4531.cfg index 3d2157852..0b046b842 100644 --- a/tcl/target/qualcomm_qca4531.cfg +++ b/tcl/target/qualcomm_qca4531.cfg @@ -38,12 +38,12 @@ reset_config none srst_pulls_trst # For SRST based variant we still need proper timings. # For ETH part the reset should be asserted at least for 10ms # Since there is no other information let's take 100ms to be sure. -adapter_nsrst_assert_width 100 +adapter srst pulse_width 100 # according to the SoC documentation it should take at least 5ms from # reset end till bootstrap end. In the practice we need 8ms to get JTAG back # to live. -adapter_nsrst_delay 8 +adapter srst delay 8 if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME diff --git a/tcl/target/readme.txt b/tcl/target/readme.txt index f028b11c7..91bb2d5f3 100644 --- a/tcl/target/readme.txt +++ b/tcl/target/readme.txt @@ -26,16 +26,15 @@ assumed that all write-protect mechanisms should be disabled. flash write_image [file] verify_image [file] -4. adapter_khz sets the maximum speed (or alternatively RCLK). If invoked +4. adapter speed sets the maximum speed (or alternatively RCLK). If invoked multiple times only the last setting is used. interface/xxx.cfg files are always executed *before* target/xxx.cfg -files, so any adapter_khz in interface/xxx.cfg will be overridden by -target/xxx.cfg. adapter_khz in interface/xxx.cfg would then, effectively, +files, so any adapter speed in interface/xxx.cfg will be overridden by +target/xxx.cfg. adapter speed in interface/xxx.cfg would then, effectively, set the default JTAG speed. Note that a target/xxx.cfg file can invoke another target/yyy.cfg file, so one can create target subtype configurations where e.g. only amount of DRAM, oscillator speeds differ and having a single config file for the default/common settings. - diff --git a/tcl/target/renesas_r7s72100.cfg b/tcl/target/renesas_r7s72100.cfg index f9466fc2f..5220b3ccb 100644 --- a/tcl/target/renesas_r7s72100.cfg +++ b/tcl/target/renesas_r7s72100.cfg @@ -1,4 +1,4 @@ -# Renesas R-Car RZ/A1H +# Renesas RZ/A1H # https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/rz/rza/rza1h.html if { [info exists DAP_TAPID] } { diff --git a/tcl/target/renesas_r8a7790.cfg b/tcl/target/renesas_r8a7790.cfg deleted file mode 100644 index a662b6b37..000000000 --- a/tcl/target/renesas_r8a7790.cfg +++ /dev/null @@ -1,36 +0,0 @@ -# Renesas R-Car H2 -# https://www.renesas.com/en-us/solutions/automotive/products/rcar-h2.html - -if { [info exists DAP_TAPID] } { - set _DAP_TAPID $DAP_TAPID -} else { - set _DAP_TAPID 0x4ba00477 -} - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME r8a7790 -} - -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID - -# Configuring only one core using DAP. -# Base addresses of Cortex A15 cores: -# core 0 - 0x800B0000 -# core 1 - 0x800B2000 -# core 2 - 0x800B4000 -# core 3 - 0x800B6000 -# Base addresses of Cortex A7 cores (not supported yet): -# core 0 - 0x800F0000 -# core 1 - 0x800F2000 -# core 2 - 0x800F4000 -# core 3 - 0x800F6000 -set _TARGETNAME $_CHIPNAME.ca15. -dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x800B0000 -target create ${_TARGETNAME}1 cortex_a -dap ${_CHIPNAME}.dap -coreid 1 -dbgbase 0x800B2000 -defer-examine -target create ${_TARGETNAME}2 cortex_a -dap ${_CHIPNAME}.dap -coreid 2 -dbgbase 0x800B4000 -defer-examine -target create ${_TARGETNAME}3 cortex_a -dap ${_CHIPNAME}.dap -coreid 3 -dbgbase 0x800B6000 -defer-examine - -targets ${_TARGETNAME}0 diff --git a/tcl/target/renesas_r8a7791.cfg b/tcl/target/renesas_r8a7791.cfg deleted file mode 100644 index f93cbb8f1..000000000 --- a/tcl/target/renesas_r8a7791.cfg +++ /dev/null @@ -1,27 +0,0 @@ -# Renesas R-Car M2 -# https://www.renesas.com/en-us/solutions/automotive/products/rcar-m2.html - -if { [info exists DAP_TAPID] } { - set _DAP_TAPID $DAP_TAPID -} else { - set _DAP_TAPID 0x4ba00477 -} - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME r8a7791 -} - -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID - -# Configuring only one core using DAP. -# Base addresses of cores: -# core 0 - 0x800B0000 -# core 1 - 0x800B2000 -set _TARGETNAME $_CHIPNAME.ca15. -dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x800B0000 -target create ${_TARGETNAME}1 cortex_a -dap ${_CHIPNAME}.dap -coreid 1 -dbgbase 0x800B2000 -defer-examine - -targets ${_TARGETNAME}0 diff --git a/tcl/target/renesas_r8a7794.cfg b/tcl/target/renesas_r8a7794.cfg deleted file mode 100644 index e3e27246c..000000000 --- a/tcl/target/renesas_r8a7794.cfg +++ /dev/null @@ -1,27 +0,0 @@ -# Renesas R-Car E2 -# https://www.renesas.com/en-us/solutions/automotive/products/rcar-e2.html - -if { [info exists DAP_TAPID] } { - set _DAP_TAPID $DAP_TAPID -} else { - set _DAP_TAPID 0x4ba00477 -} - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME r8a7794 -} - -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID - -# Configuring only one core using DAP. -# Base addresses of cores: -# core 0 - 0x800F0000 -# core 1 - 0x800F2000 -set _TARGETNAME $_CHIPNAME.ca7. -dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x800F0000 -target create ${_TARGETNAME}1 cortex_a -dap ${_CHIPNAME}.dap -coreid 1 -dbgbase 0x800F2000 -defer-examine - -targets ${_TARGETNAME}0 diff --git a/tcl/target/renesas_rcar_gen2.cfg b/tcl/target/renesas_rcar_gen2.cfg new file mode 100644 index 000000000..91baa6c90 --- /dev/null +++ b/tcl/target/renesas_rcar_gen2.cfg @@ -0,0 +1,125 @@ +# Renesas R-Car Generation 2 SOCs +# - There are a combination of Cortex-A15s and Cortex-A7s for each Gen2 SOC +# - Each SOC can boot through any of the, up to 2, core types that it has +# e.g. H2 can boot through Cortex-A15 or Cortex-A7 + +# Supported Gen2 SOCs and their cores: +# H2: Cortex-A15 x 4, Cortex-A7 x 4 +# M2: Cortex-A15 x 2 +# V2H: Cortex-A15 x 2 +# M2N: Cortex-A15 x 2 +# E2: Cortex-A7 x 2 + +# Usage: +# There are 2 configuration options: +# SOC: Selects the supported SOC. (Default 'H2') +# BOOT_CORE: Selects the booting core. 'CA15', or 'CA7' +# Defaults to 'CA15' if the SOC has one, else defaults to 'CA7' + +if { [info exists SOC] } { + set _soc $SOC +} else { + set _soc H2 +} + +# Set configuration for each SOC and the default 'BOOT_CORE' +switch $_soc { + H2 { + set _CHIPNAME r8a7790 + set _num_ca15 4 + set _num_ca7 4 + set _boot_core CA15 + } + M2 { + set _CHIPNAME r8a7791 + set _num_ca15 2 + set _num_ca7 0 + set _boot_core CA15 + } + V2H { + set _CHIPNAME r8a7792 + set _num_ca15 2 + set _num_ca7 0 + set _boot_core CA15 + } + M2N { + set _CHIPNAME r8a7793 + set _num_ca15 2 + set _num_ca7 0 + set _boot_core CA15 + } + E2 { + set _CHIPNAME r8a7794 + set _num_ca15 0 + set _num_ca7 2 + set _boot_core CA7 + } + default { + error "'$_soc' is invalid!" + } +} + +# If configured, override the default 'CHIPNAME' +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} + +# If configured, override the default 'BOOT_CORE' +if { [info exists BOOT_CORE] } { + set _boot_core $BOOT_CORE +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +echo "\t$_soc - $_num_ca15 CA15(s), $_num_ca7 CA7(s)" +echo "\tBoot Core - $_boot_core\n" + +set _DAPNAME $_CHIPNAME.dap + +# TAP and DAP +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID +dap create $_DAPNAME -chain-position $_CHIPNAME.cpu + +set CA15_DBGBASE {0x800B0000 0x800B2000 0x800B4000 0x800B6000} +set CA7_DBGBASE {0x800F0000 0x800F2000 0x800F4000 0x800F6000} + +set smp_targets "" + +proc setup_ca {core_name dbgbase num boot} { + global _CHIPNAME + global _DAPNAME + global smp_targets + for { set _core 0 } { $_core < $num } { incr _core } { + set _TARGETNAME $_CHIPNAME.$core_name.$_core + set _CTINAME $_TARGETNAME.cti + set _command "target create $_TARGETNAME cortex_a -dap $_DAPNAME \ + -coreid $_core -dbgbase [lindex $dbgbase $_core]" + if { $_core == 0 && $boot == 1 } { + set _targets "$_TARGETNAME" + } else { + set _command "$_command -defer-examine" + } + set smp_targets "$smp_targets $_TARGETNAME" + eval $_command + } +} + +# Organize target list based on the boot core +if { [string equal $_boot_core CA15] } { + setup_ca a15 $CA15_DBGBASE $_num_ca15 1 + setup_ca a7 $CA7_DBGBASE $_num_ca7 0 +} elseif { [string equal $_boot_core CA7] } { + setup_ca a7 $CA7_DBGBASE $_num_ca7 1 + setup_ca a15 $CA15_DBGBASE $_num_ca15 0 +} else { + setup_ca a15 $CA15_DBGBASE $_num_ca15 0 + setup_ca a7 $CA7_DBGBASE $_num_ca7 0 +} + +source [find target/renesas_rcar_reset_common.cfg] + +eval "target smp $smp_targets" diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg index 2c478b268..72f185d61 100644 --- a/tcl/target/renesas_rcar_gen3.cfg +++ b/tcl/target/renesas_rcar_gen3.cfg @@ -76,7 +76,7 @@ switch $_soc { set _boot_core CA53 } default { - echo "'$_soc' is invalid!" + error "'$_soc' is invalid!" } } @@ -166,4 +166,6 @@ if { [string equal $_boot_core CA57] } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 } +source [find target/renesas_rcar_reset_common.cfg] + eval "target smp $smp_targets" diff --git a/tcl/board/renesas_gen2_common.cfg b/tcl/target/renesas_rcar_reset_common.cfg similarity index 80% rename from tcl/board/renesas_gen2_common.cfg rename to tcl/target/renesas_rcar_reset_common.cfg index 00fa777c5..3e4579b91 100644 --- a/tcl/board/renesas_gen2_common.cfg +++ b/tcl/target/renesas_rcar_reset_common.cfg @@ -4,10 +4,10 @@ reset_config trst_and_srst srst_nogate proc init_reset {mode} { # Assert both resets: equivalent to a power-on reset - jtag_reset 1 1 + adapter assert trst assert srst # Deassert TRST to begin TAP communication - jtag_reset 0 1 + adapter deassert trst assert srst # TAP should now be responsive, validate the scan-chain jtag arp_init diff --git a/tcl/target/renesas_s7g2.cfg b/tcl/target/renesas_s7g2.cfg index 78fb3e82f..b4be88f61 100644 --- a/tcl/target/renesas_s7g2.cfg +++ b/tcl/target/renesas_s7g2.cfg @@ -48,4 +48,4 @@ if { ![using_hla] } { cortex_m reset_config sysresetreq } -adapter_khz 1000 +adapter speed 1000 diff --git a/tcl/target/samsung_s3c2440.cfg b/tcl/target/samsung_s3c2440.cfg index 2a0a915d6..a97659be5 100644 --- a/tcl/target/samsung_s3c2440.cfg +++ b/tcl/target/samsung_s3c2440.cfg @@ -32,4 +32,3 @@ $_TARGETNAME configure -work-area-phys 0x200000 -work-area-size 0x4000 -work-are #reset configuration reset_config trst_and_srst - diff --git a/tcl/target/samsung_s3c2450.cfg b/tcl/target/samsung_s3c2450.cfg index 1bc4f2d87..248255719 100644 --- a/tcl/target/samsung_s3c2450.cfg +++ b/tcl/target/samsung_s3c2450.cfg @@ -7,11 +7,11 @@ # # RCLK? # -# adapter_khz 0 +# adapter speed 0 # # Really low clock during reset? # -# adapter_khz 1 +# adapter speed 1 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/samsung_s3c4510.cfg b/tcl/target/samsung_s3c4510.cfg index 461d0478a..8bc5da530 100644 --- a/tcl/target/samsung_s3c4510.cfg +++ b/tcl/target/samsung_s3c4510.cfg @@ -21,4 +21,3 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CP set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME - diff --git a/tcl/target/samsung_s3c6410.cfg b/tcl/target/samsung_s3c6410.cfg index 88fe966dc..9f7c2cddf 100644 --- a/tcl/target/samsung_s3c6410.cfg +++ b/tcl/target/samsung_s3c6410.cfg @@ -40,7 +40,7 @@ jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_C set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 #reset configuration diff --git a/tcl/target/sharp_lh79532.cfg b/tcl/target/sharp_lh79532.cfg index 6f2cf2234..a464839dc 100644 --- a/tcl/target/sharp_lh79532.cfg +++ b/tcl/target/sharp_lh79532.cfg @@ -22,5 +22,3 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CP set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME - - diff --git a/tcl/target/sim3x.cfg b/tcl/target/sim3x.cfg old mode 100755 new mode 100644 index ed46a3b34..3d3fc5c3e --- a/tcl/target/sim3x.cfg +++ b/tcl/target/sim3x.cfg @@ -48,9 +48,9 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/smp8634.cfg b/tcl/target/smp8634.cfg index c13414c87..e95f633db 100644 --- a/tcl/target/smp8634.cfg +++ b/tcl/target/smp8634.cfg @@ -18,7 +18,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x08630001 } -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate diff --git a/tcl/target/snps_em_sk_fpga.cfg b/tcl/target/snps_em_sk_fpga.cfg new file mode 100644 index 000000000..2f7fecbe3 --- /dev/null +++ b/tcl/target/snps_em_sk_fpga.cfg @@ -0,0 +1,33 @@ +# Copyright (C) 2014-2015,2020 Synopsys, Inc. +# Anton Kolesov +# Didin Evgeniy +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Xilinx Spartan-6 XC6SLX45 FPGA on EM Starter Kit v1. +# Xilinx Spartan-6 XC6SLX150 FPGA on EM Starter Kit v2. +# + +source [find cpu/arc/em.tcl] + +set _CHIPNAME arc-em +set _TARGETNAME $_CHIPNAME.cpu + +# EM SK IDENTITY is 0x200444b1 +# EM SK v2 IDENTITY is 0x200044b1 +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -expected-id 0x200444b1 \ + -expected-id 0x200044b1 + +set _coreid 0 +set _dbgbase [expr 0x00000000 | ($_coreid << 13)] + +target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME \ + -coreid 0 -dbgbase $_dbgbase -endian little + +# There is no SRST, so do a software reset +$_TARGETNAME configure -event reset-assert "arc_em_reset $_TARGETNAME" + +arc_em_init_regs + +# vim:ft=tcl diff --git a/tcl/target/stellaris.cfg b/tcl/target/stellaris.cfg index 7fffd2a7c..3cab4d140 100644 --- a/tcl/target/stellaris.cfg +++ b/tcl/target/stellaris.cfg @@ -68,7 +68,7 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE # NOTE: this may be increased by a reset-init handler, after it # configures and enables the PLL. Or you might need to decrease # this, if you're using a slower clock. -adapter_khz 500 +adapter speed 500 source [find mem_helper.tcl] @@ -132,7 +132,7 @@ proc reset_peripherals {family} { } $_TARGETNAME configure -event reset-start { - adapter_khz 500 + adapter speed 500 # # When nRST is asserted on most Stellaris devices, it clears some of @@ -164,7 +164,7 @@ $_TARGETNAME configure -event reset-start { } else { if {![using_hla]} { # Tempest and Firestorm default to using NVIC VECTRESET - # peripherals will need reseting manually, see proc reset_peripherals + # peripherals will need resetting manually, see proc reset_peripherals cortex_m reset_config vectreset } # reset peripherals, based on code in diff --git a/tcl/target/stm32f0x.cfg b/tcl/target/stm32f0x.cfg index baac9b68d..b20d036cf 100644 --- a/tcl/target/stm32f0x.cfg +++ b/tcl/target/stm32f0x.cfg @@ -52,9 +52,9 @@ set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # adapter speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 reset_config srst_nogate @@ -66,7 +66,7 @@ if {![using_hla]} { proc stm32f0x_default_reset_start {} { # Reset clock is HSI (8 MHz) - adapter_khz 1000 + adapter speed 1000 } proc stm32f0x_default_examine_end {} { @@ -86,7 +86,7 @@ proc stm32f0x_default_reset_init {} { mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] # Boost JTAG frequency - adapter_khz 8000 + adapter speed 8000 } # Default hooks diff --git a/tcl/target/stm32f1x.cfg b/tcl/target/stm32f1x.cfg index 471878d7f..3e85fb217 100644 --- a/tcl/target/stm32f1x.cfg +++ b/tcl/target/stm32f1x.cfg @@ -60,9 +60,9 @@ set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/stm32f2x.cfg b/tcl/target/stm32f2x.cfg index 1e8b94ace..d790febd5 100644 --- a/tcl/target/stm32f2x.cfg +++ b/tcl/target/stm32f2x.cfg @@ -28,9 +28,9 @@ if { [info exists WORKAREASIZE] } { # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } diff --git a/tcl/target/stm32f3x.cfg b/tcl/target/stm32f3x.cfg index 86e9f594e..e3f1a34dd 100644 --- a/tcl/target/stm32f3x.cfg +++ b/tcl/target/stm32f3x.cfg @@ -28,9 +28,9 @@ if { [info exists WORKAREASIZE] } { # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. -adapter_khz 1000 +adapter speed 1000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -73,7 +73,7 @@ if {![using_hla]} { proc stm32f3x_default_reset_start {} { # Reset clock is HSI (8 MHz) - adapter_khz 1000 + adapter speed 1000 } proc stm32f3x_default_examine_end {} { @@ -93,7 +93,7 @@ proc stm32f3x_default_reset_init {} { mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] # Boost JTAG frequency - adapter_khz 8000 + adapter speed 8000 } # Default hooks diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 09ce14a5d..b95e783c5 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -58,9 +58,9 @@ flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. -adapter_khz 2000 +adapter speed 2000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -100,10 +100,10 @@ $_TARGETNAME configure -event reset-init { mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL # Boost JTAG frequency - adapter_khz 8000 + adapter speed 8000 } $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset - adapter_khz 2000 + adapter speed 2000 } diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg old mode 100755 new mode 100644 index ba1d12ffb..6ad4b65f8 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -65,9 +65,9 @@ flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME # adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz -adapter_khz 2000 +adapter speed 2000 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -162,12 +162,11 @@ $_TARGETNAME configure -event reset-init { if {[using_jtag]} { [[target current] cget -dap] memaccess 16 } { - adapter_khz 8000 + adapter speed 8000 } } $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset - adapter_khz 2000 + adapter speed 2000 } - diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg new file mode 100644 index 000000000..50836ea82 --- /dev/null +++ b/tcl/target/stm32g0x.cfg @@ -0,0 +1,88 @@ +# script for stm32g0x family + +# +# stm32g0 devices support SWD transports only. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32g0x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# Smallest proposed target has 8kB ram, use 4kB by default to avoid surprises +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # Section 37.5.5 - corresponds to Cortex-M0+ + set _CPUTAPID 0x0bc11477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +# reasonable default +adapter speed 2000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +proc stm32g0x_default_reset_start {} { + # Reset clock is HSI16 (16 MHz) + adapter speed 2000 +} + +proc stm32g0x_default_examine_end {} { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0x40015804 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0x40015808 0x00001800 0 +} + +proc stm32g0x_default_reset_init {} { + # Increase clock to 64 Mhz + mmw 0x40022000 0x00000002 0x00000005 ;# FLASH_ACR: Latency = 2 + mww 0x4002100C 0x30000802 ;# RCC_PLLCFGR = PLLR=/2, PLLN=8, PLLM=/1, PLLSRC=0x2 + mmw 0x40021000 0x01000000 0x00000000 ;# RCC_CR |= PLLON + mmw 0x40021008 0x00000002 0x00000005 ;# RCC_CFGR: SW=PLLRCLK + + # Boost JTAG frequency + adapter speed 4000 +} + +# Default hooks +$_TARGETNAME configure -event examine-end { stm32g0x_default_examine_end } +$_TARGETNAME configure -event reset-start { stm32g0x_default_reset_start } +$_TARGETNAME configure -event reset-init { stm32g0x_default_reset_init } diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg new file mode 100644 index 000000000..9f144a07e --- /dev/null +++ b/tcl/target/stm32g4x.cfg @@ -0,0 +1,103 @@ +# script for stm32g4x family + +# +# stm32g4 devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32g4x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# Smallest current target has 32kB ram, use 16kB by default to avoid surprises +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # See STM Document RM0440 + # Section 46.6.3 - corresponds to Cortex-M4 r0p1 + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} + +# reasonable default +adapter speed 2000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event reset-init { + # CPU comes out of reset with HSION | HSIRDY. + # Use HSI 16 MHz clock, compliant even with VOS == 2. + # 1 WS compliant with VOS == 2 and 16 MHz. + mmw 0x40022000 0x00000001 0x0000000E ;# FLASH_ACR: Latency = 1 + mmw 0x40021000 0x00000100 0x00000000 ;# RCC_CR |= HSION + mmw 0x40021008 0x00000001 0x00000002 ;# RCC_CFGR: SW=HSI16 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is HSI (16 MHz) + adapter speed 2000 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0042008 0x00001800 0 +} + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xE0042004 0x00000020 0 +} diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 0bfc43dfd..2d92eca92 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -12,6 +12,39 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32h7x } +if { [info exists DUAL_BANK] } { + set $_CHIPNAME.DUAL_BANK $DUAL_BANK + unset DUAL_BANK +} else { + set $_CHIPNAME.DUAL_BANK 0 +} + +if { [info exists DUAL_CORE] } { + set $_CHIPNAME.DUAL_CORE $DUAL_CORE + unset DUAL_CORE +} else { + set $_CHIPNAME.DUAL_CORE 0 +} + +# Issue a warning when hla is used, and fallback to single core configuration +if { [set $_CHIPNAME.DUAL_CORE] && [using_hla] } { + echo "Warning : hla does not support multicore debugging" + set $_CHIPNAME.DUAL_CORE 0 +} + +if { [info exists USE_CTI] } { + set $_CHIPNAME.USE_CTI $USE_CTI + unset USE_CTI +} else { + set $_CHIPNAME.USE_CTI 0 +} + +# Issue a warning when DUAL_CORE=0 and USE_CTI=1, and fallback to USE_CTI=0 +if { ![set $_CHIPNAME.DUAL_CORE] && [set $_CHIPNAME.USE_CTI] } { + echo "Warning : could not use CTI with a single core device, CTI is disabled" + set $_CHIPNAME.USE_CTI 0 +} + set _ENDIAN little # Work-area is a space in RAM used for flash programming @@ -40,18 +73,41 @@ if {[using_jtag]} { swj_newdap $_CHIPNAME bs -irlen 5 } -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap +if {![using_hla]} { + # STM32H7 provides an APB-AP at access port 2, which allows the access to + # the debug and trace features on the system APB System Debug Bus (APB-D). + target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 +} -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 +target create $_CHIPNAME.cpu0 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32h7x 0x08000000 0 0 0 $_TARGETNAME +$_CHIPNAME.cpu0 configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +flash bank $_CHIPNAME.bank1.cpu0 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu0 + +if {[set $_CHIPNAME.DUAL_BANK]} { + flash bank $_CHIPNAME.bank2.cpu0 stm32h7x 0x08100000 0 0 0 $_CHIPNAME.cpu0 +} + +if {[set $_CHIPNAME.DUAL_CORE]} { + target create $_CHIPNAME.cpu1 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 3 + + $_CHIPNAME.cpu1 configure -work-area-phys 0x38000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + + flash bank $_CHIPNAME.bank1.cpu1 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu1 + + if {[set $_CHIPNAME.DUAL_BANK]} { + flash bank $_CHIPNAME.bank2.cpu1 stm32h7x 0x08100000 0 0 0 $_CHIPNAME.cpu1 + } +} + +# Make sure that cpu0 is selected +targets $_CHIPNAME.cpu0 # Clock after reset is HSI at 64 MHz, no need of PLL -adapter_khz 1800 +adapter speed 1800 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -72,7 +128,11 @@ reset_config srst_only srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset - cortex_m reset_config sysresetreq + $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq + + if {[set $_CHIPNAME.DUAL_CORE]} { + $_CHIPNAME.cpu1 cortex_m reset_config sysresetreq + } # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 @@ -83,31 +143,133 @@ if {![using_hla]} { $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } -$_TARGETNAME configure -event examine-end { +$_CHIPNAME.cpu0 configure -event examine-end { # Enable D3 and D1 DBG clocks # DBGMCU_CR |= D3DBGCKEN | D1DBGCKEN - mmw 0x5C001004 0x00600000 0 + stm32h7x_dbgmcu_mmw 0x004 0x00600000 0 # Enable debug during low power modes (uses more power) - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP in D3 & D1 Domains - mmw 0x5C001004 0x00000187 0 + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP in D3, D2 & D1 Domains + stm32h7x_dbgmcu_mmw 0x004 0x000001BF 0 # Stop watchdog counters during halt # DBGMCU_APB3FZ1 |= WWDG1 - mmw 0x5C001034 0x00000040 0 - # DBGMCU_APB4FZ1 |= WDGLSD1 - mmw 0x5C001054 0x00040000 0 + stm32h7x_dbgmcu_mmw 0x034 0x00000040 0 + # DBGMCU_APB1LFZ1 |= WWDG2 + stm32h7x_dbgmcu_mmw 0x03C 0x00000800 0 + # DBGMCU_APB4FZ1 |= WDGLSD1 | WDGLSD2 + stm32h7x_dbgmcu_mmw 0x054 0x000C0000 0 } -$_TARGETNAME configure -event trace-config { +$_CHIPNAME.cpu0 configure -event trace-config { # Set TRACECLKEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment - mmw 0x5C001004 0x00100000 0 + stm32h7x_dbgmcu_mmw 0x004 0x00100000 0 } -$_TARGETNAME configure -event reset-init { +$_CHIPNAME.cpu0 configure -event reset-init { # Clock after reset is HSI at 64 MHz, no need of PLL - adapter_khz 4000 + adapter speed 4000 } +if {[set $_CHIPNAME.DUAL_CORE]} { + $_CHIPNAME.cpu1 configure -event examine-end { + # get _CHIPNAME from the current target + set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + global $_CHIPNAME.USE_CTI + + # Stop watchdog counters during halt + # DBGMCU_APB3FZ2 |= WWDG1 + stm32h7x_dbgmcu_mmw 0x038 0x00000040 0 + # DBGMCU_APB1LFZ2 |= WWDG2 + stm32h7x_dbgmcu_mmw 0x040 0x00000800 0 + # DBGMCU_APB4FZ2 |= WDGLSD1 | WDGLSD2 + stm32h7x_dbgmcu_mmw 0x058 0x000C0000 0 + + if {[set $_CHIPNAME.USE_CTI]} { + stm32h7x_cti_start + } + } +} + +# like mrw, but with target selection +proc stm32h7x_mrw {used_target reg} { + set value "" + $used_target mem2array value 32 $reg 1 + return $value(0) +} + +# like mmw, but with target selection +proc stm32h7x_mmw {used_target reg setbits clearbits} { + set old [stm32h7x_mrw $used_target $reg] + set new [expr ($old & ~$clearbits) | $setbits] + $used_target mww $reg $new +} + +# mmw for dbgmcu component registers, it accepts the register offset from dbgmcu base +# this procedure will use the mem_ap on AP2 whenever possible +proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { + # use $_CHIPNAME.ap2 if possible, and use the proper dbgmcu base address + if {![using_hla]} { + # get _CHIPNAME from the current target + set _CHIPNAME [regsub ".(cpu|ap)\\d*$" [target current] ""] + set used_target $_CHIPNAME.ap2 + set reg_addr [expr 0xE00E1000 + $reg_offset] + } { + set used_target [target current] + set reg_addr [expr 0x5C001000 + $reg_offset] + } + + stm32h7x_mmw $used_target $reg_addr $setbits $clearbits +} + +if {[set $_CHIPNAME.USE_CTI]} { + # create CTI instances for both cores + cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0xE0043000 + cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -ctibase 0xE0043000 + + $_CHIPNAME.cpu0 configure -event halted { stm32h7x_cti_prepare_restart_all } + $_CHIPNAME.cpu1 configure -event halted { stm32h7x_cti_prepare_restart_all } + + $_CHIPNAME.cpu0 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } + $_CHIPNAME.cpu1 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } + + proc stm32h7x_cti_start {} { + # get _CHIPNAME from the current target + set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + + # Configure Cores' CTIs to halt each other + # TRIGIN0 (DBGTRIGGER) and TRIGOUT0 (EDBGRQ) at CTM_CHANNEL_0 + $_CHIPNAME.cti0 write INEN0 0x1 + $_CHIPNAME.cti0 write OUTEN0 0x1 + $_CHIPNAME.cti1 write INEN0 0x1 + $_CHIPNAME.cti1 write OUTEN0 0x1 + + # enable CTIs + $_CHIPNAME.cti0 enable on + $_CHIPNAME.cti1 enable on + } + + proc stm32h7x_cti_stop {} { + # get _CHIPNAME from the current target + set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + + $_CHIPNAME.cti0 enable off + $_CHIPNAME.cti1 enable off + } + + proc stm32h7x_cti_prepare_restart_all {} { + stm32h7x_cti_prepare_restart cti0 + stm32h7x_cti_prepare_restart cti1 + } + + proc stm32h7x_cti_prepare_restart {cti} { + # get _CHIPNAME from the current target + set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + + # Acknowlodge EDBGRQ at TRIGOUT0 + $_CHIPNAME.$cti write INACK 0x01 + $_CHIPNAME.$cti write INACK 0x00 + } +} diff --git a/tcl/target/stm32h7x_dual_bank.cfg b/tcl/target/stm32h7x_dual_bank.cfg index 7e342f931..a88d70dcf 100644 --- a/tcl/target/stm32h7x_dual_bank.cfg +++ b/tcl/target/stm32h7x_dual_bank.cfg @@ -1,7 +1,6 @@ # script for stm32h7x family (dual flash bank) -source [find target/stm32h7x.cfg] # STM32H7xxxI 2Mo have a dual bank flash. -# Add the second flash bank. -set _FLASHNAME $_CHIPNAME.flash1 -flash bank $_FLASHNAME stm32h7x 0x08100000 0 0 0 $_TARGETNAME +set DUAL_BANK 1 + +source [find target/stm32h7x.cfg] diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index ec5d5463e..7653d13ef 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -24,9 +24,9 @@ if { [info exists WORKAREASIZE] } { # JTAG speed should be <= F_CPU/6. # F_CPU after reset is ~2MHz, so use F_JTAG max = 333kHz -adapter_khz 300 +adapter speed 300 -adapter_nsrst_delay 100 +adapter srst delay 100 if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID @@ -61,13 +61,16 @@ proc stm32l0_enable_HSI16 {} { echo "STM32L0: Enabling HSI16" # Set HSI16ON in RCC_CR (leave MSI enabled) - mww 0x40021000 0x00000101 + mmw 0x40021000 0x00000101 0 # Set HSI16 as SYSCLK (RCC_CFGR) - mww 0x4002100c 0x00000001 + mmw 0x4002100c 0x00000001 0 + + # Wait until System clock switches to HSI16 + while { ([ mrw 0x4002100c ] & 0x0c) != 0x04 } { } # Increase speed - adapter_khz 2500 + adapter speed 2500 } $_TARGETNAME configure -event reset-init { @@ -75,7 +78,7 @@ $_TARGETNAME configure -event reset-init { } $_TARGETNAME configure -event reset-start { - adapter_khz 300 + adapter speed 300 } $_TARGETNAME configure -event examine-end { diff --git a/tcl/target/stm32l1.cfg b/tcl/target/stm32l1.cfg index 054fa9b74..a81d7c798 100644 --- a/tcl/target/stm32l1.cfg +++ b/tcl/target/stm32l1.cfg @@ -23,9 +23,9 @@ if { [info exists WORKAREASIZE] } { # JTAG speed should be <= F_CPU/6. # F_CPU after reset is 2MHz, so use F_JTAG max = 333kHz -adapter_khz 300 +adapter speed 300 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -73,13 +73,13 @@ proc stm32l_enable_HSI {} { echo "STM32L: Enabling HSI" # Set HSION in RCC_CR - mww 0x40023800 0x00000101 + mmw 0x40023800 0x00000101 0 # Set HSI as SYSCLK - mww 0x40023808 0x00000001 + mmw 0x40023808 0x00000001 0 # Increase JTAG speed - adapter_khz 2000 + adapter speed 2000 } $_TARGETNAME configure -event reset-init { @@ -87,7 +87,7 @@ $_TARGETNAME configure -event reset-init { } $_TARGETNAME configure -event reset-start { - adapter_khz 300 + adapter speed 300 } $_TARGETNAME configure -event examine-end { diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 496b47a72..46e6f7e0d 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -56,9 +56,9 @@ flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ -adapter_khz 500 +adapter speed 500 -adapter_nsrst_delay 100 +adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } @@ -78,12 +78,12 @@ $_TARGETNAME configure -event reset-init { mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 # Boost JTAG frequency - adapter_khz 4000 + adapter speed 4000 } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) - adapter_khz 500 + adapter speed 500 } $_TARGETNAME configure -event examine-end { diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg new file mode 100644 index 000000000..f2ba94eec --- /dev/null +++ b/tcl/target/stm32mp15x.cfg @@ -0,0 +1,121 @@ +# STMicroelectronics STM32MP15x (Single/Dual Cortex-A7 plus Cortex-M4) +# http://www.st.com/stm32mp1 + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + echo "ERROR: To use STLink switch to DAP mode, as in \"board/stm32mp15x_dk2.cfg\"." + shutdown +} + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp15x +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } else { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x06500041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 +if { [using_jtag] } { + jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack + +# FIXME: Cortex-M code requires target accessible during reset, but this is not possible in STM32MP1 +# so defer-examine it until the reset framework get merged +# NOTE: keep ap-num and dbgbase to speed-up examine after reset +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 +target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 +target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 +target create $_CHIPNAME.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine + +targets $_CHIPNAME.cpu0 + +target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 +$_CHIPNAME.cpu0 cortex_a maskisr on +$_CHIPNAME.cpu1 cortex_a maskisr on +$_CHIPNAME.cpu0 cortex_a dacrfixup on +$_CHIPNAME.cpu1 cortex_a dacrfixup on + +cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE0094000 +cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE00D8000 +cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE00D9000 +cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -ctibase 0xE0043000 + +# interface does not work while srst is asserted +# this is target specific, valid for every board +# Errata "2.3.5 Incorrect reset of glitch-free kernel clock switch" requires +# srst to force VDDCORE power cycle or pull srst_core. Both cases reset the +# debug unit, behavior equivalent to "srst_pulls_trst" +reset_config srst_gates_jtag srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# bootrom has an internal timeout of 1 second for detecting the boot flash. +# wait at least 1 second to guarantee we are out of bootrom +adapter srst delay 1100 + +add_help_text axi_secure "Set secure mode for following AXI accesses" +proc axi_secure {} { + $::_CHIPNAME.dap apsel 0 + $::_CHIPNAME.dap apcsw 0x10006000 +} + +add_help_text axi_nsecure "Set non-secure mode for following AXI accesses" +proc axi_nsecure {} { + $::_CHIPNAME.dap apsel 0 + $::_CHIPNAME.dap apcsw 0x30006000 +} + +axi_secure + +proc dbgmcu_enable_debug {} { + # set debug enable bits in DBGMCU_CR to get ap2 and cm4 visible + catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000007} +} + +proc toggle_cpu0_dbg_claim0 {} { + # toggle CPU0 DBG_CLAIM[0] + $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 + $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 +} + +proc detect_cpu1 {} { + $::_CHIPNAME.ap1 mem2array cpu1_prsr 32 0xE00D2314 1 + set dual_core [expr $cpu1_prsr(0) & 1] + if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} +} + +# FIXME: most of handler below will be removed once reset framework get merged +$_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;dap init;catch {$::_CHIPNAME.dap apid 1}} +$_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug} +$_CHIPNAME.cpu0 configure -event reset-deassert-pre {$::_CHIPNAME.cpu0 arp_examine} +$_CHIPNAME.cpu1 configure -event reset-deassert-pre {$::_CHIPNAME.cpu1 arp_examine allow-defer} +$_CHIPNAME.cpu0 configure -event reset-deassert-post {toggle_cpu0_dbg_claim0} +$_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_examine;if {[$::_CHIPNAME.ap2 curstate] == "halted"} {$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_halt}} +$_CHIPNAME.ap1 configure -event examine-start {dap init} +$_CHIPNAME.ap2 configure -event examine-start {dbgmcu_enable_debug} +$_CHIPNAME.cpu0 configure -event examine-end {detect_cpu1} +$_CHIPNAME.ap2 configure -event examine-end {$::_CHIPNAME.cm4 arp_examine} diff --git a/tcl/target/stm32wbx.cfg b/tcl/target/stm32wbx.cfg new file mode 100644 index 000000000..90f53bb96 --- /dev/null +++ b/tcl/target/stm32wbx.cfg @@ -0,0 +1,103 @@ +# script for stm32wbx family + +# +# stm32wb devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32wbx +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } else { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x6ba02477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +# Common knowledges tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://openocd.zylin.com/#/c/3366/ +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event reset-init { + # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. + # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. + # 2 WS compliant with VOS=Range1 and 24 MHz. + mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTBE | 2(Latency) + mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz + # Boost JTAG frequency + adapter speed 4000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 500 +} + +$_TARGETNAME configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE004203C 0x00001800 0 +} + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xE0042004 0x00000020 0 +} diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg new file mode 100644 index 000000000..98c9a7ee9 --- /dev/null +++ b/tcl/target/stm32wlx.cfg @@ -0,0 +1,100 @@ +# script for stm32wlx family + +# +# stm32wl devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32wlx +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 20kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x5000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } else { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x6ba02477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + swj_newdap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +# Common knowledges tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://openocd.zylin.com/#/c/3366/ +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event reset-init { + # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. + # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. + # 2 WS compliant with VOS=Range1 and 24 MHz. + mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTEN | 2(Latency) + mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz + # Boost JTAG frequency + adapter speed 4000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 500 +} + +$_TARGETNAME configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE004203C 0x00001800 0 +} + +$_TARGETNAME configure -event trace-config { + # nothing to do +} diff --git a/tcl/target/stm8l.cfg b/tcl/target/stm8l.cfg index 5cc99e191..a06c4cb60 100644 --- a/tcl/target/stm8l.cfg +++ b/tcl/target/stm8l.cfg @@ -4,7 +4,7 @@ # stm8 devices support SWIM transports only. # -transport select stlink_swim +transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -62,7 +62,7 @@ if { [info exists BLOCKSIZE] } { set _BLOCKSIZE 0x80 } -hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 +swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu @@ -78,8 +78,10 @@ $_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocks # Set stm8l type $_TARGETNAME configure -enable_stm8l -# The khz rate does not apply here, only slow <0> and fast <1> -adapter_khz 1 +# Set high speed +adapter speed 800 +# Set low speed +#adapter speed 363 reset_config srst_only diff --git a/tcl/target/stm8s.cfg b/tcl/target/stm8s.cfg index d55e61b08..2dae65515 100644 --- a/tcl/target/stm8s.cfg +++ b/tcl/target/stm8s.cfg @@ -4,7 +4,7 @@ # stm8 devices support SWIM transports only. # -transport select stlink_swim +transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -62,7 +62,7 @@ if { [info exists BLOCKSIZE] } { set _BLOCKSIZE 0x80 } -hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 +swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu @@ -75,8 +75,10 @@ $_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocks # Uncomment this line to enable interrupts while instruction step #$_TARGETNAME configure -enable_step_irq -# The khz rate does not apply here, only slow <0> and fast <1> -adapter_khz 1 +# Set high speed +adapter speed 800 +# Set low speed +#adapter speed 363 reset_config srst_only diff --git a/tcl/target/stm8s103.cfg b/tcl/target/stm8s103.cfg new file mode 100644 index 000000000..714acf480 --- /dev/null +++ b/tcl/target/stm8s103.cfg @@ -0,0 +1,13 @@ +#config script for STM8S103 + +set FLASHEND 0x9FFF +set EEPROMEND 0x427F +set OPTIONEND 0x480A +set BLOCKSIZE 0x40 + +proc stm8_reset_rop {} { + mwb 0x4800 0x00 + reset halt +} + +source [find target/stm8s.cfg] diff --git a/tcl/target/str710.cfg b/tcl/target/str710.cfg index d26a8b1cf..29faaaa58 100644 --- a/tcl/target/str710.cfg +++ b/tcl/target/str710.cfg @@ -1,5 +1,5 @@ #start slow, speed up after reset -adapter_khz 10 +adapter speed 10 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -29,9 +29,9 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_C set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME -$_TARGETNAME configure -event reset-start { adapter_khz 10 } +$_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { - adapter_khz 6000 + adapter speed 6000 # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial diff --git a/tcl/target/str730.cfg b/tcl/target/str730.cfg index 48d3134aa..e9e2f26e8 100644 --- a/tcl/target/str730.cfg +++ b/tcl/target/str730.cfg @@ -1,6 +1,6 @@ #STR730 CPU -adapter_khz 3000 +adapter speed 3000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -27,15 +27,15 @@ reset_config trst_and_srst srst_pulls_trst jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID #jtag nTRST and nSRST delay -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian little -chain-position 0 -$_TARGETNAME configure -event reset-start { adapter_khz 10 } +$_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { - adapter_khz 3000 + adapter speed 3000 # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial @@ -51,4 +51,3 @@ $_TARGETNAME configure -work-area-phys 0xA0000000 -work-area-size 0x4000 -work-a #flash bank set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME str7x 0x80000000 0x00040000 0 0 $_TARGETNAME STR73x - diff --git a/tcl/target/str750.cfg b/tcl/target/str750.cfg index ef6e7954e..335d5ada9 100644 --- a/tcl/target/str750.cfg +++ b/tcl/target/str750.cfg @@ -19,7 +19,7 @@ if { [info exists CPUTAPID] } { } # jtag speed -adapter_khz 10 +adapter speed 10 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst @@ -29,15 +29,15 @@ reset_config trst_and_srst srst_pulls_trst jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID #jtag nTRST and nSRST delay -adapter_nsrst_delay 500 +adapter srst delay 500 jtag_ntrst_delay 500 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian little -chain-position 0 -$_TARGETNAME configure -event reset-start { adapter_khz 10 } +$_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { - adapter_khz 3000 + adapter speed 3000 init_smi # Because the hardware cannot be interrogated for the protection state diff --git a/tcl/target/str912.cfg b/tcl/target/str912.cfg index 36c0b2a54..7426276bf 100644 --- a/tcl/target/str912.cfg +++ b/tcl/target/str912.cfg @@ -13,9 +13,9 @@ if { [info exists ENDIAN] } { } # jtag speed. We need to stick to 16kHz until we've finished reset. -adapter_khz 16 +adapter speed 16 -adapter_nsrst_delay 100 +adapter srst delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately @@ -48,11 +48,11 @@ jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BST set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME -$_TARGETNAME configure -event reset-start { adapter_khz 16 } +$_TARGETNAME configure -event reset-start { adapter speed 16 } $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. - #adapter_khz 3000 + #adapter speed 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled diff --git a/tcl/target/swm050.cfg b/tcl/target/swm050.cfg index a819f9c42..e6f2ecbf9 100644 --- a/tcl/target/swm050.cfg +++ b/tcl/target/swm050.cfg @@ -1,5 +1,7 @@ # Synwit SWM050 +source [find target/swj-dp.tcl] + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { @@ -16,10 +18,10 @@ if { [info exists WORKAREASIZE] } { if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { - set _CPUTAPID 0x410CC200 + set _CPUTAPID 0x0bb11477 } -swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap @@ -27,6 +29,7 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME +adapter speed 1000 $_TARGETNAME configure -event reset-init { # Stop the watchdog, just to be safe diff --git a/tcl/target/ti-cjtag.cfg b/tcl/target/ti-cjtag.cfg old mode 100755 new mode 100644 diff --git a/tcl/target/ti_calypso.cfg b/tcl/target/ti_calypso.cfg index 9d3b293ee..52a84fb9b 100644 --- a/tcl/target/ti_calypso.cfg +++ b/tcl/target/ti_calypso.cfg @@ -32,7 +32,7 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x10000 } -adapter_khz 1000 +adapter speed 1000 reset_config trst_and_srst diff --git a/tcl/target/ti_cc26x0.cfg b/tcl/target/ti_cc26x0.cfg index 7efecb666..f95d7b2fc 100644 --- a/tcl/target/ti_cc26x0.cfg +++ b/tcl/target/ti_cc26x0.cfg @@ -52,5 +52,4 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME -reset_config srst_only -adapter_nsrst_delay 100 +cortex_m reset_config vectreset diff --git a/tcl/target/ti_cc3220sf.cfg b/tcl/target/ti_cc3220sf.cfg index f7d9bfe17..74269aa66 100644 --- a/tcl/target/ti_cc3220sf.cfg +++ b/tcl/target/ti_cc3220sf.cfg @@ -10,3 +10,31 @@ source [find target/ti_cc32xx.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME + +# +# On CC32xx family of devices, sysreqreset is disabled, and vectreset is +# blocked by the boot loader (stops in a while(1) statement). srst reset can +# leave the target in a state that prevents debug. The following uses the +# soft_reset_halt command to reset and halt the target. Then the PC and stack +# are initialized from internal flash. This allows for a more reliable reset, +# but with two caveats: it only works for the SF variant that has internal +# flash, and it only resets the CPU and not any peripherals. +# + +proc ocd_process_reset_inner { MODE } { + + soft_reset_halt + + # Initialize MSP, PSP, and PC from vector table at flash 0x01000800 + mem2array boot 32 0x01000800 2 + + reg msp $boot(0) + reg psp $boot(0) + reg pc $boot(1) + + if { 0 == [string compare $MODE run ] } { + resume + } + + cc32xx.cpu invoke-event reset-end +} diff --git a/tcl/target/ti_cc32xx.cfg b/tcl/target/ti_cc32xx.cfg index bc3038d8e..e3e3ebc92 100644 --- a/tcl/target/ti_cc32xx.cfg +++ b/tcl/target/ti_cc32xx.cfg @@ -59,6 +59,3 @@ if { [info exists WORKAREASIZE] } { } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -reset_config srst_only -adapter_nsrst_delay 1100 diff --git a/tcl/target/ti_dm355.cfg b/tcl/target/ti_dm355.cfg index 4f8f523e8..91c008765 100644 --- a/tcl/target/ti_dm355.cfg +++ b/tcl/target/ti_dm355.cfg @@ -98,8 +98,8 @@ $_TARGETNAME configure \ # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 24 MHz (best case: 36 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. -adapter_khz 1500 -$_TARGETNAME configure -event "reset-start" { adapter_khz 1500 } +adapter speed 1500 +$_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable diff --git a/tcl/target/ti_dm365.cfg b/tcl/target/ti_dm365.cfg index 0db83dbaa..8b52746bd 100644 --- a/tcl/target/ti_dm365.cfg +++ b/tcl/target/ti_dm365.cfg @@ -90,8 +90,8 @@ $_TARGETNAME configure \ # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 19.2 MHz (best case: 36 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. -adapter_khz 1500 -$_TARGETNAME configure -event "reset-start" { adapter_khz 1500 } +adapter speed 1500 +$_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable diff --git a/tcl/target/ti_dm6446.cfg b/tcl/target/ti_dm6446.cfg index fa1e6e957..ccc650a3d 100644 --- a/tcl/target/ti_dm6446.cfg +++ b/tcl/target/ti_dm6446.cfg @@ -70,8 +70,8 @@ $_TARGETNAME configure -work-area-phys 0x0000a000 -work-area-size 0x2000 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. -adapter_khz 1500 -$_TARGETNAME configure -event "reset-start" { adapter_khz 1500 } +adapter speed 1500 +$_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable diff --git a/tcl/target/ti_msp432.cfg b/tcl/target/ti_msp432.cfg index 3407f7505..77f81da69 100644 --- a/tcl/target/ti_msp432.cfg +++ b/tcl/target/ti_msp432.cfg @@ -42,10 +42,10 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x4000 } + $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME -reset_config srst_only -adapter_nsrst_delay 100 +cortex_m reset_config sysresetreq diff --git a/tcl/target/ti_tms570.cfg b/tcl/target/ti_tms570.cfg index ce3a17696..d06ff973f 100644 --- a/tcl/target/ti_tms570.cfg +++ b/tcl/target/ti_tms570.cfg @@ -1,4 +1,4 @@ -adapter_khz 1500 +adapter speed 1500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/tmpa900.cfg b/tcl/target/tmpa900.cfg index 3ba3591be..8e7070020 100644 --- a/tcl/target/tmpa900.cfg +++ b/tcl/target/tmpa900.cfg @@ -28,7 +28,7 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CP #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst -adapter_nsrst_delay 20 +adapter srst delay 20 jtag_ntrst_delay 20 ###################### diff --git a/tcl/target/tmpa910.cfg b/tcl/target/tmpa910.cfg index 5d41c8c2a..d933c0b2a 100644 --- a/tcl/target/tmpa910.cfg +++ b/tcl/target/tmpa910.cfg @@ -28,7 +28,7 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CP #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst -adapter_nsrst_delay 20 +adapter srst delay 20 jtag_ntrst_delay 20 ###################### diff --git a/tcl/target/tnetc4401.cfg b/tcl/target/tnetc4401.cfg new file mode 100644 index 000000000..48f754527 --- /dev/null +++ b/tcl/target/tnetc4401.cfg @@ -0,0 +1,17 @@ +# Texas Instruments (TI) TNETC4401, MIPS32 DOCSIS-tailored SoC (4Kc-based) +# Used in Knovative KC-100 and Motorola Surfboard SB5120 cable modems. +# Datasheet: https://brezn.muc.ccc.de/~mazzoo/DOCSIS/tnetc4401.pdf +transport select jtag +set _TARGETNAME tnetc4401 +set _CPUTAPID 0x0000100f +jtag newtap $_TARGETNAME tap -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID +target create $_TARGETNAME mips_m4k -chain-position $_TARGETNAME.tap -endian big + +# May need to halt manually before calling reset init +$_TARGETNAME configure -event reset-init { + halt + echo "Attempting to disable watchdog..." + mwb phys 0xa8610b00 0 256 + halt + wait_halt +} diff --git a/tcl/target/u8500.cfg b/tcl/target/u8500.cfg index 7ff39291b..36e0db71d 100644 --- a/tcl/target/u8500.cfg +++ b/tcl/target/u8500.cfg @@ -1,6 +1,6 @@ # Copyright (C) ST-Ericsson SA 2011 # Author : michel.jaouen@stericsson.com -# U8500 target +# U8500 target proc mmu_off {} { set cp [arm mrc 15 0 1 0 0] @@ -31,7 +31,7 @@ proc ocd_gdb_restart {target_id} { proc smp_reg {} { global _TARGETNAME_1 global _TARGETNAME_2 - targets $_TARGETNAME_1 + targets $_TARGETNAME_1 echo "$_TARGETNAME_1" set pc1 [reg pc] set stck1 [reg sp_svc] @@ -68,7 +68,7 @@ proc pwrsts { } { 8 { echo "A9 100% DVFS" } - c { + c { echo "A9 50% DVFS" } } @@ -144,7 +144,7 @@ tcl_port 5555 telnet_port 4444 gdb_port 3333 -if { [info exists CHIPNAME] } { +if { [info exists CHIPNAME] } { global _CHIPNAME set _CHIPNAME $CHIPNAME } else { @@ -194,12 +194,12 @@ set _TARGETNAME_1 $TARGETNAME_1 if { [info exists DAP_DBG1] } { set _DAP_DBG1 $DAP_DBG1 } else { - set _DAP_DBG1 0x801A8000 + set _DAP_DBG1 0x801A8000 } if { [info exists DAP_DBG2] } { set _DAP_DBG2 $DAP_DBG2 } else { - set _DAP_DBG2 0x801AA000 + set _DAP_DBG2 0x801AA000 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu @@ -226,7 +226,7 @@ global _SMP set _SMP $SMP } global SMP -if { $_SMP == 1} { +if { $_SMP == 1} { target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 } @@ -264,7 +264,7 @@ proc att { } { } else { echo "target secured" } - + } @@ -310,11 +310,11 @@ if {![info exists MAXSPEED]} { global _MAXSPEED set _MAXSPEED 15000 } else { -global _MAXSPEED +global _MAXSPEED set _MAXSPEED $MAXSPEED } -global _MAXSPEED -adapter_khz $_MAXSPEED +global _MAXSPEED +adapter speed $_MAXSPEED gdb_breakpoint_override hard @@ -322,5 +322,3 @@ set mem inaccessible-by-default-off jtag_ntrst_delay 100 reset_config trst_and_srst combined - - diff --git a/tcl/target/vybrid_vf6xx.cfg b/tcl/target/vybrid_vf6xx.cfg index 7cb916d1f..c888d259f 100644 --- a/tcl/target/vybrid_vf6xx.cfg +++ b/tcl/target/vybrid_vf6xx.cfg @@ -34,4 +34,4 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap -dbgbase 0xc0088000 target create ${_TARGETNAME}1 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine -adapter_khz 1000 +adapter speed 1000 diff --git a/tcl/target/xmc1xxx.cfg b/tcl/target/xmc1xxx.cfg index e693b59db..eb94d7b3c 100644 --- a/tcl/target/xmc1xxx.cfg +++ b/tcl/target/xmc1xxx.cfg @@ -38,4 +38,4 @@ $_TARGETNAME configure -work-area-phys 0x20000000 \ set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME xmc1xxx 0x10000000 0 0 0 $_TARGETNAME -adapter_khz 1000 +adapter speed 1000 diff --git a/tcl/target/xmc4xxx.cfg b/tcl/target/xmc4xxx.cfg index e106d34e3..3020b28b0 100644 --- a/tcl/target/xmc4xxx.cfg +++ b/tcl/target/xmc4xxx.cfg @@ -57,4 +57,4 @@ if { ![using_hla] } { cortex_m reset_config sysresetreq } -adapter_khz 1000 +adapter speed 1000 diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index 1562768c5..b4b6f9f18 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -23,7 +23,7 @@ target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80092000 target smp ${_TARGETNAME}0 ${_TARGETNAME}1 -adapter_khz 1000 +adapter speed 1000 ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" diff --git a/tcl/test/selftest.cfg b/tcl/test/selftest.cfg old mode 100755 new mode 100644 diff --git a/tcl/test/syntax1.cfg b/tcl/test/syntax1.cfg index 79d538480..2e6618895 100644 --- a/tcl/test/syntax1.cfg +++ b/tcl/test/syntax1.cfg @@ -1,12 +1,12 @@ -adapter_nsrst_delay 200 +adapter srst delay 200 jtag_ntrst_delay 200 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #LPCs need reset pulled while RTCK is low. 0 to activate JTAG, power-on reset is not enough -jtag_reset 1 1 -jtag_reset 0 0 +adapter assert trst assert srst +adapter deassert trst deassert srst #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) @@ -27,4 +27,3 @@ mvb 0xE01FC040 0x01 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 0 lpc2000_v2 14765 - diff --git a/tcl/tools/firmware-recovery.tcl b/tcl/tools/firmware-recovery.tcl index 8e017ce5b..9d7e0fce8 100644 --- a/tcl/tools/firmware-recovery.tcl +++ b/tcl/tools/firmware-recovery.tcl @@ -29,7 +29,7 @@ dump_part save partition's contents to a file erase_part erase the given partition flash_part erase, flash and verify the given partition ram_boot load binary file to RAM and run it -adapter_khz set JTAG clock frequency in kHz +adapter speed set JTAG clock frequency in kHz For example, to clear nvram and reflash CFE on an RT-N16 using TUMPA, run: openocd -f interface/ftdi/tumpa.cfg -f tools/firmware-recovery.tcl \\ @@ -38,8 +38,8 @@ openocd -f interface/ftdi/tumpa.cfg -f tools/firmware-recovery.tcl \\ shutdown } -# set default, can be overriden later -adapter_khz 1000 +# set default, can be overridden later +adapter speed 1000 proc get_partition { name } { global partition_list diff --git a/testing/build.test1/Makefile b/testing/build.test1/Makefile index 7271bf2c6..02b752307 100644 --- a/testing/build.test1/Makefile +++ b/testing/build.test1/Makefile @@ -93,6 +93,3 @@ all.download: linux.ftd2xx_installed \ linux.ft22232_libftdi \ linux.ftd2xx_installed.setup - - - diff --git a/testing/build.test1/README.TXT b/testing/build.test1/README.TXT index c8244382a..7f4d401e8 100644 --- a/testing/build.test1/README.TXT +++ b/testing/build.test1/README.TXT @@ -36,4 +36,3 @@ Dec 26,2008 cd ~/work make cygwin.buildtest - diff --git a/testing/build.test1/mingw32_help/include/sys/cdefs.h b/testing/build.test1/mingw32_help/include/sys/cdefs.h index c401ce794..606205a58 100644 --- a/testing/build.test1/mingw32_help/include/sys/cdefs.h +++ b/testing/build.test1/mingw32_help/include/sys/cdefs.h @@ -20,4 +20,3 @@ details. */ #define __P(protos) protos /* full-blown ANSI C */ #define __CONCAT(__x,__y) __x##__y #endif - diff --git a/testing/build.test2/README.txt b/testing/build.test2/README.txt index d71c14b5a..382105ef0 100644 --- a/testing/build.test2/README.txt +++ b/testing/build.test2/README.txt @@ -56,4 +56,3 @@ For example - in cygwin, type this: ======= **END** ======= - diff --git a/testing/examples/AT91R40008Test/makefile b/testing/examples/AT91R40008Test/makefile index c57130a7b..24898a329 100644 --- a/testing/examples/AT91R40008Test/makefile +++ b/testing/examples/AT91R40008Test/makefile @@ -134,4 +134,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/AT91R40008Test/prj/ethernut3_ram.ld b/testing/examples/AT91R40008Test/prj/ethernut3_ram.ld index 604e70412..a5ae16eb8 100644 --- a/testing/examples/AT91R40008Test/prj/ethernut3_ram.ld +++ b/testing/examples/AT91R40008Test/prj/ethernut3_ram.ld @@ -137,4 +137,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/AT91R40008Test/src/crt.s b/testing/examples/AT91R40008Test/src/crt.s index 0b7026118..bab4609a2 100644 --- a/testing/examples/AT91R40008Test/src/crt.s +++ b/testing/examples/AT91R40008Test/src/crt.s @@ -167,6 +167,4 @@ FIQHandler: .weak IRQHandler, FIQHandler .ltorg -/*** EOF ***/ - - +/*** EOF ***/ diff --git a/testing/examples/LPC2148Test/makefile b/testing/examples/LPC2148Test/makefile index 3a098c33b..53f45f668 100644 --- a/testing/examples/LPC2148Test/makefile +++ b/testing/examples/LPC2148Test/makefile @@ -144,4 +144,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/LPC2148Test/prj/eclipse_ram.gdb b/testing/examples/LPC2148Test/prj/eclipse_ram.gdb index 4f423124d..ea0e21fc3 100644 --- a/testing/examples/LPC2148Test/prj/eclipse_ram.gdb +++ b/testing/examples/LPC2148Test/prj/eclipse_ram.gdb @@ -8,4 +8,4 @@ monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main -continue \ No newline at end of file +continue diff --git a/testing/examples/LPC2148Test/prj/eclipse_rom.gdb b/testing/examples/LPC2148Test/prj/eclipse_rom.gdb index 86780056d..3d372a059 100644 --- a/testing/examples/LPC2148Test/prj/eclipse_rom.gdb +++ b/testing/examples/LPC2148Test/prj/eclipse_rom.gdb @@ -8,4 +8,4 @@ monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main -continue \ No newline at end of file +continue diff --git a/testing/examples/LPC2148Test/prj/lpc2148_ram.ld b/testing/examples/LPC2148Test/prj/lpc2148_ram.ld index b7951342d..3cbb616f3 100644 --- a/testing/examples/LPC2148Test/prj/lpc2148_ram.ld +++ b/testing/examples/LPC2148Test/prj/lpc2148_ram.ld @@ -137,4 +137,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/LPC2148Test/prj/lpc2148_rom.ld b/testing/examples/LPC2148Test/prj/lpc2148_rom.ld index 5844fffce..9cb12e4f6 100644 --- a/testing/examples/LPC2148Test/prj/lpc2148_rom.ld +++ b/testing/examples/LPC2148Test/prj/lpc2148_rom.ld @@ -138,4 +138,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/LPC2148Test/src/crt.s b/testing/examples/LPC2148Test/src/crt.s index 774f6b4ae..6fd1d3059 100644 --- a/testing/examples/LPC2148Test/src/crt.s +++ b/testing/examples/LPC2148Test/src/crt.s @@ -184,6 +184,4 @@ FIQHandler: .weak IRQHandler, FIQHandler .ltorg -/*** EOF ***/ - - +/*** EOF ***/ diff --git a/testing/examples/LPC2294Test/makefile b/testing/examples/LPC2294Test/makefile index 6af02fbe1..9ac7fe867 100644 --- a/testing/examples/LPC2294Test/makefile +++ b/testing/examples/LPC2294Test/makefile @@ -144,4 +144,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/LPC2294Test/prj/eclipse_ram.gdb b/testing/examples/LPC2294Test/prj/eclipse_ram.gdb index 4f423124d..ea0e21fc3 100644 --- a/testing/examples/LPC2294Test/prj/eclipse_ram.gdb +++ b/testing/examples/LPC2294Test/prj/eclipse_ram.gdb @@ -8,4 +8,4 @@ monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main -continue \ No newline at end of file +continue diff --git a/testing/examples/LPC2294Test/prj/eclipse_rom.gdb b/testing/examples/LPC2294Test/prj/eclipse_rom.gdb index 86780056d..3d372a059 100644 --- a/testing/examples/LPC2294Test/prj/eclipse_rom.gdb +++ b/testing/examples/LPC2294Test/prj/eclipse_rom.gdb @@ -8,4 +8,4 @@ monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main -continue \ No newline at end of file +continue diff --git a/testing/examples/LPC2294Test/prj/lpc2294_ram.ld b/testing/examples/LPC2294Test/prj/lpc2294_ram.ld index 17eaedd87..bc4b93947 100644 --- a/testing/examples/LPC2294Test/prj/lpc2294_ram.ld +++ b/testing/examples/LPC2294Test/prj/lpc2294_ram.ld @@ -137,4 +137,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/LPC2294Test/prj/lpc2294_rom.ld b/testing/examples/LPC2294Test/prj/lpc2294_rom.ld index 64a28f0c6..ca71c28c1 100644 --- a/testing/examples/LPC2294Test/prj/lpc2294_rom.ld +++ b/testing/examples/LPC2294Test/prj/lpc2294_rom.ld @@ -138,4 +138,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/LPC2294Test/src/crt.s b/testing/examples/LPC2294Test/src/crt.s index ac17dcd5f..8b24cc195 100644 --- a/testing/examples/LPC2294Test/src/crt.s +++ b/testing/examples/LPC2294Test/src/crt.s @@ -184,6 +184,4 @@ FIQHandler: .weak IRQHandler, FIQHandler .ltorg -/*** EOF ***/ - - +/*** EOF ***/ diff --git a/testing/examples/SAM7S256Test/makefile b/testing/examples/SAM7S256Test/makefile index 9e1e83f8e..dabe9a3d8 100644 --- a/testing/examples/SAM7S256Test/makefile +++ b/testing/examples/SAM7S256Test/makefile @@ -143,4 +143,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/SAM7S256Test/prj/sam7s256_ram.ld b/testing/examples/SAM7S256Test/prj/sam7s256_ram.ld index 1b857c99f..593e17cac 100644 --- a/testing/examples/SAM7S256Test/prj/sam7s256_ram.ld +++ b/testing/examples/SAM7S256Test/prj/sam7s256_ram.ld @@ -129,4 +129,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/SAM7S256Test/prj/sam7s256_rom.ld b/testing/examples/SAM7S256Test/prj/sam7s256_rom.ld index b64854acd..b181023bb 100644 --- a/testing/examples/SAM7S256Test/prj/sam7s256_rom.ld +++ b/testing/examples/SAM7S256Test/prj/sam7s256_rom.ld @@ -130,4 +130,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/SAM7S256Test/results/607.html b/testing/examples/SAM7S256Test/results/607.html index 852c0ad67..e097586ee 100644 --- a/testing/examples/SAM7S256Test/results/607.html +++ b/testing/examples/SAM7S256Test/results/607.html @@ -695,4 +695,4 @@ Note: these tests are not designed to test/debug the target, but to test functio - \ No newline at end of file + diff --git a/testing/examples/SAM7S256Test/src/crt.s b/testing/examples/SAM7S256Test/src/crt.s index 16e5865ea..b0bae0d63 100644 --- a/testing/examples/SAM7S256Test/src/crt.s +++ b/testing/examples/SAM7S256Test/src/crt.s @@ -220,6 +220,4 @@ FIQHandler: .weak IRQHandler, FIQHandler .ltorg -/*** EOF ***/ - - +/*** EOF ***/ diff --git a/testing/examples/SAM7X256Test/makefile b/testing/examples/SAM7X256Test/makefile index 4ad44cf0b..4a5a730da 100644 --- a/testing/examples/SAM7X256Test/makefile +++ b/testing/examples/SAM7X256Test/makefile @@ -143,4 +143,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/SAM7X256Test/prj/sam7x256_ram.ld b/testing/examples/SAM7X256Test/prj/sam7x256_ram.ld index 1b857c99f..593e17cac 100644 --- a/testing/examples/SAM7X256Test/prj/sam7x256_ram.ld +++ b/testing/examples/SAM7X256Test/prj/sam7x256_ram.ld @@ -129,4 +129,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/SAM7X256Test/prj/sam7x256_rom.ld b/testing/examples/SAM7X256Test/prj/sam7x256_rom.ld index b64854acd..b181023bb 100644 --- a/testing/examples/SAM7X256Test/prj/sam7x256_rom.ld +++ b/testing/examples/SAM7X256Test/prj/sam7x256_rom.ld @@ -130,4 +130,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/SAM7X256Test/src/crt.s b/testing/examples/SAM7X256Test/src/crt.s index 16e5865ea..b0bae0d63 100644 --- a/testing/examples/SAM7X256Test/src/crt.s +++ b/testing/examples/SAM7X256Test/src/crt.s @@ -220,6 +220,4 @@ FIQHandler: .weak IRQHandler, FIQHandler .ltorg -/*** EOF ***/ - - +/*** EOF ***/ diff --git a/testing/examples/STM32-103/readme.txt b/testing/examples/STM32-103/readme.txt index 39b080dd6..f41a03df0 100644 --- a/testing/examples/STM32-103/readme.txt +++ b/testing/examples/STM32-103/readme.txt @@ -3,4 +3,4 @@ Olimex STM32-p103 board. main.elf is a file that can be programmed to flash for testing purposes(e.g. test GDB load performance). -http://www.olimex.com/dev/stm32-p103.html \ No newline at end of file +http://www.olimex.com/dev/stm32-p103.html diff --git a/testing/examples/STR710JtagSpeed/makefile b/testing/examples/STR710JtagSpeed/makefile index 816ab233e..72be7159b 100644 --- a/testing/examples/STR710JtagSpeed/makefile +++ b/testing/examples/STR710JtagSpeed/makefile @@ -131,4 +131,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/STR710JtagSpeed/prj/eclipse_ft2232_ram.gdb b/testing/examples/STR710JtagSpeed/prj/eclipse_ft2232_ram.gdb index 92f8e18e5..9c48e3571 100644 --- a/testing/examples/STR710JtagSpeed/prj/eclipse_ft2232_ram.gdb +++ b/testing/examples/STR710JtagSpeed/prj/eclipse_ft2232_ram.gdb @@ -24,10 +24,3 @@ monitor verify_ircapture disable load break main continue - - - - - - - diff --git a/testing/examples/STR710JtagSpeed/prj/str7_ram.ld b/testing/examples/STR710JtagSpeed/prj/str7_ram.ld index d760f2620..ded9ab4b4 100644 --- a/testing/examples/STR710JtagSpeed/prj/str7_ram.ld +++ b/testing/examples/STR710JtagSpeed/prj/str7_ram.ld @@ -137,4 +137,3 @@ SECTIONS } /*** EOF ***/ - diff --git a/testing/examples/STR710JtagSpeed/src/crt.s b/testing/examples/STR710JtagSpeed/src/crt.s index d1c238c7b..c27d18e02 100644 --- a/testing/examples/STR710JtagSpeed/src/crt.s +++ b/testing/examples/STR710JtagSpeed/src/crt.s @@ -258,6 +258,4 @@ FIQHandler: .weak IRQHandler, FIQHandler .ltorg -/*** EOF ***/ - - +/*** EOF ***/ diff --git a/testing/examples/STR710Test/makefile b/testing/examples/STR710Test/makefile index 1450b73d5..adac2433a 100644 --- a/testing/examples/STR710Test/makefile +++ b/testing/examples/STR710Test/makefile @@ -143,4 +143,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/STR710Test/prj/eclipse_ram.gdb b/testing/examples/STR710Test/prj/eclipse_ram.gdb index 511ed5914..80efec42d 100644 --- a/testing/examples/STR710Test/prj/eclipse_ram.gdb +++ b/testing/examples/STR710Test/prj/eclipse_ram.gdb @@ -8,4 +8,4 @@ monitor mww 0xA0000050 0x01c2 monitor mdw 0xA0000050 load break main -continue \ No newline at end of file +continue diff --git a/testing/examples/STR710Test/prj/eclipse_rom.gdb b/testing/examples/STR710Test/prj/eclipse_rom.gdb index 9e2c37005..d8eaf1e9f 100644 --- a/testing/examples/STR710Test/prj/eclipse_rom.gdb +++ b/testing/examples/STR710Test/prj/eclipse_rom.gdb @@ -8,4 +8,4 @@ monitor mww 0xA0000050 0x01c2 monitor mdw 0xA0000050 load break main -continue \ No newline at end of file +continue diff --git a/testing/examples/STR710Test/prj/hitex_str7_rom.ld b/testing/examples/STR710Test/prj/hitex_str7_rom.ld index 11ac4b621..329dbe014 100644 --- a/testing/examples/STR710Test/prj/hitex_str7_rom.ld +++ b/testing/examples/STR710Test/prj/hitex_str7_rom.ld @@ -256,4 +256,3 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } - diff --git a/testing/examples/STR710Test/prj/str710_program.script b/testing/examples/STR710Test/prj/str710_program.script index b268adf09..b1601b847 100644 --- a/testing/examples/STR710Test/prj/str710_program.script +++ b/testing/examples/STR710Test/prj/str710_program.script @@ -1,8 +1 @@ flash protect 0 0 7 off - - - - - - - diff --git a/testing/examples/STR710Test/src/crt.s b/testing/examples/STR710Test/src/crt.s index c9db5f5ea..0e7cd37d8 100644 --- a/testing/examples/STR710Test/src/crt.s +++ b/testing/examples/STR710Test/src/crt.s @@ -296,4 +296,3 @@ FIQHandler: .ltorg /*** EOF ***/ - diff --git a/testing/examples/STR912Test/makefile b/testing/examples/STR912Test/makefile index ee7685795..6f8309eab 100644 --- a/testing/examples/STR912Test/makefile +++ b/testing/examples/STR912Test/makefile @@ -143,4 +143,4 @@ clean: # -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) -# *** EOF *** \ No newline at end of file +# *** EOF *** diff --git a/testing/examples/STR912Test/prj/eclipse_ram.gdb b/testing/examples/STR912Test/prj/eclipse_ram.gdb index 00a62d705..67def3c4f 100644 --- a/testing/examples/STR912Test/prj/eclipse_ram.gdb +++ b/testing/examples/STR912Test/prj/eclipse_ram.gdb @@ -15,7 +15,3 @@ monitor mww 0x54000000 0xf load break main continue - - - - diff --git a/testing/examples/STR912Test/prj/eclipse_rom.gdb b/testing/examples/STR912Test/prj/eclipse_rom.gdb index 58977cfcd..35cbff8e1 100644 --- a/testing/examples/STR912Test/prj/eclipse_rom.gdb +++ b/testing/examples/STR912Test/prj/eclipse_rom.gdb @@ -15,7 +15,3 @@ monitor mww 0x54000000 0xf load break main continue - - - - diff --git a/testing/examples/STR912Test/prj/str912_program.script b/testing/examples/STR912Test/prj/str912_program.script index df0239b9d..45ec8a7a2 100644 --- a/testing/examples/STR912Test/prj/str912_program.script +++ b/testing/examples/STR912Test/prj/str912_program.script @@ -1,9 +1,2 @@ str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off - - - - - - - diff --git a/testing/examples/STR912Test/prj/str912_ram.ld b/testing/examples/STR912Test/prj/str912_ram.ld index 269ada9bf..9b9e731d4 100644 --- a/testing/examples/STR912Test/prj/str912_ram.ld +++ b/testing/examples/STR912Test/prj/str912_ram.ld @@ -215,4 +215,3 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } - diff --git a/testing/examples/STR912Test/prj/str912_rom.ld b/testing/examples/STR912Test/prj/str912_rom.ld index 804149d21..aace268ca 100644 --- a/testing/examples/STR912Test/prj/str912_rom.ld +++ b/testing/examples/STR912Test/prj/str912_rom.ld @@ -246,4 +246,3 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } - diff --git a/testing/examples/ledtest-imx27ads/Makefile b/testing/examples/ledtest-imx27ads/Makefile index 4009c41b2..a1e0ba3ac 100644 --- a/testing/examples/ledtest-imx27ads/Makefile +++ b/testing/examples/ledtest-imx27ads/Makefile @@ -39,4 +39,3 @@ dump_full: clean: -/bin/rm -f *.o *~ test.elf - diff --git a/testing/examples/ledtest-imx27ads/crt0.S b/testing/examples/ledtest-imx27ads/crt0.S index d7498814c..770982b31 100644 --- a/testing/examples/ledtest-imx27ads/crt0.S +++ b/testing/examples/ledtest-imx27ads/crt0.S @@ -44,4 +44,3 @@ _mainCRTStartup: .word __bss_start__ .LC2: .word __bss_end__ - diff --git a/testing/examples/ledtest-imx27ads/gdbinit-imx27ads b/testing/examples/ledtest-imx27ads/gdbinit-imx27ads index 4764bc738..88fc78a3d 100644 --- a/testing/examples/ledtest-imx27ads/gdbinit-imx27ads +++ b/testing/examples/ledtest-imx27ads/gdbinit-imx27ads @@ -33,4 +33,3 @@ b main # Run to the breakpoint. c - diff --git a/testing/examples/ledtest-imx27ads/test.c b/testing/examples/ledtest-imx27ads/test.c index a3dd52234..01dc284da 100644 --- a/testing/examples/ledtest-imx27ads/test.c +++ b/testing/examples/ledtest-imx27ads/test.c @@ -54,5 +54,3 @@ atexit() { while (1); } /* ATEXIT */ - - diff --git a/testing/examples/ledtest-imx31pdk/Makefile b/testing/examples/ledtest-imx31pdk/Makefile index 74e2fc23f..1ca6a8d15 100644 --- a/testing/examples/ledtest-imx31pdk/Makefile +++ b/testing/examples/ledtest-imx31pdk/Makefile @@ -39,4 +39,3 @@ dump_full: clean: -/bin/rm -f *.o *~ test.elf - diff --git a/testing/examples/ledtest-imx31pdk/crt0.S b/testing/examples/ledtest-imx31pdk/crt0.S index d7498814c..770982b31 100644 --- a/testing/examples/ledtest-imx31pdk/crt0.S +++ b/testing/examples/ledtest-imx31pdk/crt0.S @@ -44,4 +44,3 @@ _mainCRTStartup: .word __bss_start__ .LC2: .word __bss_end__ - diff --git a/testing/examples/ledtest-imx31pdk/gdbinit-imx31pdk b/testing/examples/ledtest-imx31pdk/gdbinit-imx31pdk index 304a8d899..8374f5acb 100644 --- a/testing/examples/ledtest-imx31pdk/gdbinit-imx31pdk +++ b/testing/examples/ledtest-imx31pdk/gdbinit-imx31pdk @@ -33,4 +33,3 @@ b main # Run to the breakpoint. c - diff --git a/testing/examples/ledtest-imx31pdk/test.c b/testing/examples/ledtest-imx31pdk/test.c index 4135f89c0..a7e37b442 100644 --- a/testing/examples/ledtest-imx31pdk/test.c +++ b/testing/examples/ledtest-imx31pdk/test.c @@ -52,5 +52,3 @@ atexit() { while (1); } /* ATEXIT */ - - diff --git a/testing/profile_stm32.txt b/testing/profile_stm32.txt index a7e03b08f..e0eb875ad 100644 --- a/testing/profile_stm32.txt +++ b/testing/profile_stm32.txt @@ -49,4 +49,3 @@ step 114 mem 96 erase 1547 flash fill 15564 - diff --git a/testing/results/template.html b/testing/results/template.html index 286bf2e3a..ffc9bbf1f 100644 --- a/testing/results/template.html +++ b/testing/results/template.html @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/testing/results/v0.4.0-rc1/AT91FR40162.html b/testing/results/v0.4.0-rc1/AT91FR40162.html index 0baa31e6b..8dcdf487c 100755 --- a/testing/results/v0.4.0-rc1/AT91FR40162.html +++ b/testing/results/v0.4.0-rc1/AT91FR40162.html @@ -853,4 +853,4 @@ Note: these tests are not designed to test/debug the target, but to test functio - \ No newline at end of file + diff --git a/testing/results/v0.4.0-rc1/LPC2148.html b/testing/results/v0.4.0-rc1/LPC2148.html index 425b52484..24d101129 100755 --- a/testing/results/v0.4.0-rc1/LPC2148.html +++ b/testing/results/v0.4.0-rc1/LPC2148.html @@ -930,4 +930,4 @@ Note: these tests are not designed to test/debug the target, but to test functio - \ No newline at end of file + diff --git a/testing/results/v0.4.0-rc1/SAM7.html b/testing/results/v0.4.0-rc1/SAM7.html index a400a476f..9dcabf88c 100755 --- a/testing/results/v0.4.0-rc1/SAM7.html +++ b/testing/results/v0.4.0-rc1/SAM7.html @@ -850,4 +850,4 @@ Note: these tests are not designed to test/debug the target, but to test functio - \ No newline at end of file + diff --git a/testing/results/v0.4.0-rc1/STR710.html b/testing/results/v0.4.0-rc1/STR710.html index 1a18ad0e6..075d549e3 100755 --- a/testing/results/v0.4.0-rc1/STR710.html +++ b/testing/results/v0.4.0-rc1/STR710.html @@ -904,4 +904,4 @@ The current source language is "auto; currently asm".
- \ No newline at end of file + diff --git a/testing/results/v0.4.0-rc1/STR912.html b/testing/results/v0.4.0-rc1/STR912.html index c8df03488..e9be17b98 100755 --- a/testing/results/v0.4.0-rc1/STR912.html +++ b/testing/results/v0.4.0-rc1/STR912.html @@ -1005,4 +1005,4 @@ verified 420 bytes in 0.350000s (1.172 kb/s)
- \ No newline at end of file + diff --git a/testing/tcl_test.tcl b/testing/tcl_test.tcl index 476e1c21a..3883dd965 100644 --- a/testing/tcl_test.tcl +++ b/testing/tcl_test.tcl @@ -60,6 +60,3 @@ puts "Running help on PC using data from OpenOCD" global ocd_helptext set ocd_helptext [get_help_text] puts [pc_help] - - - diff --git a/testing/testcases.html b/testing/testcases.html index a151e9f68..13b9e7256 100644 --- a/testing/testcases.html +++ b/testing/testcases.html @@ -563,4 +563,4 @@ Note: these tests are not designed to test/debug the target, but to test functio - \ No newline at end of file + diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh index e1dd267f9..0a630a248 100755 --- a/tools/checkpatch.sh +++ b/tools/checkpatch.sh @@ -2,4 +2,4 @@ # since=${1:-HEAD^} -git format-patch -M --stdout $since | tools/scripts/checkpatch.pl - --no-tree +git format-patch -M --stdout $since | tools/scripts/checkpatch.pl - diff --git a/tools/release/helpers.sh b/tools/release/helpers.sh index 47d5782ab..f06df34e9 100644 --- a/tools/release/helpers.sh +++ b/tools/release/helpers.sh @@ -57,4 +57,3 @@ Release: ${PACKAGE_RELEASE} Type: ${RELEASE_TYPE} INFO } - diff --git a/tools/release/version.sh b/tools/release/version.sh index d6c9434b3..a1c92f708 100755 --- a/tools/release/version.sh +++ b/tools/release/version.sh @@ -146,4 +146,3 @@ do_version() { package_info_load do_version "$@" - diff --git a/tools/st7_dtc_as/st7_dtc_as.pl b/tools/st7_dtc_as/st7_dtc_as.pl index 380c61d80..d4c42d7af 100755 --- a/tools/st7_dtc_as/st7_dtc_as.pl +++ b/tools/st7_dtc_as/st7_dtc_as.pl @@ -706,4 +706,3 @@ if($opt{'b'}) { 0; -