Merge branch 'master' into from_upstream

Conflicts:
      .gitmodules
      .travis.yml
      jimtcl
      src/jtag/core.c
      src/jtag/drivers/ftdi.c
      src/jtag/drivers/libjaylink
      src/jtag/drivers/mpsse.c
      src/jtag/drivers/stlink_usb.c
      src/rtos/hwthread.c
      src/target/riscv/riscv-013.c
      src/target/riscv/riscv.c
      tcl/board/sifive-hifive1-revb.cfg

Change-Id: I2d26ebeffb4c1374730d2e20e6e2a7710403657c
This commit is contained in:
Tim Newsome 2020-06-23 13:05:43 -07:00
commit e07613de33
766 changed files with 21771 additions and 5946 deletions

View File

@ -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).

2
README
View File

@ -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

37
TODO
View File

@ -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.
*/

View File

@ -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], [

View File

@ -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"

View File

@ -16,4 +16,3 @@ To see how many times the trace point was hit:
Spen
spen@spen-soft.co.uk

View File

@ -713,4 +713,3 @@ send_to_debugger:
receive_from_debugger:
m_receive_from_debugger r0
mov pc, lr

View File

@ -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 <http://www.gnu.org/licenses/>.
* 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 <http://www.gnu.org/licenses/>.
*/
;;
;; erase check memory code

View File

@ -57,4 +57,3 @@ done_write:
bkpt #0
.end

View File

@ -129,4 +129,3 @@ SECTIONS
}
/*** EOF ***/

View File

@ -2,6 +2,7 @@
/* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */
#include <stdint.h>
#include "../../../../src/flash/nor/bluenrg-x.h"
/* Status Values ----------------------------------------------------------*/
#define SUCCESS 0
@ -13,33 +14,14 @@
#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_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)
@ -48,8 +30,6 @@
#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;

View File

@ -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,

View File

@ -148,4 +148,3 @@ SECTIONS {
__stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK);
PROVIDE(__stack = __stack_top);
}

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -0,0 +1,306 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* SH QSPI (Quad SPI) driver
* Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
*/
#define BIT(n) (1UL << (n))
/* SH QSPI register bit masks <REG>_<BIT> */
#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

View File

@ -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,

View File

@ -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*)
}
}

View File

@ -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

View File

@ -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,

View File

@ -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 */
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 */
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
error:
movs r1, #0
str r1, [r0, #4] /* set rp = 0 on error */
exit:
mov r0, r6 /* return status in r0 */
bkpt #0x00
.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

View File

@ -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,

View File

@ -61,4 +61,3 @@ done:
bkpt #0
.end

View File

@ -78,4 +78,3 @@ done:
bkpt #0
.end

View File

@ -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:

View File

@ -726,4 +726,3 @@ finally:
cmdbuf[0] = XCOMPLETE
output.write( cmdbuf )
output.close()

View File

@ -265,4 +265,3 @@ def main():
if __name__ == "__main__":
main()

3
doc/.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
# Avoid DOS conversion of texinfo files during git clone
*.texi text eol=lf
*.txt text eol=lf

View File

@ -449,4 +449,3 @@ to permit their use in free software.
@c Local Variables:
@c ispell-local-pdict: "ispell-dict"
@c End:

View File

@ -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.

View File

@ -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 <millivolts>} 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 <measured nanoseconds>
@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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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,6 +3650,7 @@ showall:
}
if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
if (r == ERROR_OK)
command_print(CMD, "sam3-gpnvm%u: %u", who, v);
return r;
} else {
@ -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 = "",
},

View File

@ -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 = "",
},

View File

@ -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++) {

View File

@ -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;

View File

@ -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) */

View File

@ -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;

View File

@ -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");

View File

@ -24,35 +24,62 @@
#include <target/armv7m.h>
#include <target/cortex_m.h>
#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 <target#> */
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, &reg_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,28 +259,6 @@ 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;
}
/* Program chunk 16 bytes aligned in fast mode */
if (fast_size) {
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");
@ -378,7 +278,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* Stack pointer area */
if (target_alloc_working_area(target, 64,
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;
@ -392,30 +292,34 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
init_reg_param(&reg_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);
/* 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);
buf_set_u32(reg_params[2].value, 0, 32, address);
/* Number of bytes */
buf_set_u32(reg_params[3].value, 0, 32, fast_size);
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);
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("address = %08x", address);
LOG_DEBUG("count = %08x", count);
retval = target_run_flash_async_algorithm(target,
buffer+pre_size,
fast_size/16,
buffer,
count/16,
16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
0,
NULL,
1,
mem_params,
5,
reg_params,
source->address,
@ -452,17 +356,8 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
destroy_reg_param(&reg_params[4]);
if (retval != ERROR_OK)
return retval;
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,
};

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> *
* 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 <http://www.gnu.org/licenses/>. *
***************************************************************************/
#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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
if (retval != ERROR_OK)
return retval;
return retval2;
}
static int mb9bf_probe(struct flash_bank *bank)

View File

@ -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;

View File

@ -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 {

View File

@ -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 */

View File

@ -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)
);

View File

@ -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)
);

View File

@ -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;
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;
}
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,14 +961,16 @@ 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])
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,
};

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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 <marek.vasut@gmail.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "cfi.h"
#include "non_cfi.h"
#include <helper/binarybuffer.h>
#include <helper/bits.h>
#include <helper/time_support.h>
#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,
};

912
src/flash/nor/sh_qspi.c Normal file
View File

@ -0,0 +1,912 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* SH QSPI (Quad SPI) driver
* Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
*
* Based on U-Boot SH QSPI driver
* Copyright (C) 2013 Renesas Electronics Corporation
* Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "spi.h"
#include <helper/binarybuffer.h>
#include <helper/bits.h>
#include <helper/time_support.h>
#include <helper/types.h>
#include <jtag/jtag.h>
#include <target/algorithm.h>
#include <target/arm.h>
#include <target/arm_opcodes.h>
#include <target/target.h>
/* SH QSPI register bit masks <REG>_<BIT> */
#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(&reg_params[0], "r0", 32, PARAM_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
init_reg_param(&reg_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(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_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(&reg_params[0], "r0", 32, PARAM_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
init_reg_param(&reg_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(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_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,
};

View File

@ -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;

View File

@ -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");

View File

@ -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)
{
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);
LOG_DEBUG("sector %d: %dkBytes", 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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

82
src/flash/nor/stm32l4x.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>. *
***************************************************************************/
#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

View File

@ -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;
}

View File

@ -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,

View File

@ -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));

View File

@ -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));

View File

@ -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,14 +52,18 @@ proc program {filename args} {
program_error "** Unable to reset target **" $exit
}
# start programming phase
echo "** Programming Started **"
set filename \{$filename\}
if {[info exists address]} {
set flash_args "$filename $address"
} else {
set flash_args "$filename"
# 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
if {$needsflash == 1} {
echo "** Programming Started **"
if {[catch {eval flash write_image erase $flash_args}] == 0} {
echo "** Programming Finished **"
@ -60,6 +76,10 @@ proc program {filename args} {
program_error "** Verify Failed **" $exit
}
}
} else {
program_error "** Programming Failed **" $exit
}
}
if {[info exists reset]} {
# reset target if requested
@ -70,9 +90,7 @@ proc program {filename args} {
echo "** Resetting Target **"
reset run
}
} else {
program_error "** Programming Failed **" $exit
}
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 "<filename> \[address\] \[verify\] \[reset\] \[exit\]"
add_usage_text program "<filename> \[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 {

View File

@ -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.

View File

@ -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,8 +1216,8 @@ 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"
.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);

View File

@ -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 */

View File

@ -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;

View File

@ -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)
{
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 "
"%d ms timelimit. GDB alive packet not "
"sent! (%" PRId64 " ms). Workaround: increase "
"\"set remotetimeout\" in GDB",
current_time-last_time);
KEEP_ALIVE_TIMEOUT_MS,
delta_time);
else
LOG_DEBUG("keep_alive() was not invoked in the "
"1000ms timelimit (%" PRId64 "). This may cause "
"%d ms timelimit (%" PRId64 " ms). This may cause "
"trouble with GDB connections.",
current_time-last_time);
KEEP_ALIVE_TIMEOUT_MS,
delta_time);
}
void keep_alive(void)
{
current_time = timeval_ms();
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
}

View File

@ -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;

View File

@ -29,4 +29,3 @@ add_help_text script "filename of OpenOCD script (tcl) to run"
add_usage_text script "<file>"
#########

View File

@ -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 */

View File

@ -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)

View File

@ -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,

View File

@ -25,7 +25,6 @@
#include <transport/transport.h>
#include <target/target.h>
#include <jtag/aice/aice_transport.h>
#include <jtag/drivers/libusb_common.h>
#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,
};

View File

@ -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);
}

View File

@ -19,7 +19,7 @@
#include "config.h"
#endif
#include <jtag/drivers/libusb_common.h>
#include <jtag/drivers/libusb_helper.h>
#include <helper/log.h>
#include <helper/time_support.h>
#include <target/target.h>
@ -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) {

View File

@ -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 {

View File

@ -31,6 +31,7 @@
#endif
#include <jtag/jtag.h>
#include <transport/transport.h>
#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;

View File

@ -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);
jtag_sleep(adapter_nsrst_delay * 1000);
}
}
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("SRST timings error");
return;
}
}
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;
}

View File

@ -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

View File

@ -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,
};

View File

@ -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);

View File

@ -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)

Some files were not shown because too many files have changed in this diff Show More