Merge branch 'master' into from_upstream

Conflicts:
	.github/workflows/snapshot.yml
	.gitmodules
	src/flash/nor/drivers.c
	src/helper/jep106.inc
	src/rtos/hwthread.c
	src/target/riscv/riscv.c
	src/target/target.c

Change-Id: I62f65e10d15dcda4c405d4042cce1d96f8e1680a
This commit is contained in:
Tim Newsome 2020-12-31 13:40:49 -08:00
commit 11b8110443
212 changed files with 11818 additions and 1841 deletions

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "jimtcl"]
path = jimtcl
url = https://github.com/msteveb/jimtcl
url = https://github.com/msteveb/jimtcl.git

View File

@ -43,13 +43,14 @@ if INTERNAL_JIMTCL
AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \
-I$(top_builddir)/jimtcl
endif
EXTRA_DIST_NEWS != ls $(srcdir)/NEWS-*
EXTRA_DIST += \
BUGS \
HACKING \
NEWTAPS \
README.Windows \
README.OSX \
$(wildcard $(srcdir)/NEWS*) \
$(EXTRA_DIST_NEWS) \
Doxyfile.in \
tools/logger.pl \
tools/rlink_make_speed_table \

207
NEWS
View File

@ -2,27 +2,232 @@ This file includes highlights of the changes made in the OpenOCD
source archive release.
JTAG Layer:
* add debug level 4 for verbose I/O debug
* bitbang, add read buffer to improve performance
* Cadence SystemVerilog Direct Programming Interface (DPI) adapter driver
* CMSIS-DAP v2 (USB bulk based) adapter driver
* Cypress KitProg adapter driver
* FTDI FT232R sync bitbang adapter driver
* Linux GPIOD bitbang adapter driver through libgpiod
* Mellanox rshim USB or PCIe adapter driver
* Nuvoton Nu-Link and Nu-Link2 adapter drivers
* NXP IMX GPIO mmap based adapter driver
* ST-Link consolidate all versions in single config
* ST-Link read properly old USB serial numbers
* STLink/V3 support (for ST devices only !)
* STM8 SWIM transport
* TI XDS110 adapter driver
* Xilinx XVC/PCIe adapter driver
Boundary Scan:
Target Layer:
* 64 bit address support
* ARCv2 target support
* ARM Cortex-A hypervisor mode support
* ARM Cortex-M fast PC sampling support for profiling
* ARM generic CTI support
* ARM generic mem-ap target support
* ARMv7-A MMU tools
* ARMv7m traces add TCP stream server
* ARMv8 AARCH64 target support and semihosting support
* ARMv8 AARCH64 disassembler support through capstone library
* ARMv8-M target support
* EnSilica eSi-RISC target support, including instruction tracing
eSi-Trace support
* MIPS64 target support
* Motorola SREC S6 record image file support
* RISC-V target support
* SEGGER Real Time Transfer (RTT) initial support (for single target,
Cortex-M only)
* ST STM8 target support
* Various MIPS32 target improvements
Flash Layer:
* Atheros (ath79) SPI interface support
* Atmel atmega128rfa1 support
* Atmel SAM D21, D51, DA1, E51, E53, E54, G55, R30 support
* Atmel SAMC2?N* support
* Cypress PSoC5LP, PSoC6 support
* EnSilica eSi-RISC support
* Foshan Synwit Tech SWM050 support
* Maxim Integrated MAX32XXX support
* Nordic Semiconductor nRF51822, nRF52810, nRF52832 support
* NXP Kinetis K27, K28, KE1x, KEAx, KL28, KL8x, KV5x, KWx support
* Renesas RPC HF support
* SH QSPI support
* SiFive Freedom E support
* Silicon Labs EFR-family, EZR32HG support
* ST BlueNRG support
* ST STM32 QUAD/OCTO-SPI interface support for Flash, FRAM and EEPROM
* ST STM32F72x, STM32F4x3, STM32H7xx support
* ST STM32G0xx, STM32G4xx, STM32L4x, STM32WB, STM32WL support
* ST STM32L5x support (non secure mode)
* TI CC13xx, CC26xx, CC32xx support
* TI MSP432 support
* Winner Micro w600 support
* Xilinx XCF platform support
* Various discrete SPI NOR flashes support
Board, Target, and Interface Configuration Scripts:
* 8devices LIMA board config
* Achilles Instant-Development Kit Arria 10 board config
* Amazon Kindle 2 and DX board config
* Analog Devices ADSP-SC58x, ADSP-SC584-EZBRD board config
* Andes Technology ADP-XC7KFF676 board config
* Andes Technology Corvette-F1 board config
* ARM Musca A board config
* Arty Spartan 7 FPGA board config
* Atmel SAMD10 Xplained mini board config
* Atmel SAMD11 Xplained Pro board config
* Atmel SAM G55 Xplained Pro board config
* AVNET UltraZED EG StarterKit board config
* Blue Pill STM32F103C8 board config
* DP Busblaster v4.1a board config
* DPTechnics DPT-Board-v1 board config
* Emcraft imx8 SOM BSB board config
* Globalscale ESPRESSObin board config
* Kasli board config
* Kintex Ultrascale XCKU040 board config
* Knovative KC-100 board config
* LeMaker HiKey board config
* Microchip (Atmel) SAME54 Xplained Pro board config
* Microchip (Atmel) SAML11 Xplained Pro board config
* Nordic module NRF52 board config
* Numato Lab Mimas A7 board config
* NXP Freedom FRDM-LS1012A board config
* NXP IMX7SABRE board config
* NXP IMX8MP-EVK board config
* NXP MC-IMX8M-EVK board config
* QuickLogic QuickFeather board config
* Renesas R-Car E2, H2, M2 board config
* Renesas R-Car Salvator-X(S) board config
* Renesas RZ/A1H GR-Peach board config
* Rigado BMD-300 board config
* Sayma AMC board config
* Sifive e31arty, e51arty, hifive1 board config
* ST B-L475E-IOT01A board config
* ST BlueNRG idb007v1, idb008v1, idb011v1 board config
* ST STM32F412g discovery board config
* ST STM32F413h discovery board config
* ST STM32F469i discovery board config
* ST STM32F7 Nucleo board config
* ST STM32F723e discovery board config
* ST STM32F746g discovery board config
* ST STM32F769i discovery board config
* ST STM32H735g discovery board config
* ST STM32H743zi Nucleo board config
* ST STM32H745i discovery board config
* ST STM32H747i discovery board config
* ST STM32H750b discovery board config
* ST STM32H7b3i discovery board config
* ST STM32H7x_dual_qspi board config
* ST STM32H7x3i Eval boards config
* ST STM32L073 Nucleo board config
* ST STM32L476g discovery board config
* ST STM32L496g discovery board config
* ST STM32L4p5g discovery board config
* ST STM32L4r9i discovery board config
* ST STM32L5 Nucleo board config
* ST STM32MP15x DK2 board config
* ST STM32WB Nucleo board config
* ST STM8L152R8 Nucleo board config
* Synopsys DesignWare ARC EM board config
* Synopsys DesignWare ARC HSDK board config
* TI BeagleBone family boards config
* TI CC13xx, CC26xx, CC32xx LaunchPad board config
* TI MSP432 LaunchPad board config
* Tocoding Poplar board config
* TP-Link WDR4300 board config
* Allwinner V3s target config
* Andes Technology NDS V5 target config
* Atmel atmega128rfa1 target config
* ARM corelink SSE-200 target config
* Atheros_ar9344 target config
* Cypress PSoC5LP, PSoC6 target config
* EnSilica eSi-RISC target config
* Foshan Synwit Tech SWM050 target config
* GigaDevice GD32VF103 target config
* Hisilicon Hi3798 target config
* Hisilicon Hi6220 target config
* Infineon TLE987x target config
* Marvell Armada 3700 target config
* Maxim Integrated MAX32XXX target config
* Mellanox BlueField target config
* Microchip (Atmel) SAME5x, SAML1x target config
* NXP IMX6SX, IMX6UL, IMX7, IMX7ULP, IMX8 target config
* NXP Kinetis KE1xZ, KE1xF target config
* NXP LPC84x, LPC8Nxx, LS1012A, NHS31xx target config
* Qualcomm QCA4531 target config
* QuickLogic EOS S3 target config
* Renesas R-Car E2, H2, M2 target config
* Renesas R-Car Gen3 target config
* Renesas RZ/A1H target config
* Rockchip RK3308 target config
* ST BlueNRG target config
* ST STM32G0, STM32G4, STM32H7, STM32L0, STM32L5 target config
* ST STM32MP15x target config
* ST STM32WBx, STM32WLEx target config
* ST STM8L152, S003, S103, S105 target config
* Synopsys DesignWare ARC EM target config
* Synopsys DesignWare ARC HS Development Kit SoC target config
* TI CC13xx, CC26xx, CC32xx target config
* TI TNETC4401 target config
* Xilinx UltraScale+ target config
* Altera 5M570Z (MAXV family) CPLD config
* Xilinx Ultrascale, XCF CPLD config
* Intel (Altera) Arria10 FPGA config
* Cadence SystemVerilog Direct Programming Interface (DPI) interface config
* Cypress KitProg interface config
* Digilent SMT2 NC interface config
* DLN-2 example of Linux GPIOD interface config
* FTDI C232HM interface config
* HIE JTAG Debugger interface config
* In-Circuit's ICprog interface config
* isodebug isolated JTAG/SWD+UART interface config
* Mellanox rshim USB or PCIe interface config
* Nuvoton Nu-Link interface config
* NXP IMX GPIO mmap based interface config
* Steppenprobe open hardware interface config
* TI XDS110 interface config
Server Layer:
* 64 bit address support
* default bind to IPv4 localhost
* gdb: allow multiple connections
* gdb: architecture element support
* gdb: vCont, vRun support
* telnet: handle Ctrl+A, Ctrl+E and Ctrl+K
RTOS:
* Chromium-EC rtos support
* hwthread pseudo rtos support
* NuttX rtos support
* RIOT rtos support
Documentation:
* Improve STM32 flash driver
* Various typo fix and improvements
Build and Release:
* Add libutil to support jimtcl version 0.80
* Clang warning fixes
* GitHub workflow for Win32 snapshot binaries
* Handle Tcl return values consistently
* Mitigation for CVE-2018-5704: Prevent some forms of Cross
Protocol Scripting attacks
* Support for libftdi 1.5
* Travis-CI basic support
* Update libjaylink to version 0.2.0
* Update jimtcl to version 0.79
* Use external (optional) library capstone for ARM and AARCH64 disassembly
This release also contains a number of other important functional and
cosmetic bugfixes. For more details about what has changed since the
last release, see the git repository history:
http://sourceforge.net/p/openocd/code/ci/v0.x.0/log/?path=
http://sourceforge.net/p/openocd/code/ci/v0.11.0-rc1/log/?path=
For older NEWS, see the NEWS files associated with each release

View File

@ -1,7 +1,8 @@
AC_PREREQ(2.64)
AC_INIT([openocd], [0.10.0+dev],
AC_INIT([openocd], [0.11.0-rc1+dev],
[OpenOCD Mailing List <openocd-devel@lists.sourceforge.net>])
AC_CONFIG_SRCDIR([src/openocd.c])
AC_CONFIG_AUX_DIR([.])
m4_include([config_subdir.m4])dnl
@ -43,6 +44,7 @@ AC_TYPE_LONG_LONG_INT
AC_SEARCH_LIBS([ioperm], [ioperm])
AC_SEARCH_LIBS([dlopen], [dl])
AC_SEARCH_LIBS([openpty], [util])
AC_CHECK_HEADERS([sys/socket.h])
AC_CHECK_HEADERS([elf.h])
@ -118,6 +120,7 @@ m4_define([USB1_ADAPTERS],
[[ft232r], [Bitbang mode of FT232R based devices], [FT232R]],
[[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]],
[[xds110], [TI XDS110 Debug Probe], [XDS110]],
[[cmsis_dap_v2], [CMSIS-DAP v2 Compliant Debugger], [CMSIS_DAP_USB]],
[[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],
[[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]],
[[aice], [Andes JTAG Programmer], [AICE]]])
@ -128,7 +131,7 @@ m4_define([USB0_ADAPTERS],
[[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]]])
m4_define([HIDAPI_ADAPTERS],
[[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP]],
[[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]],
[[nulink], [Nu-Link Programmer], [HLADAPTER_NULINK]]])
m4_define([HIDAPI_USB1_ADAPTERS],
@ -669,7 +672,11 @@ for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do
])
done
PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [use_libftdi=yes], [
PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [
use_libftdi=yes
PKG_CHECK_EXISTS([libftdi1 >= 1.5],
[AC_DEFINE([HAVE_LIBFTDI_TCIOFLUSH], [1], [Define if your libftdi has ftdi_tcioflush()])])
], [
PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no])
])
@ -827,6 +834,7 @@ AS_IF([test "x${gcc_wextra}" = "xyes"], [
GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast"
GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align"
GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls"
GCC_WARNINGS="${GCC_WARNINGS} -Wpointer-arith"
])
AS_IF([test "x${gcc_werror}" = "xyes"], [
GCC_WARNINGS="${GCC_WARNINGS} -Werror"

View File

@ -167,6 +167,7 @@ ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev",
# Keil Software, Inc. ULink
ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2750", MODE="660", GROUP="plugdev", TAG+="uaccess"
# CMSIS-DAP compatible adapters
ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess"

View File

@ -14,8 +14,8 @@
# paths refer to the build file system.
#
# This script is probably more useful as a reference than as a complete build
# tool but for some configurations it may be usable as-is. It only cross-
# builds libusb-1.0, hidapi and libftdi from source, but the script can be
# tool but for some configurations it may be usable as-is. It only cross-builds
# libusb-1.0, hidapi, libftdi and capstone from source, but the script can be
# extended to build other prerequisites in a similar manner.
#
# Usage:
@ -39,17 +39,20 @@ WORK_DIR=$PWD
: ${LIBUSB1_SRC:=/path/to/libusb1}
: ${HIDAPI_SRC:=/path/to/hidapi}
: ${LIBFTDI_SRC:=/path/to/libftdi}
: ${CAPSTONE_SRC:=/path/to/capstone}
OPENOCD_SRC=`readlink -m $OPENOCD_SRC`
LIBUSB1_SRC=`readlink -m $LIBUSB1_SRC`
HIDAPI_SRC=`readlink -m $HIDAPI_SRC`
LIBFTDI_SRC=`readlink -m $LIBFTDI_SRC`
CAPSTONE_SRC=`readlink -m $CAPSTONE_SRC`
HOST_TRIPLET=$1
BUILD_DIR=$WORK_DIR/$HOST_TRIPLET-build
LIBUSB1_BUILD_DIR=$BUILD_DIR/libusb1
HIDAPI_BUILD_DIR=$BUILD_DIR/hidapi
LIBFTDI_BUILD_DIR=$BUILD_DIR/libftdi
CAPSTONE_BUILD_DIR=$BUILD_DIR/capstone
OPENOCD_BUILD_DIR=$BUILD_DIR/openocd
## Root of host file tree
@ -129,6 +132,26 @@ if [ -d $LIBFTDI_SRC ] ; then
make install DESTDIR=$SYSROOT
fi
# capstone build & install into sysroot
if [ -d $CAPSTONE_SRC ] ; then
mkdir -p $CAPSTONE_BUILD_DIR
cd $CAPSTONE_BUILD_DIR
cp -r $CAPSTONE_SRC/* .
make install DESTDIR=$SYSROOT PREFIX=$PREFIX \
CROSS="${HOST_TRIPLET}-" \
$CAPSTONE_CONFIG
# fix the generated capstone.pc
CAPSTONE_PC_FILE=${SYSROOT}${PREFIX}/lib/pkgconfig/capstone.pc
sed -i '/^libdir=/d' $CAPSTONE_PC_FILE
sed -i '/^includedir=/d' $CAPSTONE_PC_FILE
sed -i '/^archive=/d' $CAPSTONE_PC_FILE
sed -i '1s;^;prefix=/usr \
exec_prefix=${prefix} \
libdir=${exec_prefix}/lib \
includedir=${prefix}/include\n\n;' $CAPSTONE_PC_FILE
fi
# OpenOCD build & install into sysroot
mkdir -p $OPENOCD_BUILD_DIR
cd $OPENOCD_BUILD_DIR

View File

@ -0,0 +1,34 @@
BIN2C = ../../../../src/helper/bin2char.sh
SRCS=stmqspi_erase_check.S stmqspi_crc32.S stmqspi_read.S stmqspi_write.S \
stmoctospi_erase_check.S stmoctospi_crc32.S stmoctospi_read.S stmoctospi_write.S
OBJS=$(patsubst %.S,%.inc,$(SRCS))
CROSS_COMPILE ?= arm-none-eabi-
CC=$(CROSS_COMPILE)gcc
OBJCOPY=$(CROSS_COMPILE)objcopy
OBJDUMP=$(CROSS_COMPILE)objdump
LD=$(CROSS_COMPILE)ld
all: $(OBJS)
%.o: %.S Makefile
$(CC) -Wall -Werror -Wa,-adhlmn -o $@ -c $< > $(@:.o=.lst)
@enscript -Easm -T 4 -G -o - $(@:.o=.lst) | ps2pdf - $(@:.o=.pdf) || true
%.elf: %.o
$(LD) -s -defsym=_start=0 -o $@ $<
%.bin: %.elf
$(OBJCOPY) -S -O binary $< $@
%.inc: %.bin
$(BIN2C) < $< > $@
clean:
-rm -f *.o *.elf *.lst *.pdf *.bin *.inc
.PHONY: all clean
.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS))

View File

@ -0,0 +1,679 @@
#!/usr/bin/perl
#
# Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+
# and F1 (for 'stmqspi' and 'cmspi' drivers).
#
# Each pin is configured by "PortAndBit:Conf:Speed"
# 'PortAndBit' specifies Port and bit number
# 'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input),
# (each optionally by 'P' (push-pull) or 'O' (open-drain)),
# (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down))
# 'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high)
#
# Port configuration can be given on command line as a single string (pins separated by commas)
# or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the
# corresponding header. The precise spelling in these files doesn't seem to be consistent, though ...
#
# Pins have to be ordered this way:
# - I2C: SDA, SCL
# - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI
# - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI
# - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI
# For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2
# For octal flash: NCS, CLK, DQS, IO7 down to IO0
use strict;
use Getopt::Std;
my $GPIO_BASE;
my $Conf;
my $STM32F1 = 0;
# "Blue-Pill stm32f103cbt6 board w/ cmspi
#$STM32F1 = 1;
#$GPIO_BASE = 0x40010800;
#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V";
#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V";
#$STM32F1 = 1;
#$GPIO_BASE = 0x40010800;
#$Conf = "PB07:INUP:V, PB06:INUP:V";
# mini-stm32f030f4p6 board w/ cmspi
#$GPIO_BASE = 0x48000000;
#$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V";
# stm32f407vet6 board w/ cmspi
#$GPIO_BASE = 0x40020000;
#$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V";
# stm32f412g-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V";
# stm32f413h-disco
#$GPIO_BASE = 0x40020000;
#$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V";
# stm32f469i-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V";
# w/ cmspi
#$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V";
# stm32f723e-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
# stm32f746g-disco quad
#$GPIO_BASE = 0x40020000;
#Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
# w/ cmspi
#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V";
# stm32f769i-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
# w/ cmspi
#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, ";
# b-l475e-iot01a quad
#$GPIO_BASE = 0x48000000;
#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
# stm32l476g-disco quad
#$GPIO_BASE = 0x48000000;
#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
# stm32l496g-disco quad
#$GPIO_BASE = 0x48000000;
#$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V";
# stm32l4r9i-disco octal
#$GPIO_BASE = 0x48000000;
#$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, "
# . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V";
# stm32l4p5g-disco octal/octal
#$GPIO_BASE = 0x48000000;
#$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, "
# . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V";
#$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, "
# . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V";
# nucleo-f767zi dual quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
# w/ cmspi
#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
# nucleo-h743zi dual quad
#$GPIO_BASE = 0x58020000;
#$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
# w/ cmspi
#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
# nucleo-h7a3zi dual quad
#$GPIO_BASE = 0x58020000;
#$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, "
# . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V";
# w/ cmspi
#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
# nucleo-l4r5zi one dual quad single NCS
#$GPIO_BASE = 0x48000000;
#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
# w/ cmspi
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
# nucleo-l552ze-q dual quad with single NCS
#$GPIO_BASE = 0x42020000;
#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
# w/ cmspi
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
# nucleo-g071rb dual quad
#$GPIO_BASE = 0x50000000;
#$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H";
#$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V";
# nucleo-g474re dual quad with single NCS
#$GPIO_BASE = 0x48000000;
#$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, "
# . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V";
# w/ cmspi
#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V";
#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V";
# stm32h745i-disco dual quad with single NCS
#$GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
# stm32h747i-disco dual quad with single NCS
#GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
# stm32h7b3i-disco octal
#$GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, "
# . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V";
# stm32h735g-disco octal
#$GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, "
# . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
# stm32l562e-disco octal
#$GPIO_BASE = 0x42020000;
#$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, "
# . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V";
&getopts('b:c:f:t');
if ($Getopt::Std::opt_b eq '')
{
if ($GPIO_BASE eq '')
{
die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]");
}
}
else
{
$GPIO_BASE = eval $Getopt::Std::opt_b;
}
if ($Getopt::Std::opt_c eq '')
{
if (($Conf eq '') && ($Getopt::Std::opt_f eq ''))
{
die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )");
}
}#
else
{
$Conf = $Getopt::Std::opt_c . ',';
}
$STM32F1 = $Getopt::Std::opt_t;
my $Sep = "\t";
my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# ";
my $GPIO_OFFS;
my $GPIO_CRL;
my $GPIO_CRH;
my $GPIO_MODER;
my $GPIO_OTYPER;
my $GPIO_OSPEEDR;
my $GPIO_PUPDR;
my $GPIO_IDR;
my $GPIO_ODR;
my $GPIO_AFRL;
my $GPIO_AFRH;
if ($STM32F1)
{
# offsets for F1 devices
$GPIO_OFFS = 0x400;
$GPIO_CRL = 0x00;
$GPIO_CRH = 0x04;
$GPIO_IDR = 0x08;
$GPIO_ODR = 0x0C;
}
else
{
# these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now
$GPIO_OFFS = 0x400;
$GPIO_MODER = 0x00;
$GPIO_OTYPER = 0x04;
$GPIO_OSPEEDR = 0x08;
$GPIO_PUPDR = 0x0C;
$GPIO_IDR = 0x10;
$GPIO_ODR = 0x14;
$GPIO_AFRL = 0x20;
$GPIO_AFRH = 0x24;
}
my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } );
my @Port = ( );
my $Exor;
my %Conf;
my $Pins = "${Sep}#";
my $pins;
my $altn;
my %defs;
if ($Getopt::Std::opt_f ne '')
{
open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f");
while (my $line = <CONF_FILE>)
{
if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/)
{
if ($line =~ /#define\s+(\w+)\s+(\w+)/)
{
$defs{$1} = $2;
}
else
{
die($line);
}
}
elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/)
{
$Conf{$4} = sprintf("%s%02d", $1, $2);
}
elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/)
{
$pins = $1;
while ($line !~ /;/)
{
$line = <CONF_FILE>;
$line =~ /^\s*([^;]+\w)/;
$pins .= $1;
}
}
elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/)
{
$altn = $1;
}
elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/)
{
my $port = $1;
if ($port =~ /GPIO([A-Z])/)
{
$port = $1;
}
elsif (exists($defs{$port}))
{
$defs{$port} =~ /GPIO([A-Z])/;
$port = $1;
}
else
{
printf("\n");
next;
}
my @pin = split(/\s*\|\s*/, $pins);
foreach my $pin (@pin)
{
my $bit;
if (exists($defs{$pin}))
{
$defs{$pin} =~ /GPIO_PIN_([0-9]+)/;
$bit = $1;
}
else
{
$pin =~ /GPIO_PIN_([0-9]+)/;
$bit = $1;
}
$Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn);
}
$pins = '';
$altn = 0;
}
}
close(CONF_FILE);
}
else
{
my @names = ( );
my @conf = split(/\s*,\s*/, $Conf);
if (@conf == 2)
{
push(@names, 'SDA', 'SCL');
} else {
if (@conf == 3)
{
push(@names, 'NCS', 'CLK', 'IO0/DIO');
}
elsif (@conf == 4)
{
push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI');
}
elsif (@conf == 6)
{
push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI');
}
elsif (@conf == 10)
{
push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
}
elsif (@conf == 11)
{
push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
}
else
{
die("invalid config");
}
}
for (my $index = 0; $index < @conf; $index++)
{
uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
$Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2);
}
chop($Pins);
}
if (exists $Conf{'BK1_IO0'})
{
# QuadSPI on F4, F7, H7
my $line;
for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
if (exists $Conf{'BK2_IO0'})
{
# QuadSPI on F4, F7, H7
my $line;
for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
if (exists $Conf{'P1_IO0'})
{
# OctoSPI on L4+, L5, H7
my $line;
for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4',
'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
if (exists $Conf{'P2_IO0'})
{
# OctoSPI on L4+, H7
my $line;
for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4',
'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
my @Col = ( );
my @conf = split(/\s*,\s*/, $Conf);
if (@conf == 3)
{
splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE');
}
elsif (@conf == 4)
{
splice(@conf, 2, 0, 'NONE', 'NONE');
}
foreach my $line (@conf)
{
$line = uc($line);
$line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
my $port = $1;
my $pin = $2;
my $conf = $3;
my $speed = $4;
my $MODER = 0x0;
my $OTYPER = 0x0;
my $OSPEEDR = 0x0;
my $PUPDR = 0x0;
my $AFR = 0x0;
my $num = ord(${port}) - ord('A');
my $out = $Out[$num];
(exists $$out{'DEF'}) || ($$out{'DEF'} = 0);
if ($conf eq '')
{
if ($line ne 'NONE')
{
printf(STDERR "invalid conf %s\n", $line);
}
next;
}
elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/)
{
if ($STM32F1)
{
printf(STDERR "no alternate %s for F1 family\n", $line);
next;
}
if (($1 < 0) || ($1 > 15))
{
printf(STDERR "invalid alternate %s\n", $line);
next;
}
$MODER = 0x2;
$AFR = $1;
if ($pin <= 7)
{
$$out{'AFRL_H'} |= ($AFR << (${pin} << 2));
$$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2));
}
else
{
$$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2));
$$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2));
}
if ($2 ne '') {
$OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
$$out{'OTYPER_H'} |= ($OTYPER << $pin);
$$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
}
$PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0);
$$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
$$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
$conf = sprintf("AF%02d%s%s", $AFR, $2, $3);
}
elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/)
{
if ($STM32F1)
{
$MODER = ($1 eq '') ? 0x4 : 0x8;
($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin}));
($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin}));
}
else
{
$MODER = 0x0;
if ($1 ne '')
{
$OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
$$out{'OTYPER_H'} |= ($OTYPER << $pin);
$$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
}
$PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
$$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
$$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
}
($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
}
elsif ($conf =~ /^P(P|O)(|UP|DO)$/)
{
if ($STM32F1)
{
$MODER = ($1 eq 'O') ? 0x4 : 0x0;
$MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1));
if ($2 ne '')
{
printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line);
}
}
else
{
$MODER = 0x1;
$OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
$$out{'OTYPER_H'} |= ($OTYPER << $pin);
$$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
$PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
$$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1));
$$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1));
}
($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
}
else
{
printf(STDERR "invalid conf %s\n", $line);
next;
}
if ($$out{'DEF'} & (1<< ${pin}))
{
printf(STDERR "redefinition: %s\n", $line);
}
if ($STM32F1)
{
if ($pin >= 8)
{
$$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2));
$$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
}
else
{
$$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2));
$$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
}
$Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
my $exor = 0xB << (($pin & 0x7) << 2);
(($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X",
((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF,
((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor));
}
else
{
$$out{'DEF'} |= (1 << ${pin});
$$out{'MODER_H'} |= ($MODER << (${pin} << 1));
$$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1));
$OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0)));
$$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1));
$$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1));
$Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
my $exor = (0x1 << ($pin << 1));
($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF,
(${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor));
}
push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed));
push(@Col, $Exor);
}
my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF);
for (my $i = 0; $i < @Col; $i++)
{
if (($i != 0) && (($i % 2) == 0))
{
(($i + 1) < @Col) && ($Col .= "\\\n${Sep}");
}
$Col .= sprintf("%s ", $Col[$i]);
}
printf("%s\n", $Col);
my @Col = ( );
my $Set;
for (my $i = 0; $i < @Out; $i++)
{
my $out = $Out[$i];
my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS};
my $count = 0;
if ($STM32F1)
{
if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} |
$$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0)
{
push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
$Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
join(", ", sort({ $b cmp $a } @{$Port[$i]})));
(($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) &&
($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'}));
(($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) &&
($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'}));
(($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
}
}
else
{
if (($$out{'MODER_H'} | $$out{'MODER_L'} |
$$out{'OTYPER_H'} | $$out{'OTYPER_L'} |
$$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} |
$$out{'PUPDR_H'} | $$out{'PUPDR_L'} |
$$out{'ODR_H'} | $$out{'ODR_L'} |
$$out{'AFRL_H'} | $$out{'AFRL_L'} |
$$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0)
{
push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
$Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
join(", ", sort({ $b cmp $a } @{$Port[$i]})));
(($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) &&
($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'}));
(($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) &&
($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'}));
(($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) &&
($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'}));
(($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) &&
($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'}));
(($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
(($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) &&
($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'}));
(($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) &&
($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'}));
}
}
}
my $Col = '';
for (my $i = 0; $i < @Col; $i++)
{
if (($i % 6) == 0)
{
chop($Col);
(($i + 1) < @Col) && ($Col .= "\n${Sep}#");
}
$Col .= sprintf(" %s,", $Col[$i]);
}
chop($Col);
#printf("\n%s\n", $Pins);
printf("%s\n", $Col);
printf("%s\n", $Set);

View File

@ -0,0 +1,123 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), crc32 (out)
* r1 - flash page size
* r2 - address offset into flash
* r3 - OCTOSPI io_base
* Clobbered:
* r4 - tmp
* r5 - address of OCTOSPI_DR
* r6 - address of OCTOSPI_CCR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
movs r4, #0x00 /* initialize crc */
mvns r4, r4 /* to 0xFFFFFFFF */
start_read:
octospi_abort /* start in clean state */
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r5, r5, r3 /* address of OCTOSPI_DR */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r5 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_page_read /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then read to end of page */
mov r7, r0 /* else read all remaining */
write_dlr:
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_read /* TCR for read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_read /* IR for read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
ldr r6, =0x04C11DB7 /* CRC32 polynomial */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
lsls r7, r7, #24 /* shift into msb */
eors r4, r4, r7
.rept 8 /* unrolled bit loop */
asrs r7, r4, #31 /* copy bit 31 into bits 0 to 31 */
ands r7, r7, r6 /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
lsls r4, r4, #1 /* shift result */
eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */
.endr
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
.pool
exit:
mvns r0, r4 /* invert to get final result */
octospi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
cr_page_read:
.space 4 /* OCTOSPI_CR value for read command */
ccr_page_read:
.space 4 /* OCTOSPI_CCR value for read command */
tcr_page_read:
.space 4 /* OCTOSPI_TCR value for read command */
ir_page_read:
.space 4 /* OCTOSPI_IR value for read command */

View File

@ -0,0 +1,13 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,
0x5f,0x62,0x22,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,
0x07,0x46,0x1f,0x64,0x1e,0x4f,0x37,0x60,0x1e,0x4f,0xb7,0x60,0x1e,0x4f,0x37,0x61,
0x9a,0x64,0x15,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,0x05,0xd4,
0x0a,0x42,0xd7,0xd1,0xb8,0xe7,0x00,0x00,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,108 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - sector count
* r1 - QSPI io_base
* Clobbered:
* r2 - r7 tmp */
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r1, #OCTOSPI_CR] /* get OCTOSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r1, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r1, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r1, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
adr r2, buffer /* pointer to start of buffer */
movs r3, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r3, r3, r1 /* address of OCTOSPI_DR */
sector_start:
octospi_abort /* start in clean state */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r3 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_page_read /* indirect read mode */
str r7, [r1, #OCTOSPI_CR] /* set mode */
ldmia r2!, {r4, r5} /* load address offset, length */
subs r2, r2, #4 /* point to length */
subs r5, r5, #1 /* decrement sector length for DLR */
str r5, [r1, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_read /* TCR for read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_read /* IR for read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r4, [r1, #OCTOSPI_AR] /* store SPI start address */
ldr r6, [r2, #4] /* load initial value */
read_loop:
ldrb r4, [r3, #0] /* read next byte from DR */
movs r7, #0xFF /* fill bits 8-15 */
lsls r7, r7, #8 /* with ones */
orrs r4, r4, r7 /* copy ones to left of read byte */
ands r6, r6, r4 /* and read byte to result */
lsls r4, r4, #8 /* shift result into higher byte */
orrs r6, r6, r4 /* or read byte to result */
subs r5, r5, #1 /* decrement byte (count-1) */
bpl read_loop /* again if sector not completed */
adds r5, r5, #1 /* increment count due to the -1 */
stmia r2!, {r5, r6} /* save final count and result for sector */
subs r0, r0, #1 /* decrement sector count */
bne sector_start /* next sector? */
octospi_abort /* to idle state */
exit:
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
cr_page_read:
.space 4 /* OCTOSPI_CR value for read command */
ccr_page_read:
.space 4 /* OCTOSPI_CCR value for read command */
tcr_page_read:
.space 4 /* OCTOSPI_TCR value for read command */
ir_page_read:
.space 4 /* OCTOSPI_IR value for read command */
.equ buffer, .

View File

@ -0,0 +1,8 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x1b,0xa2,0x50,0x23,0x5b,0x18,0x02,0x25,0x0f,0x68,0x2f,0x43,0x0f,0x60,0xb0,0x26,
0xf6,0x18,0x0f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x4f,0x62,0x10,0x4f,0x0f,0x60,
0x30,0xca,0x04,0x3a,0x01,0x3d,0x0d,0x64,0x0e,0x4f,0x37,0x60,0x0e,0x4f,0xb7,0x60,
0x0e,0x4f,0x37,0x61,0x8c,0x64,0x56,0x68,0x1c,0x78,0xff,0x27,0x3f,0x02,0x3c,0x43,
0x26,0x40,0x24,0x02,0x26,0x43,0x01,0x3d,0xf6,0xd5,0x01,0x35,0x60,0xc2,0x01,0x38,
0xd9,0xd1,0x02,0x25,0x0f,0x68,0x2f,0x43,0x0f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,142 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - OCTOSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - wp
* r5 - address of OCTOSPI_DR
* r6 - address of OCTOSPI_CCR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, wp /* load wp */
start_read:
octospi_abort /* start in clean state */
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r5, r5, r3 /* address of OCTOSPI_DR */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r5 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_page_read /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then write to end of page */
mov r7, r0 /* else write all remaining */
write_dlr:
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_read /* TCR for read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_read /* IR for read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
strb r7, [r4, #0] /* write next byte */
adds r4, r4, #1 /* increment internal wp */
cmp r4, r9 /* internal wp beyond end? */
blo wait_fifo /* if no, then ok */
mov r4, r8 /* else wrap around */
wait_fifo:
ldr r7, rp /* get rp */
cmp r7, #0 /* if rp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo full */
beq wait_fifo /* wait until not full */
adr r7, wp /* get address of wp */
str r4, [r7] /* store updated wp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
octospi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
cr_page_read:
.space 4 /* OCTOSPI_CR value for read command */
ccr_page_read:
.space 4 /* OCTOSPI_CCR value for read command */
tcr_page_read:
.space 4 /* OCTOSPI_TCR value for read command */
ir_page_read:
.space 4 /* OCTOSPI_IR value for read command */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,12 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x27,0x4c,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x50,0x25,
0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,
0x1c,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,
0x1f,0x64,0x19,0x4f,0x37,0x60,0x19,0x4f,0xb7,0x60,0x19,0x4f,0x37,0x61,0x9a,0x64,
0x2f,0x78,0x27,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x16,0x4f,0x00,0x2f,
0x09,0xd0,0xbc,0x42,0xfa,0xd0,0x13,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,0x02,0xd4,
0x0a,0x42,0xed,0xd1,0xcf,0xe7,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,219 @@
/***************************************************************************
* Copyright (C) 2018 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - OCTOSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - rp
* r5 - address of OCTOSPI_DR
* r6 - address of OCTOSPI_CCR
* r7 - tmp
* r10 - single 0x0 / dual 0x1
*/
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, rp /* load rp */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI_CR register */
lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
mov r10, r7 /* save in r10 */
wip_loop:
octospi_abort /* start in clean state */
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r5, r5, r3 /* address of OCTOSPI_DR */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r5 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_read_status /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r10 /* get dual bit */
str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
ldr r7, tcr_read_status /* TCR for status read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_read_status /* IR for status read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
movs r7, #0 /* dummy address */
str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
bcs wip_loop /* then poll again */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq write_enable /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
bcs wip_loop /* then poll again */
write_enable:
tst r0, r0 /* test residual count */
bmi exit /* if negative, then finished */
wait_busy
ldr r7, cr_write_enable /* indirect write mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
ldr r7, ccr_write_enable /* CCR for write enable */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate write enable */
ldr r7, tcr_write_enable /* TCR for write enable */
str r7, [r6, #OCTOSPI_TCR_CCR] /* write enable instruction */
ldr r7, ir_write_enable /* IR for write enable */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
movs r7, #0 /* silicon bug in L5? dummy write */
str r7, [r3, #OCTOSPI_AR] /* into AR resolves issue */
wait_busy
ldr r7, cr_read_status /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r10 /* get dual count */
str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
ldr r7, tcr_read_status /* TCR for status read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_read_status /* IR for status read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
movs r7, #0 /* dummy address */
str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
bcc error /* write enabled, then error */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq start_write /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
bcc error /* write enabled, then error */
start_write:
wait_busy
ldr r7, cr_page_write /* indirect write mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then write to end of page */
mov r7, r0 /* else write all remaining */
write_dlr:
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_write /* CCR for page write */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_write /* TCR for page write */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_write /* IR for page write */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
write_loop:
ldr r7, wp /* get wp */
cmp r7, #0 /* if wp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo empty */
beq write_loop /* wait until not empty */
ldrb r7, [r4, #0] /* read next byte */
strb r7, [r5] /* write next byte to DR */
adds r4, r4, #1 /* increment internal rp */
cmp r4, r9 /* internal rp beyond end? */
blo upd_write /* if no, then ok */
mov r4, r8 /* else wrap around */
upd_write:
adr r7, rp /* get address of rp */
str r4, [r7] /* store updated rp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi page_end /* stop if no data left */
tst r2, r1 /* page end ? */
bne write_loop /* if not, then next byte */
page_end:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
bcc page_end /* loop until TCF set */
bal wip_loop /* then next page */
error:
movs r0, #0 /* return 0xFFFFFFFF */
subs r0, r0, #2 /* for error */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
octospi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
cr_read_status:
.space 4 /* OCTOSPI_CR value for READ_STATUS command */
ccr_read_status:
.space 4 /* OCTOSPI_CCR value for READ_STATUS command */
tcr_read_status:
.space 4 /* OCTOSPI_TCR value for READ_STATUS command */
ir_read_status:
.space 4 /* OCTOSPI_IR value for READ_STATUS command */
cr_write_enable:
.space 4 /* OCTOSPI_CR value for WRITE_ENABLE command */
ccr_write_enable:
.space 4 /* OCTOSPI_CCR value for WRITE_ENABLE command */
tcr_write_enable:
.space 4 /* OCTOSPI_TCR value for WRITE_ENABLE command */
ir_write_enable:
.space 4 /* OCTOSPI_IR value for WRITE_ENABLE command */
cr_page_write:
.space 4 /* OCTOSPI_CR value for PAGE_PROG command */
ccr_page_write:
.space 4 /* OCTOSPI_CCR value for PAGE_PROG command */
tcr_page_write:
.space 4 /* OCTOSPI_TCR value for PAGE_PROG command */
ir_page_write:
.space 4 /* OCTOSPI_IR value for PAGE_PROG command */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,21 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x4f,0x4c,0x1f,0x68,0x7f,0x06,0xff,0x0f,0xba,0x46,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,
0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,0x39,0x4f,0x1f,0x60,0x57,0x46,0x1f,0x64,
0x38,0x4f,0x37,0x60,0x38,0x4f,0xb7,0x60,0x38,0x4f,0x37,0x61,0x00,0x27,0x9f,0x64,
0x2f,0x78,0x7f,0x08,0xe3,0xd2,0x57,0x46,0x3f,0x42,0x02,0xd0,0x2f,0x78,0x7f,0x08,
0xdd,0xd2,0x00,0x42,0x55,0xd4,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,
0x2f,0x4f,0x1f,0x60,0x2f,0x4f,0x37,0x60,0x2f,0x4f,0xb7,0x60,0x2f,0x4f,0x37,0x61,
0x00,0x27,0x9f,0x64,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,0x24,0x4f,
0x1f,0x60,0x57,0x46,0x1f,0x64,0x23,0x4f,0x37,0x60,0x23,0x4f,0xb7,0x60,0x23,0x4f,
0x37,0x61,0x00,0x27,0x9f,0x64,0x2f,0x78,0xbf,0x08,0x30,0xd3,0x57,0x46,0x3f,0x42,
0x02,0xd0,0x2f,0x78,0xbf,0x08,0x2a,0xd3,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,
0x5f,0x62,0x1f,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,
0x07,0x46,0x1f,0x64,0x1b,0x4f,0x37,0x60,0x1b,0x4f,0xb7,0x60,0x1b,0x4f,0x37,0x61,
0x9a,0x64,0x1b,0x4f,0x00,0x2f,0x14,0xd0,0xbc,0x42,0xfa,0xd0,0x27,0x78,0x2f,0x70,
0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x16,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,
0x01,0xd4,0x0a,0x42,0xed,0xd1,0x1f,0x6a,0xbf,0x08,0xfc,0xd3,0x87,0xe7,0x00,0x20,
0x02,0x38,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x00,0xbe,0xc0,0x46,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,108 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), crc32 (out)
* r1 - flash page size
* r2 - address offset into flash
* r3 - QSPI io_base
* Clobbered:
* r4 - rp
* r5 - address of QSPI_DR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
movs r4, #0x00 /* initialize crc */
mvns r4, r4 /* to 0xFFFFFFFF */
start_read:
qspi_abort /* start in clean state */
movs r5, #QSPI_DR /* load QSPI_DR address offset */
adds r5, r5, r3 /* address of QSPI_DR */
wait_busy
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then read to end of page */
mov r7, r0 /* else read all remaining */
write_dlr:
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for page read */
str r7, [r3, #QSPI_CCR] /* initiate transfer */
str r2, [r3, #QSPI_AR] /* store SPI start address */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
ldr r6, =0x04C11DB7 /* CRC32 polynomial */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
lsls r7, r7, #24 /* shift into msb */
eors r4, r4, r7
.rept 8 /* unrolled bit loop */
asrs r7, r4, #31 /* copy bit 31 into bits 0 to 31 */
ands r7, r7, r6 /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
lsls r4, r4, #1 /* shift result */
eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */
.endr
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
.pool
exit:
mvns r0, r4 /* invert to get final result */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
ccr_page_read:
.space 4 /* QSPI_CCR value for read command */
.space 4 /* not used */
.space 4 /* not used */

View File

@ -0,0 +1,12 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46,
0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x1c,0x4f,0x5f,0x61,
0x9a,0x61,0x9f,0x68,0x14,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,
0x04,0xd4,0x0a,0x42,0xd7,0xd1,0xbf,0xe7,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,91 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - sector count
* r1 - QSPI io_base
* Clobbered:
* r2 - r7 tmp */
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r4, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r1, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r4 /* set abort bit */
str r7, [r1, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r1, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r1, #QSPI_FCR] /* clear TCF flag */
.endm
start:
adr r2, buffer /* pointer to start of buffer */
movs r3, #QSPI_DR /* load QSPI_DR address offset */
add r3, r3, r1 /* address of QSPI_DR */
sector_start:
qspi_abort /* start in clean state */
ldmia r2!, {r4, r5, r6} /* load address offset, length, initial value */
subs r2, r2, #8 /* point to length */
subs r5, r5, #1 /* decrement sector length for DLR */
wait_busy
str r5, [r1, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for page read */
str r7, [r1, #QSPI_CCR] /* initiate transfer */
str r4, [r1, #QSPI_AR] /* store SPI start address */
ldr r7, [r1, #QSPI_SR] /* wait for command startup */
read_loop:
ldrb r4, [r3] /* read next byte from DR */
movs r7, #0xFF /* fill bits 8-15 */
lsls r7, r7, #8 /* with ones */
orrs r4, r4, r7 /* copy ones to left of read byte */
ands r6, r6, r4 /* and read byte to result */
lsls r4, r4, #8 /* shift result into higher byte */
orrs r6, r6, r4 /* or read byte to result */
subs r5, r5, #1 /* decrement byte (count-1) */
bpl read_loop /* again if sector not completed */
adds r5, r5, #1 /* increment count due to the -1 */
stmia r2!, {r5, r6} /* save final count and result for sector */
subs r0, r0, #1 /* decrement sector count */
bne sector_start /* next sector? */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
ccr_page_read:
.space 4 /* QSPI_CCR value for read command */
.space 4 /* not used */
.space 4 /* not used */
.equ buffer, .

View File

@ -0,0 +1,7 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x17,0xa2,0x20,0x23,0x0b,0x44,0x02,0x24,0x0f,0x68,0x27,0x43,0x0f,0x60,0x70,0xca,
0x08,0x3a,0x01,0x3d,0x8f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xcf,0x60,0x0d,0x61,
0x0c,0x4f,0x4f,0x61,0x8c,0x61,0x8f,0x68,0x1c,0x78,0xff,0x27,0x3f,0x02,0x3c,0x43,
0x26,0x40,0x24,0x02,0x26,0x43,0x01,0x3d,0xf6,0xd5,0x01,0x35,0x60,0xc2,0x01,0x38,
0xe1,0xd1,0x02,0x24,0x0f,0x68,0x27,0x43,0x0f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,127 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - QSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - wp
* r5 - address of QSPI_DR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, wp /* load wp */
start_read:
qspi_abort /* start in clean state */
movs r5, #QSPI_DR /* load QSPI_DR address offset */
adds r5, r5, r3 /* address of QSPI_DR */
wait_busy
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then read to end of page */
mov r7, r0 /* else read all remaining */
write_dlr:
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for page read */
str r7, [r3, #QSPI_CCR] /* initiate transfer */
str r2, [r3, #QSPI_AR] /* store SPI start address */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
strb r7, [r4, #0] /* write next byte */
adds r4, r4, #1 /* increment internal wp */
cmp r4, r9 /* internal wp beyond end? */
blo wait_fifo /* if no, then ok */
mov r4, r8 /* else wrap around */
wait_fifo:
ldr r7, rp /* get rp */
cmp r7, #0 /* if rp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo full */
beq wait_fifo /* wait until not full */
adr r7, wp /* get address of wp */
str r4, [r7] /* store updated wp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
ccr_page_read:
.space 4 /* QSPI_CCR value for read command */
.space 4 /* not used */
.space 4 /* not used */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,11 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x24,0x4c,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x20,0x25,
0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46,0x0f,0x43,
0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x18,0x4f,0x5f,0x61,0x9a,0x61,
0x9f,0x68,0x2f,0x78,0x27,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x17,0x4f,
0x00,0x2f,0x09,0xd0,0xbc,0x42,0xfa,0xd0,0x13,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,
0x02,0xd4,0x0a,0x42,0xed,0xd1,0xd6,0xe7,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,
0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,177 @@
/***************************************************************************
* Copyright (C) 2016 - 2018 by 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 *
* (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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - QSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - rp
* r5 - address of QSPI_DR
* r7 - tmp
* r10 - single 0x0 / dual 0x1
*/
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, rp /* load rp */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
mov r10, r7 /* save in r10 */
wip_loop:
qspi_abort /* start in clean state */
movs r5, #QSPI_DR /* load QSPI_DR address offset */
adds r5, r5, r3 /* address of QSPI_DR */
wait_busy
mov r7, r10 /* get dual bit */
str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r3, #QSPI_CCR] /* initiate status read */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
bcs wip_loop /* then poll again */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq write_enable /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
bcs wip_loop /* then poll again */
write_enable:
tst r0, r0 /* test residual count */
bmi exit /* if negative, then finished */
wait_busy
ldr r7, ccr_write_enable /* CCR for write enable */
str r7, [r3, #QSPI_CCR] /* initiate write enable */
wait_busy
mov r7, r10 /* get dual bit */
str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r3, #QSPI_CCR] /* initiate status read */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
bcc error /* write enabled, then error */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq start_write /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
bcc error /* write enabled, then error */
start_write:
wait_busy
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then write to end of page */
mov r7, r0 /* else write all remaining */
write_dlr:
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_write /* CCR for page write */
str r7, [r3, #QSPI_CCR] /* initiate transfer */
str r2, [r3, #QSPI_AR] /* store SPI start address */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
write_loop:
ldr r7, wp /* get wp */
cmp r7, #0 /* if wp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo empty */
beq write_loop /* wait until not empty */
ldrb r7, [r4, #0] /* read next byte */
strb r7, [r5] /* write next byte to DR */
adds r4, r4, #1 /* increment internal rp */
cmp r4, r9 /* internal rp beyond end? */
blo upd_write /* if no, then ok */
mov r4, r8 /* else wrap around */
upd_write:
adr r7, rp /* get address of rp */
str r4, [r7] /* store updated rp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi page_end /* stop if no data left */
tst r2, r1 /* page end ? */
bne write_loop /* if not, then next byte */
page_end:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
bcc page_end /* loop until TCF set */
bal wip_loop /* then next page */
error:
movs r0, #0 /* return 0xFFFFFFFF */
subs r0, r0, #2 /* for error */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
ccr_read_status:
.space 4 /* QSPI_CCR value for READ_STATUS command */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
ccr_write_enable:
.space 4 /* QSPI_CCR value for WRITE_ENABLE command */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
ccr_page_write:
.space 4 /* QSPI_CCR value for PAGE_PROG command */
.space 4 /* not used */
.space 4 /* not used */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,18 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x41,0x4c,0x1f,0x68,0x7f,0x06,0xff,0x0f,0xba,0x46,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,
0x02,0x27,0xdf,0x60,0x57,0x46,0x1f,0x61,0x2c,0x4f,0x5f,0x61,0x9f,0x68,0x2f,0x78,
0x7f,0x08,0xec,0xd2,0x57,0x46,0x3f,0x42,0x02,0xd0,0x2f,0x78,0x7f,0x08,0xe6,0xd2,
0x00,0x42,0x41,0xd4,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x27,0x4f,
0x5f,0x61,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x57,0x46,0x1f,0x61,
0x1e,0x4f,0x5f,0x61,0x9f,0x68,0x2f,0x78,0xbf,0x08,0x2b,0xd3,0x57,0x46,0x3f,0x42,
0x02,0xd0,0x2f,0x78,0xbf,0x08,0x25,0xd3,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,
0xdf,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,
0x1a,0x4f,0x5f,0x61,0x9a,0x61,0x9f,0x68,0x1b,0x4f,0x00,0x2f,0x14,0xd0,0xbc,0x42,
0xfa,0xd0,0x27,0x78,0x2f,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x17,0xa7,
0x3c,0x60,0x01,0x32,0x01,0x38,0x01,0xd4,0x0a,0x42,0xed,0xd1,0x9f,0x68,0xbf,0x08,
0xfc,0xd3,0xa4,0xe7,0x00,0x20,0x02,0x38,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,
0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -30,9 +30,9 @@ of the Open On-Chip Debugger (OpenOCD).
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''.
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
copy of the license is included in the section entitled ``GNU Free
Documentation License''.
@end quotation
@end copying
@ -79,7 +79,6 @@ Free Documentation License''.
* JTAG Commands:: JTAG Commands
* Boundary Scan Commands:: Boundary Scan Commands
* Utility Commands:: Utility Commands
* TFTP:: TFTP
* GDB and OpenOCD:: Using GDB and OpenOCD
* Tcl Scripting API:: Tcl Scripting API
* FAQ:: Frequently Asked Questions
@ -624,6 +623,13 @@ emulation model of target hardware.
@item @b{xlnx_pcie_xvc}
@* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface.
@item @b{linuxgpiod}
@* A bitbang JTAG driver using Linux GPIO through library libgpiod.
@item @b{sysfsgpio}
@* A bitbang JTAG driver using Linux legacy sysfs GPIO.
This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}.
@end itemize
@node About Jim-Tcl
@ -2430,7 +2436,8 @@ and a specific set of GPIOs is used.
@end deffn
@deffn {Interface Driver} {cmsis-dap}
ARM CMSIS-DAP compliant based adapter.
ARM CMSIS-DAP compliant based adapter v1 (USB HID based)
or v2 (USB bulk).
@deffn {Config Command} {cmsis_dap_vid_pid} [vid pid]+
The vendor ID and product ID of the CMSIS-DAP device. If not specified
@ -2446,6 +2453,23 @@ Specifies the @var{serial} of the CMSIS-DAP device to use.
If not specified, serial numbers are not considered.
@end deffn
@deffn {Config Command} {cmsis_dap_backend} [@option{auto}|@option{usb_bulk}|@option{hid}]
Specifies how to communicate with the adapter:
@itemize @minus
@item @option{hid} Use HID generic reports - CMSIS-DAP v1
@item @option{usb_bulk} Use USB bulk - CMSIS-DAP v2
@item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try HID CMSIS-DAP v1.
This is the default if @command{cmsis_dap_backend} is not specified.
@end itemize
@end deffn
@deffn {Config Command} {cmsis_dap_usb interface} [number]
Specifies the @var{number} of the USB interface to use in v2 mode (USB bulk).
In most cases need not to be specified and interfaces are searched by
interface string or for user class interface.
@end deffn
@deffn {Command} {cmsis-dap info}
Display various device information, like hardware version, firmware version, current bus status.
@end deffn
@ -2881,8 +2905,8 @@ The following example shows how to read 4 bytes from the EMUCOM channel 0x0:
@deffn {Config} {jlink usb} <@option{0} to @option{3}>
Set the USB address of the interface, in case more than one adapter is connected
to the host. If not specified, USB addresses are not considered. Device
selection via USB address is deprecated and the serial number should be used
instead.
selection via USB address is not always unambiguous. It is recommended to use
the serial number instead, if possible.
As a configuration command, it can be used only before 'init'.
@end deffn
@ -3223,6 +3247,22 @@ pinout.
@end deffn
@deffn {Interface Driver} {linuxgpiod}
Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6.
The driver emulates either JTAG and SWD transport through bitbanging.
See @file{interface/dln-2-gpiod.cfg} for a sample config.
@end deffn
@deffn {Interface Driver} {sysfsgpio}
Linux legacy userspace access to GPIO through sysfs is deprecated from Linux kernel version v5.3.
Prefer using @b{linuxgpiod}, instead.
See @file{interface/sysfsgpio-raspberrypi.cfg} for a sample config.
@end deffn
@deffn {Interface Driver} {openjtag}
OpenJTAG compatible USB adapter.
This defines some driver-specific commands:
@ -4694,6 +4734,11 @@ possible values of the parameter @var{number}, which are not only numeric values
Use this option to override, for this target only, the global parameter set with
command @command{gdb_port}.
@xref{gdb_port,,command gdb_port}.
@item @code{-gdb-max-connections} @var{number} -- EXPERIMENTAL: set the maximum
number of GDB connections that are allowed for the target. Default is 1.
A negative value for @var{number} means unlimited connections.
See @xref{gdbmeminspect,,Using GDB as a non-intrusive memory inspector}.
@end itemize
@end deffn
@ -5249,6 +5294,18 @@ it has been removed by the @option{unlock} flag.
@end deffn
@deffn Command {flash verify_image} filename [offset] [type]
Verify the image @file{filename} to the current target's flash bank(s).
Parameters follow the description of 'flash write_image'.
In contrast to the 'verify_image' command, for banks with specific
verify method, that one is used instead of the usual target's read
memory methods. This is necessary for flash banks not readable by
ordinary memory reads.
This command gives only an overall good/bad result for each bank, not
addresses of individual failed bytes as it's intended only as quick
check for successful programming.
@end deffn
@section Other Flash commands
@cindex flash protection
@ -5507,6 +5564,117 @@ flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME
@end deffn
@deffn {Flash Driver} stmqspi
@cindex STMicroelectronics QuadSPI/OctoSPI Interface
@cindex QuadSPI
@cindex OctoSPI
@cindex stmqspi
Some devices from STMicroelectronics include a proprietary ``QuadSPI Interface''
(e.g. STM32F4, STM32F7, STM32L4) or ``OctoSPI Interface'' (e.g. STM32L4+)
controller able to drive one or even two (dual mode) external SPI flash devices.
The OctoSPI is a superset of QuadSPI, its presence is detected automatically.
Currently only the regular command mode is supported, whereas the HyperFlash
mode is not.
QuadSPI/OctoSPI makes the flash contents directly accessible in the CPU address
space; in case of dual mode both devices must be of the same type and are
mapped in the same memory bank (even and odd addresses interleaved).
CPU can directly read data, execute code (but not boot) from QuadSPI bank.
The 'flash bank' command only requires the @var{base} parameter and the extra
parameter @var{io_base} in order to identify the memory bank. Both are fixed
by hardware, see datasheet or RM. All other parameters are ignored.
The controller must be initialized after each reset and properly configured
for memory-mapped read operation for the particular flash chip(s), for the full
list of available register settings cf. the controller's RM. This setup is quite
board specific (that's why booting from this memory is not possible). The
flash driver infers all parameters from current controller register values when
'flash probe @var{bank_id}' is executed.
Normal OpenOCD commands like @command{mdw} can be used to display the flash content,
but only after proper controller initialization as decribed above. However,
due to a silicon bug in some devices, attempting to access the very last word
should be avoided.
It is possible to use two (even different) flash chips alternatingly, if individual
bank chip selects are available. For some package variants, this is not the case
due to limited pin count. To switch from one to another, adjust FSEL bit accordingly
and re-issue 'flash probe bank_id'. Note that the bank base address will @emph{not}
change, so the address spaces of both devices will overlap. In dual flash mode
both chips must be identical regarding size and most other properties.
Block or sector protection internal to the flash chip is not handled by this
driver at all, but can be dealt with manually by the 'cmd' command, see below.
The sector protection via 'flash protect' command etc. is completely internal to
openocd, intended only to prevent accidental erase or overwrite and it does not
persist across openocd invocations.
OpenOCD contains a hardcoded list of flash devices with their properties,
these are auto-detected. If a device is not included in this list, SFDP discovery
is attempted. If this fails or gives inappropriate results, manual setting is
required (see 'set' command).
@example
flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
flash bank $_FLASHNAME stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400
@end example
There are three specific commands
@deffn Command {stmqspi mass_erase} bank_id
Clears sector protections and performs a mass erase. Works only if there is no
chip specific write protection engaged.
@end deffn
@deffn Command {stmqspi set} bank_id name total_size page_size read_cmd fread_cmd pprg_cmd mass_erase_cmd sector_size sector_erase_cmd
Set flash parameters: @var{name} human readable string, @var{total_size} size
in bytes, @var{page_size} is write page size. @var{read_cmd}, @var{fread_cmd} and @var{pprg_cmd}
are commands for reading and page programming. @var{fread_cmd} is used in DPI and QPI modes,
@var{read_cmd} in normal SPI (single line) mode. @var{mass_erase_cmd}, @var{sector_size}
and @var{sector_erase_cmd} are optional.
This command is required if chip id is not hardcoded yet and e.g. for EEPROMs or FRAMs
which don't support an id command.
In dual mode parameters of both chips are set identically. The parameters refer to
a single chip, so the whole bank gets twice the specified capacity etc.
@end deffn
@deffn Command {stmqspi cmd} bank_id resp_num cmd_byte ...
If @var{resp_num} is zero, sends command @var{cmd_byte} and following data
bytes. In dual mode command byte is sent to @emph{both} chips but data bytes are
sent @emph{alternatingly} to chip 1 and 2, first to flash 1, second to flash 2, etc.,
i.e. the total number of bytes (including cmd_byte) must be odd.
If @var{resp_num} is not zero, cmd and at most four following data bytes are
sent, in dual mode @emph{simultaneously} to both chips. Then @var{resp_num} bytes
are read interleaved from both chips starting with chip 1. In this case
@var{resp_num} must be even.
Note the hardware dictated subtle difference of those two cases in dual-flash mode.
To check basic communication settings, issue
@example
stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 1 0x05; stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 1 0x05
@end example
for single flash mode or
@example
stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 2 0x05; stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 2 0x05
@end example
for dual flash mode. This should return the status register contents.
In 8-line mode, @var{cmd_byte} is sent twice - first time as given, second time
complemented. Additionally, in 8-line mode only, some commands (e.g. Read Status)
need a dummy address, e.g.
@example
stmqspi cmd bank_id 1 0x05 0x00 0x00 0x00 0x00
@end example
should return the status register contents.
@end deffn
@end deffn
@deffn {Flash Driver} mrvlqspi
This driver supports QSPI flash controller of Marvell's Wireless
Microcontroller platform.
@ -6989,10 +7157,9 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@deffn {Flash Driver} stm32l4x
All members of the STM32L4, STM32L4+, STM32WB, STM32WL and STM32G4
All members of the STM32 G0, G4, L4, L4+, L5, WB and WL
microcontroller families from STMicroelectronics include internal flash
and use ARM Cortex-M4 cores.
Additionally this driver supports STM32G0 family with ARM Cortex-M0+ core.
and use ARM Cortex-M0+, M4 and M33 cores.
The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself.
@ -8279,6 +8446,94 @@ the watchpoint should trigger. The value may be first be masked
using @var{mask} to mark ``don't care'' fields.
@end deffn
@section Real Time Transfer (RTT)
Real Time Transfer (RTT) is an interface specified by SEGGER based on basic
memory reads and writes to transfer data bidirectionally between target and host.
The specification is independent of the target architecture.
Every target that supports so called "background memory access", which means
that the target memory can be accessed by the debugger while the target is
running, can be used.
This interface is especially of interest for targets without
Serial Wire Output (SWO), such as ARM Cortex-M0, or where semihosting is not
applicable because of real-time constraints.
@quotation Note
The current implementation supports only single target devices.
@end quotation
The data transfer between host and target device is organized through
unidirectional up/down-channels for target-to-host and host-to-target
communication, respectively.
@quotation Note
The current implementation does not respect channel buffer flags.
They are used to determine what happens when writing to a full buffer, for
example.
@end quotation
Channels are exposed via raw TCP/IP connections. One or more RTT servers can be
assigned to each channel to make them accessible to an unlimited number
of TCP/IP connections.
@deffn Command {rtt setup} address size ID
Configure RTT for the currently selected target.
Once RTT is started, OpenOCD searches for a control block with the
identifier @var{ID} starting at the memory address @var{address} within the next
@var{size} bytes.
@end deffn
@deffn Command {rtt start}
Start RTT.
If the control block location is not known, OpenOCD starts searching for it.
@end deffn
@deffn Command {rtt stop}
Stop RTT.
@end deffn
@deffn Command {rtt polling_interval [interval]}
Display the polling interval.
If @var{interval} is provided, set the polling interval.
The polling interval determines (in milliseconds) how often the up-channels are
checked for new data.
@end deffn
@deffn Command {rtt channels}
Display a list of all channels and their properties.
@end deffn
@deffn Command {rtt channellist}
Return a list of all channels and their properties as Tcl list.
The list can be manipulated easily from within scripts.
@end deffn
@deffn Command {rtt server start} port channel
Start a TCP server on @var{port} for the channel @var{channel}.
@end deffn
@deffn Command {rtt server stop} port
Stop the TCP sever with port @var{port}.
@end deffn
The following example shows how to setup RTT using the SEGGER RTT implementation
on the target device.
@example
resume
rtt setup 0x20000000 2048 "SEGGER RTT"
rtt start
rtt server start 9090 0
@end example
In this example, OpenOCD searches the control block with the ID "SEGGER RTT"
starting at 0x20000000 for 2048 bytes. The RTT channel 0 is exposed through the
TCP/IP port 9090.
@section Misc Commands
@cindex profiling
@ -8593,7 +8848,7 @@ CTI is mandatory for core run control and each core has an individual
CTI instance attached to it. OpenOCD has limited support for CTI using
the @emph{cti} group of commands.
@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-ctibase} base_address
@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-baseaddr} base_address
Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP
@var{apn}. The @var{base_address} must match the base address of the CTI
on the respective MEM-AP. All arguments are mandatory. This creates a
@ -9201,7 +9456,7 @@ Selects whether interrupts will be processed when single stepping
@cindex ITM
@cindex ETM
@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal (@var{filename} | -)}) @
@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal (@var{filename} | @var{:port} | -)}) @
(@option{sync @var{port_width}} | ((@option{manchester} | @option{uart}) @var{formatter_enable})) @
@var{TRACECLKIN_freq} [@var{trace_freq}]))
@ -9221,23 +9476,28 @@ Command options:
@itemize @minus
@item @option{disable} disable TPIU handling;
@item @option{external} configure TPIU to let user capture trace
output externally (with an additional UART or logic analyzer hardware);
@item @option{internal @var{filename}} configure TPIU and debug adapter to
gather trace data and append it to @var{filename} (which can be
either a regular file or a named pipe);
@item @option{internal -} configure TPIU and debug adapter to
gather trace data, but not write to any file. Useful in conjunction with the @command{tcl_trace} command;
output externally (with an additional UART or logic analyzer hardware).
@item @option{internal (@var{filename} | @var{:port} | -)} configure TPIU and debug adapter to
gather trace data then:
@itemize @minus
@item append it to a regular file or a named pipe if @var{filename} is specified.
@item listen to a TCP/IP port if @var{:port} is specified, then broadcast the trace data over this port.
@item if '-' is specified, OpenOCD will forward trace data to @command{tcl_trace} command.
@*@b{Note:} while broadcasting to file or TCP, the forwarding to @command{tcl_trace} will remain active.
@end itemize
@item @option{sync @var{port_width}} use synchronous parallel trace output
mode, and set port width to @var{port_width};
mode, and set port width to @var{port_width}.
@item @option{manchester} use asynchronous SWO mode with Manchester
coding;
coding.
@item @option{uart} use asynchronous SWO mode with NRZ (same as
regular UART 8N1) coding;
regular UART 8N1) coding.
@item @var{formatter_enable} is @option{on} or @option{off} to enable
or disable TPIU formatter which needs to be used when both ITM and ETM
data is to be output via SWO;
data is to be output via SWO.
@item @var{TRACECLKIN_freq} this should be specified to match target's
current TRACECLKIN frequency (usually the same as HCLK);
current TRACECLKIN frequency (usually the same as HCLK).
@item @var{trace_freq} trace port frequency. Can be omitted in
internal mode to let the adapter driver select the maximum supported
rate automatically.
@ -10411,28 +10671,6 @@ For quickstart instructions run:
openocd -f tools/firmware-recovery.tcl -c firmware_help
@end example
@node TFTP
@chapter TFTP
@cindex TFTP
If OpenOCD runs on an embedded host (as ZY1000 does), then TFTP can
be used to access files on PCs (either the developer's PC or some other PC).
The way this works on the ZY1000 is to prefix a filename by
"/tftp/ip/" and append the TFTP path on the TFTP
server (tftpd). For example,
@example
load_image /tftp/10.0.0.96/c:\temp\abc.elf
@end example
will load c:\temp\abc.elf from the developer pc (10.0.0.96) into memory as
if the file was hosted on the embedded host.
In order to achieve decent performance, you must choose a TFTP server
that supports a packet size bigger than the default packet size (512 bytes). There
are numerous TFTP servers out there (free and commercial) and you will have to do
a bit of googling to find something that fits your requirements.
@node GDB and OpenOCD
@chapter GDB and OpenOCD
@cindex GDB
@ -10656,7 +10894,13 @@ of a running target. Do not use GDB commands @command{continue},
and GDB would require stopping the target to get the prompt back.
Do not use this mode under an IDE like Eclipse as it caches values of
previously shown varibles.
previously shown variables.
It's also possible to connect more than one GDB to the same target by the
target's configuration option @code{-gdb-max-connections}. This allows, for
example, one GDB to run a script that continuously polls a set of variables
while other GDB can be used interactively. Be extremely careful in this case,
because the two GDB can easily get out-of-sync.
@section RTOS Support
@cindex RTOS Support

View File

@ -53,7 +53,8 @@ endif
%D%/target/libtarget.la \
%D%/server/libserver.la \
%D%/rtos/librtos.la \
%D%/helper/libhelper.la
%D%/helper/libhelper.la \
%D%/rtt/librtt.la
BIN2C = $(srcdir)/%D%/helper/bin2char.sh
@ -83,3 +84,4 @@ include %D%/rtos/Makefile.am
include %D%/server/Makefile.am
include %D%/flash/Makefile.am
include %D%/pld/Makefile.am
include %D%/rtt/Makefile.am

View File

@ -860,7 +860,7 @@ static int validate_target_state(struct nand_device *nand)
return ERROR_OK;
}
int ecc_status_v1(struct nand_device *nand)
static int ecc_status_v1(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
@ -886,7 +886,7 @@ int ecc_status_v1(struct nand_device *nand)
return ERROR_OK;
}
int ecc_status_v2(struct nand_device *nand)
static int ecc_status_v2(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;

View File

@ -52,10 +52,12 @@ NOR_DRIVERS = \
%D%/psoc5lp.c \
%D%/psoc6.c \
%D%/renesas_rpchf.c \
%D%/sfdp.c \
%D%/sh_qspi.c \
%D%/sim3x.c \
%D%/spi.c \
%D%/stmsmi.c \
%D%/stmqspi.c \
%D%/stellaris.c \
%D%/stm32f1x.c \
%D%/stm32f2x.c \
@ -84,6 +86,8 @@ NORHEADERS = \
%D%/imp.h \
%D%/non_cfi.h \
%D%/ocl.h \
%D%/sfdp.h \
%D%/spi.h \
%D%/stm32l4x.h \
%D%/stmqspi.h \
%D%/msp432.h

View File

@ -3099,7 +3099,7 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
* is owned by this bank. This simplification works only for one shot
* deallocation like current flash_free_all_banks()
*/
void sam3_free_driver_priv(struct flash_bank *bank)
static void sam3_free_driver_priv(struct flash_bank *bank)
{
struct sam3_chip *chip = all_sam3_chips;
while (chip) {

View File

@ -676,6 +676,9 @@ showall:
}
if ((who >= 0) && (((unsigned)who) < SAMV_NUM_GPNVM_BITS)) {
r = samv_get_gpnvm(target, who, &v);
if (r != ERROR_OK)
return r;
command_print(CMD, "samv-gpnvm%u: %u", who, v);
return r;
} else {

View File

@ -43,7 +43,7 @@ struct flash_ctrl_priv_data {
char *part_name;
};
const struct flash_ctrl_priv_data flash_priv_data_1 = {
static const struct flash_ctrl_priv_data flash_priv_data_1 = {
.die_id_reg = 0x4090001C,
.jtag_idcode_reg = 0x40900028,
.flash_base = 0x10040000,
@ -53,7 +53,7 @@ const struct flash_ctrl_priv_data flash_priv_data_1 = {
.part_name = "BLUENRG-1",
};
const struct flash_ctrl_priv_data flash_priv_data_2 = {
static const struct flash_ctrl_priv_data flash_priv_data_2 = {
.die_id_reg = 0x4090001C,
.jtag_idcode_reg = 0x40900028,
.flash_base = 0x10040000,
@ -63,7 +63,7 @@ const struct flash_ctrl_priv_data flash_priv_data_2 = {
.part_name = "BLUENRG-2",
};
const struct flash_ctrl_priv_data flash_priv_data_lp = {
static const struct flash_ctrl_priv_data flash_priv_data_lp = {
.die_id_reg = 0x40000000,
.jtag_idcode_reg = 0x40000004,
.flash_base = 0x10040000,
@ -79,7 +79,11 @@ struct bluenrgx_flash_bank {
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};
static 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)

View File

@ -94,7 +94,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
}
int flash_driver_write(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count)
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int retval;
@ -135,6 +135,43 @@ int default_flash_read(struct flash_bank *bank,
return target_read_buffer(bank->target, offset + bank->base, count, buffer);
}
int flash_driver_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int retval;
retval = bank->driver->verify ? bank->driver->verify(bank, buffer, offset, count) :
default_flash_verify(bank, buffer, offset, count);
if (retval != ERROR_OK) {
LOG_ERROR("verify failed in bank at " TARGET_ADDR_FMT " starting at 0x%8.8" PRIx32,
bank->base, offset);
}
return retval;
}
int default_flash_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
uint32_t target_crc, image_crc;
int retval;
retval = image_calculate_checksum(buffer, count, &image_crc);
if (retval != ERROR_OK)
return retval;
retval = target_checksum_memory(bank->target, offset + bank->base, count, &target_crc);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32,
offset + bank->base, count, ~image_crc, ~target_crc);
if (target_crc == image_crc)
return ERROR_OK;
else
return ERROR_FAIL;
}
void flash_bank_add(struct flash_bank *bank)
{
/* put flash bank in linked list */
@ -697,12 +734,12 @@ static bool flash_write_check_gap(struct flash_bank *bank,
}
int flash_write_unlock(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock)
int flash_write_unlock_verify(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock, bool write, bool verify)
{
int retval = ERROR_OK;
int section;
unsigned int section;
uint32_t section_offset;
struct flash_bank *c;
int *padding;
@ -727,8 +764,8 @@ int flash_write_unlock(struct target *target, struct image *image,
* whereas an image can have sections out of order. */
struct imagesection **sections = malloc(sizeof(struct imagesection *) *
image->num_sections);
int i;
for (i = 0; i < image->num_sections; i++)
for (unsigned int i = 0; i < image->num_sections; i++)
sections[i] = &image->sections[i];
qsort(sections, image->num_sections, sizeof(struct imagesection *),
@ -738,7 +775,7 @@ int flash_write_unlock(struct target *target, struct image *image,
while (section < image->num_sections) {
uint32_t buffer_idx;
uint8_t *buffer;
int section_last;
unsigned int section_last;
target_addr_t run_address = sections[section]->base_address + section_offset;
uint32_t run_size = sections[section]->size - section_offset;
int pad_bytes = 0;
@ -932,8 +969,17 @@ int flash_write_unlock(struct target *target, struct image *image,
}
if (retval == ERROR_OK) {
/* write flash sectors */
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
if (write) {
/* write flash sectors */
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
}
}
if (retval == ERROR_OK) {
if (verify) {
/* verify flash sectors */
retval = flash_driver_verify(c, buffer, run_address - c->base, run_size);
}
}
free(buffer);
@ -957,7 +1003,7 @@ done:
int flash_write(struct target *target, struct image *image,
uint32_t *written, bool erase)
{
return flash_write_unlock(target, image, written, erase, false);
return flash_write_unlock_verify(target, image, written, erase, false, true, false);
}
struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size,

View File

@ -200,6 +200,7 @@ void default_flash_free_driver_priv(struct flash_bank *bank);
/** Deallocates all flash banks */
void flash_free_all_banks(void);
/**
* Provides default read implementation for flash memory.
* @param bank The bank to read.
@ -210,6 +211,18 @@ void flash_free_all_banks(void);
*/
int default_flash_read(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Provides default verify implementation for flash memory.
* @param bank The bank to verify.
* @param buffer The data bytes to verify.
* @param offset The offset into the chip to verify.
* @param count The number of bytes to verify.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int default_flash_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Provides default erased-bank check handling. Checks to see if
* the flash driver knows they are erased; if things look uncertain,
@ -217,7 +230,6 @@ int default_flash_read(struct flash_bank *bank,
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int default_flash_blank_check(struct flash_bank *bank);
/**
* Returns the flash bank specified by @a name, which matches the
* driver name and a suffix (option) specify the driver-specific

View File

@ -155,6 +155,20 @@ struct flash_driver {
int (*read)(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Verify data in flash. Note CPU address will be
* "bank->base + offset", while the physical address is
* dependent upon current target MMU mappings.
*
* @param bank The bank to verify
* @param buffer The data bytes to verify against.
* @param offset The offset into the chip to verify.
* @param count The number of bytes to verify.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*verify)(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Probe to determine what kind of flash is present.
* This is invoked by the "probe" script command.

View File

@ -44,6 +44,7 @@ extern const struct flash_driver faux_flash;
extern const struct flash_driver fm3_flash;
extern const struct flash_driver fm4_flash;
extern const struct flash_driver fespi_flash;
extern const struct flash_driver gd32vf103_flash;
extern const struct flash_driver jtagspi_flash;
extern const struct flash_driver kinetis_flash;
extern const struct flash_driver kinetis_ke_flash;
@ -75,7 +76,7 @@ extern const struct flash_driver stm32f2x_flash;
extern const struct flash_driver stm32lx_flash;
extern const struct flash_driver stm32l4x_flash;
extern const struct flash_driver stm32h7x_flash;
extern const struct flash_driver gd32vf103_flash;
extern const struct flash_driver stmqspi_flash;
extern const struct flash_driver stmsmi_flash;
extern const struct flash_driver str7x_flash;
extern const struct flash_driver str9x_flash;
@ -150,6 +151,7 @@ static const struct flash_driver * const flash_drivers[] = {
&stm32h7x_flash,
&gd32vf103_flash,
&stmsmi_flash,
&stmqspi_flash,
&str7x_flash,
&str9x_flash,
&str9xpec_flash,

View File

@ -42,12 +42,14 @@ int flash_driver_erase(struct flash_bank *bank, unsigned int first,
int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last);
int flash_driver_write(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
const uint8_t *buffer, uint32_t offset, uint32_t count);
int flash_driver_read(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
int flash_driver_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count);
/* write (optional verify) an image to flash memory of the given target */
int flash_write_unlock(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock);
int flash_write_unlock_verify(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock, bool write, bool verify);
#endif /* OPENOCD_FLASH_NOR_IMP_H */

View File

@ -434,7 +434,7 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank)
return ERROR_OK;
}
int kinetis_ke_stop_watchdog(struct target *target)
static int kinetis_ke_stop_watchdog(struct target *target)
{
struct working_area *watchdog_algorithm;
struct armv7m_algorithm armv7m_info;

View File

@ -1103,9 +1103,9 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_
uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32);
if (original_value != checksum) {
LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is "
LOG_WARNING("Boot verification checksum in image (0x%8.8" PRIx32 ") to be written to flash is "
"different from calculated vector checksum (0x%8.8" PRIx32 ").", original_value, checksum);
LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector "
LOG_WARNING("OpenOCD will write the correct checksum. To remove this warning modify build tools on developer PC to inject correct LPC vector "
"checksum.");
}

View File

@ -635,9 +635,9 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command)
/* The image will always start at offset 0 */
struct image image;
image.base_address_set = 1;
image.base_address_set = true;
image.base_address = 0;
image.start_address_set = 0;
image.start_address_set = false;
const char *filename = CMD_ARGV[1];
const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL;

View File

@ -761,7 +761,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
return retval;
}
int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer,
static int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
@ -914,7 +914,7 @@ static int mrvlqspi_flash_erase_check(struct flash_bank *bank)
return ERROR_OK;
}
int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
static int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;

View File

@ -158,7 +158,7 @@ struct nrf5_info {
bool ficr_info_valid;
struct nrf52_ficr_info ficr_info;
const struct nrf5_device_spec *spec;
uint32_t hwid;
uint16_t hwid;
enum nrf5_features features;
unsigned int flash_size_kb;
unsigned int ram_size_kb;
@ -328,7 +328,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
do {
res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read NVMC_READY register");
LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)");
return res;
}
@ -440,6 +440,38 @@ error:
return ERROR_FAIL;
}
static int nrf5_protect_check_clenr0(struct flash_bank *bank)
{
int res;
uint32_t clenr0;
struct nrf5_bank *nbank = bank->driver_priv;
struct nrf5_info *chip = nbank->chip;
assert(chip != NULL);
res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[FICR]");
return res;
}
if (clenr0 == 0xFFFFFFFF) {
res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
return res;
}
}
for (unsigned int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected =
clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0;
return ERROR_OK;
}
static int nrf5_protect_check_bprot(struct flash_bank *bank)
{
struct nrf5_bank *nbank = bank->driver_priv;
@ -469,9 +501,6 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank)
static int nrf5_protect_check(struct flash_bank *bank)
{
int res;
uint32_t clenr0;
/* UICR cannot be write protected so just return early */
if (bank->base == NRF5_UICR_BASE)
return ERROR_OK;
@ -484,53 +513,20 @@ static int nrf5_protect_check(struct flash_bank *bank)
if (chip->features & NRF5_FEATURE_BPROT)
return nrf5_protect_check_bprot(bank);
if (!(chip->features & NRF5_FEATURE_SERIES_51)) {
LOG_WARNING("Flash protection of this nRF device is not supported");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
if (chip->features & NRF5_FEATURE_SERIES_51)
return nrf5_protect_check_clenr0(bank);
res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[FICR]");
return res;
}
if (clenr0 == 0xFFFFFFFF) {
res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
return res;
}
}
for (unsigned int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected =
clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0;
return ERROR_OK;
LOG_WARNING("Flash protection of this nRF device is not supported");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
int res;
uint32_t clenr0, ppfc;
struct nrf5_info *chip;
/* UICR cannot be write protected so just bail out early */
if (bank->base == NRF5_UICR_BASE)
return ERROR_FAIL;
res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
if (!(chip->features & NRF5_FEATURE_SERIES_51)) {
LOG_ERROR("Flash protection setting of this nRF device is not supported");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
struct nrf5_bank *nbank = bank->driver_priv;
struct nrf5_info *chip = nbank->chip;
if (first != 0) {
LOG_ERROR("Code region 0 must start at the beginning of the bank");
@ -552,25 +548,59 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
&clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code region 0 size[UICR]");
LOG_ERROR("Couldn't read code region 0 size from UICR");
return res;
}
if (clenr0 == 0xFFFFFFFF) {
res = target_write_u32(chip->target, NRF51_UICR_CLENR0,
clenr0);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't write code region 0 size[UICR]");
return res;
}
} else {
if (!set || clenr0 != 0xFFFFFFFF) {
LOG_ERROR("You need to perform chip erase before changing the protection settings");
return ERROR_FAIL;
}
nrf5_protect_check(bank);
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
return ERROR_OK;
clenr0 = bank->sectors[last].offset + bank->sectors[last].size;
res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0);
int res2 = nrf5_wait_for_nvmc(chip);
if (res == ERROR_OK)
res = res2;
if (res == ERROR_OK)
LOG_INFO("A reset or power cycle is required for the new protection settings to take effect.");
else
LOG_ERROR("Couldn't write code region 0 size to UICR");
error:
nrf5_nvmc_read_only(chip);
return res;
}
static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
int res;
struct nrf5_info *chip;
/* UICR cannot be write protected so just bail out early */
if (bank->base == NRF5_UICR_BASE) {
LOG_ERROR("UICR page does not support protection");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
if (chip->features & NRF5_FEATURE_SERIES_51)
return nrf5_protect_clenr0(bank, set, first, last);
LOG_ERROR("Flash protection setting is not supported on this nRF5 device");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
static bool nrf5_info_variant_to_str(uint32_t variant, char *bf)
@ -618,7 +648,7 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
variant, &variant[2]);
} else {
res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")",
res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")",
chip->hwid);
}
if (res <= 0)
@ -735,14 +765,15 @@ static int nrf5_probe(struct flash_bank *bank)
struct nrf5_info *chip = nbank->chip;
struct target *target = chip->target;
res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid);
uint32_t configid;
res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read CONFIGID register");
return res;
}
chip->hwid &= 0xFFFF; /* HWID is stored in the lower two
* bytes of the CONFIGID register */
/* HWID is stored in the lower two bytes of the CONFIGID register */
chip->hwid = configid & 0xFFFF;
/* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
chip->features = NRF5_FEATURE_SERIES_51;
@ -820,8 +851,6 @@ static int nrf5_probe(struct flash_bank *bank)
if (!bank->sectors)
return ERROR_FAIL;
nrf5_protect_check(bank);
chip->bank[0].probed = true;
} else {
@ -983,7 +1012,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u
0, NULL,
ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
write_algorithm->address, write_algorithm->address + sizeof(nrf5_flash_write_code) - 2,
&armv7m_info);
target_free_working_area(target, source);
@ -1011,6 +1040,34 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
assert(offset % 4 == 0);
assert(count % 4 == 0);
/* UICR CLENR0 based protection used on nRF51 is somewhat clumsy:
* RM reads: Code running from code region 1 will not be able to write
* to code region 0.
* Unfortunately the flash loader running from RAM can write to both
* code regions whithout any hint the protection is violated.
*
* Update protection state and check if any flash sector to be written
* is protected. */
if (chip->features & NRF5_FEATURE_SERIES_51) {
res = nrf5_protect_check_clenr0(bank);
if (res != ERROR_OK)
return res;
for (unsigned int sector = 0; sector < bank->num_sectors; sector++) {
struct flash_sector *bs = &bank->sectors[sector];
/* Start offset in or before this sector? */
/* End offset in or behind this sector? */
if ((offset < (bs->offset + bs->size))
&& ((offset + count - 1) >= bs->offset)
&& bs->is_protected == 1) {
LOG_ERROR("Write refused, sector %d is protected", sector);
return ERROR_FLASH_PROTECTED;
}
}
}
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
@ -1037,11 +1094,36 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
if (res != ERROR_OK)
return res;
/* For each sector to be erased */
for (unsigned int s = first; s <= last && res == ERROR_OK; s++)
res = nrf5_erase_page(bank, chip, &bank->sectors[s]);
/* UICR CLENR0 based protection used on nRF51 prevents erase
* absolutely silently. NVMC has no flag to indicate the protection
* was violated.
*
* Update protection state and check if any flash sector to be erased
* is protected. */
if (chip->features & NRF5_FEATURE_SERIES_51) {
return res;
res = nrf5_protect_check_clenr0(bank);
if (res != ERROR_OK)
return res;
}
/* For each sector to be erased */
for (unsigned int s = first; s <= last && res == ERROR_OK; s++) {
if (chip->features & NRF5_FEATURE_SERIES_51
&& bank->sectors[s].is_protected == 1) {
LOG_ERROR("Flash sector %d is protected", s);
return ERROR_FLASH_PROTECTED;
}
res = nrf5_erase_page(bank, chip, &bank->sectors[s]);
if (res != ERROR_OK) {
LOG_ERROR("Error erasing sector %d", s);
return res;
}
}
return ERROR_OK;
}
static void nrf5_free_driver_priv(struct flash_bank *bank)
@ -1158,23 +1240,16 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
}
res = nrf5_erase_all(chip);
if (res != ERROR_OK) {
if (res == ERROR_OK) {
LOG_INFO("Mass erase completed.");
if (chip->features & NRF5_FEATURE_SERIES_51)
LOG_INFO("A reset or power cycle is required if the flash was protected before.");
} else {
LOG_ERROR("Failed to erase the chip");
nrf5_protect_check(bank);
return res;
}
res = nrf5_protect_check(bank);
if (res != ERROR_OK) {
LOG_ERROR("Failed to check chip's write protection");
return res;
}
res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank);
if (res != ERROR_OK)
return res;
return ERROR_OK;
return res;
}
COMMAND_HANDLER(nrf5_handle_info_command)

View File

@ -139,7 +139,7 @@ struct psoc4_chip_family {
uint32_t flags;
};
const struct psoc4_chip_family psoc4_families[] = {
static const struct psoc4_chip_family psoc4_families[] = {
{ 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY },
{ 0x9A, "PSoC4000", .flags = 0 },
{ 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 },

View File

@ -151,12 +151,6 @@ static int sromalgo_prepare(struct target *target)
if (hr != ERROR_OK)
return hr;
/* Restore THUMB bit in xPSR register */
const struct armv7m_common *cm = target_to_armv7m(target);
hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000);
if (hr != ERROR_OK)
return hr;
/* Allocate Working Area for Stack and Flash algorithm */
hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
if (hr != ERROR_OK)
@ -908,7 +902,7 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command)
* @param target current target
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
*************************************************************************************************/
int handle_reset_halt(struct target *target)
static int handle_reset_halt(struct target *target)
{
int hr;
uint32_t reset_addr;

263
src/flash/nor/sfdp.c Normal file
View File

@ -0,0 +1,263 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "spi.h"
#include "sfdp.h"
#define SFDP_MAGIC 0x50444653
#define SFDP_ACCESS_PROT 0xFF
#define SFDP_BASIC_FLASH 0xFF00
#define SFDP_4BYTE_ADDR 0xFF84
static const char *sfdp_name = "sfdp";
struct sfdp_hdr {
uint32_t signature;
uint32_t revision;
};
struct sfdp_phdr {
uint32_t revision;
uint32_t ptr;
};
struct sfdp_basic_flash_param {
uint32_t fast_addr; /* 01: fast read and 3/4 address bytes */
uint32_t density; /* 02: memory density */
uint32_t fast_1x4; /* 03: 1-1-4 and 1-4-4 fast read */
uint32_t fast_1x2; /* 04: 1-2-2 and 1-1-2 fast read */
uint32_t fast_444; /* 05: 4-4-4 and 2-2-2 fast read */
uint32_t read_222; /* 06: 2-2-2 fast read instr and dummy */
uint32_t read_444; /* 07: 4-4-4 fast read instr and dummy */
uint32_t erase_t12; /* 08: erase types 1, 2 */
uint32_t erase_t34; /* 09: erase types 3, 4 */
uint32_t erase_time; /* 10: erase times for types 1 - 4 */
uint32_t chip_byte; /* 11: chip erase time, byte prog time, page prog */
uint32_t susp_time; /* 12: suspend and resume times */
uint32_t susp_instr; /* 13: suspend and resume instr */
uint32_t pwrd_instr; /* 14: powerdown instr */
uint32_t quad_req; /* 15: quad enable requirements */
uint32_t addr_reset; /* 16: 3-/4-byte addressing and reset */
uint32_t read_1x8; /* 17: 1-1-8 and 1-8-8 fast read instr and dummy */
uint32_t dtr_drive; /* 18: dtr modes and drive strength */
uint32_t octal_req; /* 19: octal enable requirements */
uint32_t speed_888; /* 20: speed in 8-8-8 modes */
};
struct sfdp_4byte_addr_param {
uint32_t flags; /* 01: various flags */
uint32_t erase_t1234; /* 02: erase commands */
};
/* Try to get parameters from flash via SFDP */
int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
read_sfdp_block_t read_sfdp_block)
{
struct sfdp_hdr header;
struct sfdp_phdr *pheaders = NULL;
uint32_t *ptable = NULL;
unsigned int j, k, nph;
int retval, erase_type = 0;
memset(dev, 0, sizeof(struct flash_device));
/* retrieve SFDP header */
memset(&header, 0, sizeof(header));
retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *)&header);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision);
if (header.signature != SFDP_MAGIC) {
LOG_INFO("no SDFP found");
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) {
LOG_ERROR("access protocol 0x%02x not implemented",
(header.revision >> 24) & 0xFFU);
return ERROR_FLASH_BANK_NOT_PROBED;
}
/* retrieve table of parameter headers */
nph = ((header.revision >> 16) & 0xFF) + 1;
LOG_DEBUG("parameter headers: %d", nph);
pheaders = malloc(sizeof(struct sfdp_phdr) * nph);
if (pheaders == NULL) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph);
retval = read_sfdp_block(bank, sizeof(header),
(sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *)pheaders);
if (retval != ERROR_OK)
goto err;
for (k = 0; k < nph; k++) {
uint8_t words = (pheaders[k].revision >> 24) & 0xFF;
uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF);
uint32_t ptr = pheaders[k].ptr & 0xFFFFFF;
LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16
" ptr=0x%06" PRIx32, k, words, id, ptr);
/* retrieve parameter table */
ptable = malloc(words << 2);
if (ptable == NULL) {
LOG_ERROR("not enough memory");
retval = ERROR_FAIL;
goto err;
}
retval = read_sfdp_block(bank, ptr, words, ptable);
if (retval != ERROR_OK)
goto err;
for (j = 0; j < words; j++)
LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]);
if (id == SFDP_BASIC_FLASH) {
struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *)ptable;
uint16_t erase;
if (words < 9) {
LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words);
retval = ERROR_FLASH_BANK_NOT_PROBED;
goto err;
}
LOG_DEBUG("basic flash parameter table");
/* dummy device name */
dev->name = sfdp_name;
/* default instructions */
dev->read_cmd = SPIFLASH_READ;
dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM;
dev->chip_erase_cmd = SPIFLASH_MASS_ERASE;
/* get device size */
if (table->density & (1UL << 31))
dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3);
else
dev->size_in_bytes = (table->density + 1) >> 3;
/* 2-2-2 read instruction, not used */
if (table->fast_444 & (1UL << 0))
dev->qread_cmd = (table->read_222 >> 24) & 0xFF;
/* 4-4-4 read instruction */
if (table->fast_444 & (1UL << 4))
dev->qread_cmd = (table->read_444 >> 24) & 0xFF;
/* find the largest erase block size and instruction */
erase = (table->erase_t12 >> 0) & 0xFFFF;
erase_type = 1;
if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t12 >> 16) & 0xFFFF;
erase_type = 2;
}
if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t34 >> 0) & 0xFFFF;
erase_type = 3;
}
if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t34 >> 16) & 0xFFFF;
erase_type = 4;
}
dev->erase_cmd = (erase >> 8) & 0xFF;
dev->sectorsize = 1UL << (erase & 0xFF);
if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) {
/* get Program Page Size, if chip_byte present, that's optional */
dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F);
} else {
/* no explicit page size specified ... */
if (table->fast_addr & (1UL << 2)) {
/* Write Granularity = 1, use 64 bytes */
dev->pagesize = 1UL << 6;
} else {
/* Write Granularity = 0, use 16 bytes */
dev->pagesize = 1UL << 4;
}
}
if (dev->size_in_bytes > (1UL << 24)) {
if (((table->fast_addr >> 17) & 0x3) == 0x0)
LOG_ERROR("device needs paging - not implemented");
/* 4-byte addresses needed if more than 16 MBytes */
if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) &&
(table->addr_reset & (1UL << 29))) {
/* dedicated 4-byte-address instructions, hopefully these ...
* this entry is unfortunately optional as well
* a subsequent 4-byte address table may overwrite this */
dev->read_cmd = 0x13;
dev->pprog_cmd = 0x12;
dev->erase_cmd = 0xDC;
if (dev->qread_cmd != 0)
dev->qread_cmd = 0xEC;
} else if (((table->fast_addr >> 17) & 0x3) == 0x1)
LOG_INFO("device has to be switched to 4-byte addresses");
}
} else if (id == SFDP_4BYTE_ADDR) {
struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *)ptable;
if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234)
+ sizeof(table->erase_t1234)) >> 2) {
LOG_INFO("4-byte address parameter table");
/* read and page program instructions */
if (table->flags & (1UL << 0))
dev->read_cmd = 0x13;
if (table->flags & (1UL << 5))
dev->qread_cmd = 0xEC;
if (table->flags & (1UL << 6))
dev->pprog_cmd = 0x12;
/* erase instructions */
if ((erase_type == 1) && (table->flags & (1UL << 9)))
dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF;
else if ((erase_type == 2) && (table->flags & (1UL << 10)))
dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF;
else if ((erase_type == 3) && (table->flags & (1UL << 11)))
dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF;
else if ((erase_type == 4) && (table->flags & (1UL << 12)))
dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF;
} else
LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words);
} else
LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id);
free(ptable);
ptable = NULL;
}
if (erase_type != 0) {
LOG_INFO("valid SFDP detected");
retval = ERROR_OK;
} else {
LOG_ERROR("incomplete/invalid SFDP");
retval = ERROR_FLASH_BANK_NOT_PROBED;
}
err:
free(pheaders);
free(ptable);
return retval;
}

34
src/flash/nor/sfdp.h Normal file
View File

@ -0,0 +1,34 @@
/***************************************************************************
* Copyright (C) 2019 by 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 *
* (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_SFDP_H
#define OPENOCD_FLASH_NOR_SFDP_H
/* per JESD216D 'addr' is *byte* based but must be word aligned,
* 'buffer' is word based, word aligned and always little-endian encoded,
* in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8
*
* the actual number of dummy clocks should be worked out by this function
* dynamically, i.e. by scanning the first few bytes for the SFDP signature
*
* buffer contents is supposed to be returned in ***host*** endianness */
typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr,
uint32_t words, uint32_t *buffer);
extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
read_sfdp_block_t read_sfdp_block);
#endif /* OPENOCD_FLASH_NOR_SFDP_H */

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2018 by Andreas Bolsch *
* Copyright (C) 2018-2019 by Andreas Bolsch *
* andreas.bolsch@mni.thm.de *
* *
* Copyright (C) 2012 by George Harris *
@ -29,7 +29,7 @@
/* data structure to maintain flash ids from different vendors */
struct flash_device {
char *name;
const char *name;
uint8_t read_cmd;
uint8_t qread_cmd;
uint8_t pprog_cmd;
@ -87,6 +87,8 @@ extern const struct flash_device flash_devices[];
#define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */
#define SPIFLASH_FAST_READ 0x0B /* Fast Read */
#define SPIFLASH_READ 0x03 /* Normal Read */
#define SPIFLASH_MASS_ERASE 0xC7 /* Mass Erase */
#define SPIFLASH_READ_SFDP 0x5A /* Read Serial Flash Discoverable Parameters */
#define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */

View File

@ -215,7 +215,7 @@ static int stm32x_check_operation_supported(struct flash_bank *bank)
/* if we have a dual flash bank device then
* we need to perform option byte stuff on bank0 only */
if (stm32x_info->register_base != FLASH_REG_BASE_B0) {
LOG_ERROR("Option Byte Operation's must use bank0");
LOG_ERROR("Option byte operations must use bank 0");
return ERROR_FLASH_OPERATION_FAILED;
}

View File

@ -81,8 +81,7 @@
* http://www.st.com/resource/en/reference_manual/dm00530369.pdf
*/
/*
* STM32G0xxx series for reference.
/* STM32G0xxx series for reference.
*
* RM0444 (STM32G0x1)
* http://www.st.com/resource/en/reference_manual/dm00371828.pdf
@ -91,10 +90,9 @@
* http://www.st.com/resource/en/reference_manual/dm00463896.pdf
*/
/*
* STM32G4xxx series for reference.
/* STM32G4xxx series for reference.
*
* RM0440 (STM32G43x/44x/47x/48x)
* RM0440 (STM32G43x/44x/47x/48x/49x/4Ax)
* http://www.st.com/resource/en/reference_manual/dm00355726.pdf
*
* Cat. 2 devices have single bank only, page size is 2kByte.
@ -104,12 +102,60 @@
*
* Bank mode is controlled by bit 22 (DBANK) in option bytes register.
* Both banks are treated as a single OpenOCD bank.
*
* Cat. 4 devices have single bank only, page size is 2kByte.
*/
/* STM32L5xxx series for reference.
*
* RM0428 (STM32L552xx/STM32L562xx)
* http://www.st.com/resource/en/reference_manual/dm00346336.pdf
*/
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
#define FLASH_ERASE_TIMEOUT 250
enum stm32l4_flash_reg_index {
STM32_FLASH_ACR_INDEX,
STM32_FLASH_KEYR_INDEX,
STM32_FLASH_OPTKEYR_INDEX,
STM32_FLASH_SR_INDEX,
STM32_FLASH_CR_INDEX,
STM32_FLASH_OPTR_INDEX,
STM32_FLASH_WRP1AR_INDEX,
STM32_FLASH_WRP1BR_INDEX,
STM32_FLASH_WRP2AR_INDEX,
STM32_FLASH_WRP2BR_INDEX,
STM32_FLASH_REG_INDEX_NUM,
};
static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
[STM32_FLASH_ACR_INDEX] = 0x000,
[STM32_FLASH_KEYR_INDEX] = 0x008,
[STM32_FLASH_OPTKEYR_INDEX] = 0x00C,
[STM32_FLASH_SR_INDEX] = 0x010,
[STM32_FLASH_CR_INDEX] = 0x014,
[STM32_FLASH_OPTR_INDEX] = 0x020,
[STM32_FLASH_WRP1AR_INDEX] = 0x02C,
[STM32_FLASH_WRP1BR_INDEX] = 0x030,
[STM32_FLASH_WRP2AR_INDEX] = 0x04C,
[STM32_FLASH_WRP2BR_INDEX] = 0x050,
};
static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
[STM32_FLASH_ACR_INDEX] = 0x000,
[STM32_FLASH_KEYR_INDEX] = 0x008,
[STM32_FLASH_OPTKEYR_INDEX] = 0x010,
[STM32_FLASH_SR_INDEX] = 0x020,
[STM32_FLASH_CR_INDEX] = 0x028,
[STM32_FLASH_OPTR_INDEX] = 0x040,
[STM32_FLASH_WRP1AR_INDEX] = 0x058,
[STM32_FLASH_WRP1BR_INDEX] = 0x05C,
[STM32_FLASH_WRP2AR_INDEX] = 0x068,
[STM32_FLASH_WRP2BR_INDEX] = 0x06C,
};
struct stm32l4_rev {
const uint16_t rev;
const char *str;
@ -123,6 +169,7 @@ struct stm32l4_part_info {
const uint16_t max_flash_size_kb;
const bool has_dual_bank;
const uint32_t flash_regs_base;
const uint32_t *default_flash_regs;
const uint32_t fsize_addr;
};
@ -135,10 +182,11 @@ struct stm32l4_flash_bank {
uint32_t user_bank_size;
uint32_t wrpxxr_mask;
const struct stm32l4_part_info *part_info;
const uint32_t *flash_regs;
};
/* human readable list of families this drivers supports */
static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0";
/* human readable list of families this drivers supports (sorted alphabetically) */
static const char *device_families = "STM32G0/G4/L4/L4+/L5/WB/WL";
static const struct stm32l4_rev stm32_415_revs[] = {
{ 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
@ -184,6 +232,14 @@ static const struct stm32l4_rev stm32_471_revs[] = {
{ 0x1001, "Z" },
};
static const struct stm32l4_rev stm32_472_revs[] = {
{ 0x1000, "A" }, { 0x2000, "B" },
};
static const struct stm32l4_rev stm32_479_revs[] = {
{ 0x1000, "A" },
};
static const struct stm32l4_rev stm32_495_revs[] = {
{ 0x2001, "2.1" },
};
@ -205,6 +261,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 1024,
.has_dual_bank = true,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -215,6 +272,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 256,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -225,6 +283,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 128,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -235,6 +294,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 1024,
.has_dual_bank = true,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -245,6 +305,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 512,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -255,6 +316,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 128,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -265,6 +327,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 64,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -275,6 +338,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 128,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -285,6 +349,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 512,
.has_dual_bank = true,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -295,6 +360,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 2048,
.has_dual_bank = true,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -305,6 +371,29 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 1024,
.has_dual_bank = true,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
.id = 0x472,
.revs = stm32_472_revs,
.num_revs = ARRAY_SIZE(stm32_472_revs),
.device_str = "STM32L55/L56xx",
.max_flash_size_kb = 512,
.has_dual_bank = true,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l5_ns_flash_regs,
.fsize_addr = 0x0BFA05E0,
},
{
.id = 0x479,
.revs = stm32_479_revs,
.num_revs = ARRAY_SIZE(stm32_479_revs),
.device_str = "STM32G49/G4Axx",
.max_flash_size_kb = 512,
.has_dual_bank = false,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -315,6 +404,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 1024,
.has_dual_bank = false,
.flash_regs_base = 0x58004000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -325,6 +415,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 512,
.has_dual_bank = false,
.flash_regs_base = 0x58004000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
{
@ -335,6 +426,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.max_flash_size_kb = 256,
.has_dual_bank = false,
.flash_regs_base = 0x58004000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
},
};
@ -368,16 +460,37 @@ static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t r
return stm32l4_info->part_info->flash_regs_base + reg_offset;
}
static inline uint32_t stm32l4_get_flash_reg_by_index(struct flash_bank *bank,
enum stm32l4_flash_reg_index reg_index)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
return stm32l4_get_flash_reg(bank, stm32l4_info->flash_regs[reg_index]);
}
static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
{
return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value);
}
static inline int stm32l4_read_flash_reg_by_index(struct flash_bank *bank,
enum stm32l4_flash_reg_index reg_index, uint32_t *value)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
return stm32l4_read_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value);
}
static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
{
return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value);
}
static inline int stm32l4_write_flash_reg_by_index(struct flash_bank *bank,
enum stm32l4_flash_reg_index reg_index, uint32_t value)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
return stm32l4_write_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value);
}
static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
{
uint32_t status;
@ -385,7 +498,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* wait for busy to clear */
for (;;) {
retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status);
retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &status);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%" PRIx32 "", status);
@ -398,7 +511,6 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
alive_sleep(1);
}
if (status & FLASH_WRPERR) {
LOG_ERROR("stm32x device protected");
retval = ERROR_FAIL;
@ -411,7 +523,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* If this operation fails, we ignore it and report the original
* retval
*/
stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR);
stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, status & FLASH_ERROR);
}
return retval;
@ -424,7 +536,7 @@ static int stm32l4_unlock_reg(struct flash_bank *bank)
/* first check if not already unlocked
* otherwise writing on STM32_FLASH_KEYR will fail
*/
int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@ -432,15 +544,15 @@ static int stm32l4_unlock_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock flash registers */
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY1);
if (retval != ERROR_OK)
return retval;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY2);
if (retval != ERROR_OK)
return retval;
retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@ -456,7 +568,7 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank)
{
uint32_t ctrl;
int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@ -464,15 +576,15 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock option registers */
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY1);
if (retval != ERROR_OK)
return retval;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY2);
if (retval != ERROR_OK)
return retval;
retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl);
retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@ -508,14 +620,14 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
if (retval != ERROR_OK)
goto err_lock;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OPTSTRT);
if (retval != ERROR_OK)
goto err_lock;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
err_lock:
retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK);
retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK | FLASH_OPTLOCK);
if (retval != ERROR_OK)
return retval;
@ -528,11 +640,11 @@ static int stm32l4_protect_check(struct flash_bank *bank)
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar);
stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br);
stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1AR_INDEX, &wrp1ar);
stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1BR_INDEX, &wrp1br);
if (stm32l4_info->part_info->has_dual_bank) {
stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar);
stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br);
stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2AR_INDEX, &wrp2ar);
stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2BR_INDEX, &wrp2br);
} else {
/* prevent uninitialized errors */
wrp2ar = 0;
@ -611,7 +723,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
} else
erase_flags |= i << FLASH_PAGE_SHIFT;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, erase_flags);
if (retval != ERROR_OK)
break;
@ -623,7 +735,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
}
err_lock:
retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
if (retval != ERROR_OK)
return retval;
@ -651,7 +763,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
reg_value = ((last & 0xFF) << 16) | begin;
}
ret = stm32l4_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 0xffffffff);
ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP2AR_INDEX], reg_value, 0xffffffff);
}
/* Bank 1 */
reg_value = 0xFF; /* Default to bank un-protected */
@ -661,7 +773,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
reg_value = (end << 16) | (first & 0xFF);
}
ret = stm32l4_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 0xffffffff);
ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP1AR_INDEX], reg_value, 0xffffffff);
}
return ret;
@ -727,8 +839,8 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[2].value, 0, 32, address);
buf_set_u32(reg_params[3].value, 0, 32, count);
buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR));
buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR));
buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX));
buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX));
retval = target_run_flash_async_algorithm(target, buffer, count, 8,
0, NULL,
@ -748,7 +860,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
if (error != 0) {
LOG_ERROR("flash write failed = %08" PRIx32, error);
/* Clear but report errors */
stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error);
stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, error);
retval = ERROR_FAIL;
}
}
@ -825,7 +937,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
retval = stm32l4_write_block(bank, buffer, offset, count / 8);
err_lock:
retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
if (retval != ERROR_OK) {
LOG_ERROR("block write failed");
@ -838,17 +950,17 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
{
int retval;
/* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */
retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id);
if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) {
retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id);
if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) {
LOG_ERROR("can't get device id");
return (retval == ERROR_OK) ? ERROR_FAIL : retval;
}
/* try reading possible IDCODE registers, in the following order */
uint32_t DBGMCU_IDCODE[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5};
for (unsigned int i = 0; i < ARRAY_SIZE(DBGMCU_IDCODE); i++) {
retval = target_read_u32(bank->target, DBGMCU_IDCODE[i], id);
if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff))
return ERROR_OK;
}
return retval;
LOG_ERROR("can't get the device id");
return (retval == ERROR_OK) ? ERROR_FAIL : retval;
}
static int stm32l4_probe(struct flash_bank *bank)
@ -880,6 +992,7 @@ static int stm32l4_probe(struct flash_bank *bank)
}
part_info = stm32l4_info->part_info;
stm32l4_info->flash_regs = stm32l4_info->part_info->default_flash_regs;
char device_info[1024];
retval = bank->driver->info(bank, device_info, sizeof(device_info));
@ -913,7 +1026,7 @@ static int stm32l4_probe(struct flash_bank *bank)
assert((flash_size_kb != 0xffff) && flash_size_kb);
/* read flash option register */
retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options);
retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options);
if (retval != ERROR_OK)
return retval;
@ -924,6 +1037,7 @@ static int stm32l4_probe(struct flash_bank *bank)
int page_size_kb = 0;
stm32l4_info->dual_bank_mode = false;
bool use_dbank_bit = false;
switch (device_id) {
case 0x415: /* STM32L47/L48xx */
@ -952,6 +1066,7 @@ static int stm32l4_probe(struct flash_bank *bank)
case 0x464: /* STM32L41/L42xx */
case 0x466: /* STM32G03/G04xx */
case 0x468: /* STM32G43/G44xx */
case 0x479: /* STM32G49/G4Axx */
case 0x497: /* STM32WLEx */
/* single bank flash */
page_size_kb = 2;
@ -989,7 +1104,7 @@ static int stm32l4_probe(struct flash_bank *bank)
page_size_kb = 8;
num_pages = flash_size_kb / page_size_kb;
stm32l4_info->bank1_sectors = num_pages;
const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
if ((use_dbank_bit && (options & BIT(22))) ||
(!use_dbank_bit && (options & BIT(21)))) {
stm32l4_info->dual_bank_mode = true;
@ -998,6 +1113,23 @@ static int stm32l4_probe(struct flash_bank *bank)
stm32l4_info->bank1_sectors = num_pages / 2;
}
break;
case 0x472: /* STM32L55/L56xx */
/* STM32L55/L56xx can be single/dual bank:
* if size = 512K check DBANK bit(22)
* if size = 256K check DB256K bit(21)
*/
page_size_kb = 4;
num_pages = flash_size_kb / page_size_kb;
stm32l4_info->bank1_sectors = num_pages;
use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
if ((use_dbank_bit && (options & BIT(22))) ||
(!use_dbank_bit && (options & BIT(21)))) {
stm32l4_info->dual_bank_mode = true;
page_size_kb = 2;
num_pages = flash_size_kb / page_size_kb;
stm32l4_info->bank1_sectors = num_pages / 2;
}
break;
case 0x495: /* STM32WB5x */
case 0x496: /* STM32WB3x */
/* single bank flash */
@ -1086,19 +1218,17 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
for (unsigned int i = 0; i < part_info->num_revs; i++) {
if (rev_id == part_info->revs[i].rev) {
rev_str = part_info->revs[i].str;
if (rev_str != NULL) {
snprintf(buf, buf_size, "%s - Rev: %s%s",
part_info->device_str, rev_str, stm32l4_info->probed ?
(stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : "");
return ERROR_OK;
}
break;
}
}
snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s",
part_info->device_str, rev_id, stm32l4_info->probed ?
(stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : "");
int buf_len = snprintf(buf, buf_size, "%s - Rev %s : 0x%04x",
part_info->device_str, rev_str ? rev_str : "'unknown'", rev_id);
if (stm32l4_info->probed)
snprintf(buf + buf_len, buf_size - buf_len, " - %s-bank",
stm32l4_info->dual_bank_mode ? "Flash dual" : "Flash single");
return ERROR_OK;
} else {
snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families);
@ -1133,18 +1263,18 @@ static int stm32l4_mass_erase(struct flash_bank *bank)
if (retval != ERROR_OK)
goto err_lock;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action);
if (retval != ERROR_OK)
goto err_lock;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action | FLASH_STRT);
if (retval != ERROR_OK)
goto err_lock;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
err_lock:
retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
if (retval != ERROR_OK)
return retval;
@ -1257,7 +1387,7 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command)
* "Note: If the read protection is set while the debugger is still
* connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset."
*/
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH);
retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OBL_LAUNCH);
command_print(CMD, "stm32l4x option load completed. Power-on reset might be required");
@ -1288,7 +1418,8 @@ COMMAND_HANDLER(stm32l4_handle_lock_command)
}
/* set readout protection level 1 by erasing the RDP option byte */
if (stm32l4_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != ERROR_OK) {
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], 0, 0x000000FF) != ERROR_OK) {
command_print(CMD, "%s failed to lock device", bank->driver->name);
return ERROR_OK;
}
@ -1315,7 +1446,9 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
return ERROR_TARGET_NOT_HALTED;
}
if (stm32l4_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 0x000000FF) != ERROR_OK) {
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX],
RDP_LEVEL_0, 0x000000FF) != ERROR_OK) {
command_print(CMD, "%s failed to unlock device", bank->driver->name);
return ERROR_OK;
}

View File

@ -19,18 +19,6 @@
#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)

2449
src/flash/nor/stmqspi.c Normal file

File diff suppressed because it is too large Load Diff

125
src/flash/nor/stmqspi.h Normal file
View File

@ -0,0 +1,125 @@
/***************************************************************************
* Copyright (C) 2016 - 2018 by 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 *
* (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_STMQSPI_H
#define OPENOCD_FLASH_NOR_STMQSPI_H
#include "spi.h"
/* QSPI register offsets */
#define QSPI_CR (0x00) /* Control register */
#define QSPI_DCR (0x04) /* Device configuration register */
#define QSPI_SR (0x08) /* Status register */
#define QSPI_FCR (0x0C) /* Flag clear register */
#define QSPI_DLR (0x10) /* Data length register */
#define QSPI_CCR (0x14) /* Communication configuration register */
#define QSPI_AR (0x18) /* Address register */
#define QSPI_ABR (0x1C) /* Alternate bytes register */
#define QSPI_DR (0x20) /* Data register */
/* common bits in QSPI_CR and OCTOSPI_CR */
#define SPI_FSEL_FLASH 7 /* Select flash 2 */
#define SPI_DUAL_FLASH 6 /* Dual flash mode */
#define SPI_ABORT 1 /* Abort bit */
/* common bits in QSPI_DCR and OCTOSPI_DCR1 */
#define SPI_FSIZE_POS 16 /* bit position of FSIZE */
#define SPI_FSIZE_LEN 5 /* width of FSIZE field */
/* common bits in QSPI_SR/FCR and OCTOSPI_SR/FCR */
#define SPI_BUSY 5 /* Busy flag */
#define SPI_FTF 2 /* FIFO threshold flag */
#define SPI_TCF 1 /* Transfer complete flag */
/* fields in QSPI_CCR */
#define QSPI_DDRM 31 /* position of DDRM bit */
#define SPI_DMODE_POS 24 /* bit position of DMODE */
#define QSPI_DCYC_POS 18 /* bit position of DCYC */
#define QSPI_DCYC_LEN 5 /* width of DCYC field */
#define QSPI_DCYC_MASK ((BIT(QSPI_DCYC_LEN) - 1) << QSPI_DCYC_POS)
#define SPI_ADSIZE_POS 12 /* bit position of ADSIZE */
#define QSPI_WRITE_MODE 0x00000000U /* indirect write mode */
#define QSPI_READ_MODE 0x04000000U /* indirect read mode */
#define QSPI_MM_MODE 0x0C000000U /* memory mapped mode */
#define QSPI_ALTB_MODE 0x0003C000U /* alternate byte mode */
#define QSPI_4LINE_MODE 0x03000F00U /* 4 lines for data, addr, instr */
#define QSPI_NO_DATA (~0x03000000U) /* no data */
#define QSPI_NO_ALTB (~QSPI_ALTB_MODE) /* no alternate */
#define QSPI_NO_ADDR (~0x00000C00U) /* no address */
#define QSPI_ADDR3 (0x2U << SPI_ADSIZE_POS) /* 3 byte address */
#define QSPI_ADDR4 (0x3U << SPI_ADSIZE_POS) /* 4 byte address */
/* OCTOSPI register offsets */
#define OCTOSPI_CR (0x000) /* Control register */
#define OCTOSPI_DCR1 (0x008) /* Device configuration register 1 */
#define OCTOSPI_DCR2 (0x00C) /* Device configuration register 2 */
#define OCTOSPI_DCR3 (0x010) /* Device configuration register 3 */
#define OCTOSPI_SR (0x020) /* Status register */
#define OCTOSPI_FCR (0x024) /* Flag clear register */
#define OCTOSPI_DLR (0x040) /* Data length register */
#define OCTOSPI_AR (0x048) /* Address register */
#define OCTOSPI_DR (0x050) /* Data register */
#define OCTOSPI_CCR (0x100) /* Communication configuration register */
#define OCTOSPI_TCR (0x108) /* Timing configuration register */
#define OCTOSPI_IR (0x110) /* Instruction register */
#define OCTOSPI_WCCR (0x180) /* Write communication configuration register */
#define OCTOSPI_WIR (0x190) /* Write instruction register */
#define OCTOSPI_MAGIC (0x3FC) /* Magic ID register, deleted from RM, why? */
#define OCTO_MAGIC_ID 0xA3C5DD01 /* Magic ID, deleted from RM, why? */
/* additional bits in OCTOSPI_CR */
#define OCTOSPI_WRITE_MODE 0x00000000U /* indirect write mode */
#define OCTOSPI_READ_MODE 0x10000000U /* indirect read mode */
#define OCTOSPI_MM_MODE 0x30000000U /* memory mapped mode */
/* additional fields in OCTOSPI_DCR1 */
#define OCTOSPI_MTYP_POS (24) /* bit position of MTYP */
#define OCTOSPI_MTYP_LEN (3) /* width of MTYP field */
#define OCTOSPI_MTYP_MASK ((BIT(OCTOSPI_MTYP_LEN) - 1) << OCTOSPI_MTYP_POS)
/* fields in OCTOSPI_CCR */
#define OCTOSPI_ALTB_MODE 0x001F0000U /* alternate byte mode */
#define OCTOSPI_8LINE_MODE 0x0F003F3FU /* 8 lines DTR for data, addr, instr */
#define OCTOSPI_NO_DATA (~0x0F000000U) /* no data */
#define OCTOSPI_NO_ALTB (~OCTOSPI_ALTB_MODE) /* no alternate */
#define OCTOSPI_NO_ADDR (~0x00000F00U) /* no address */
#define OCTOSPI_ADDR3 (0x2U << SPI_ADSIZE_POS) /* 3 byte address */
#define OCTOSPI_ADDR4 (0x3U << SPI_ADSIZE_POS) /* 4 byte address */
#define OCTOSPI_DQSEN 29 /* DQS enable */
#define OCTOSPI_DDTR 27 /* DTR for data */
#define OCTOSPI_NO_DDTR (~BIT(OCTOSPI_DDTR)) /* no DTR for data, but maybe still DQS */
#define OCTOSPI_ISIZE_MASK (0x30) /* ISIZE field */
/* fields in OCTOSPI_TCR */
#define OCTOSPI_DCYC_POS 0 /* bit position of DCYC */
#define OCTOSPI_DCYC_LEN 5 /* width of DCYC field */
#define OCTOSPI_DCYC_MASK ((BIT(OCTOSPI_DCYC_LEN) - 1) << OCTOSPI_DCYC_POS)
#define IS_OCTOSPI (stmqspi_info->octo)
#define SPI_CR (IS_OCTOSPI ? OCTOSPI_CR : QSPI_CR)
#define SPI_DCR (IS_OCTOSPI ? OCTOSPI_DCR1 : QSPI_DCR)
#define SPI_SR (IS_OCTOSPI ? OCTOSPI_SR : QSPI_SR)
#define SPI_FCR (IS_OCTOSPI ? OCTOSPI_FCR : QSPI_FCR)
#define SPI_DLR (IS_OCTOSPI ? OCTOSPI_DLR : QSPI_DLR)
#define SPI_AR (IS_OCTOSPI ? OCTOSPI_AR : QSPI_AR)
#define SPI_DR (IS_OCTOSPI ? OCTOSPI_DR : QSPI_DR)
#define SPI_CCR (IS_OCTOSPI ? OCTOSPI_CCR : QSPI_CCR)
#endif /* OPENOCD_FLASH_NOR_STMQSPI_H */

View File

@ -41,34 +41,33 @@
#include <jtag/jtag.h>
#include <helper/time_support.h>
#define SMI_READ_REG(a) (_SMI_READ_REG(a))
#define _SMI_READ_REG(a) \
{ \
int __a; \
uint32_t __v; \
#define SMI_READ_REG(a) \
({ \
int _ret; \
uint32_t _value; \
\
__a = target_read_u32(target, io_base + (a), &__v); \
if (__a != ERROR_OK) \
return __a; \
__v; \
}
_ret = target_read_u32(target, io_base + (a), &_value); \
if (_ret != ERROR_OK) \
return _ret; \
_value; \
})
#define SMI_WRITE_REG(a, v) \
{ \
int __r; \
int _retval; \
\
__r = target_write_u32(target, io_base + (a), (v)); \
if (__r != ERROR_OK) \
return __r; \
_retval = target_write_u32(target, io_base + (a), (v)); \
if (_retval != ERROR_OK) \
return _retval; \
}
#define SMI_POLL_TFF(timeout) \
{ \
int __r; \
int _retval; \
\
__r = poll_tff(target, io_base, timeout); \
if (__r != ERROR_OK) \
return __r; \
_retval = poll_tff(target, io_base, timeout); \
if (_retval != ERROR_OK) \
return _retval; \
}
#define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \

View File

@ -30,7 +30,7 @@
* Implements Tcl commands used to access NOR flash facilities.
*/
COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
struct flash_bank **bank, bool do_probe)
{
const char *name = CMD_ARGV[name_index];
@ -440,6 +440,58 @@ COMMAND_HANDLER(handle_flash_write_image_command)
struct duration bench;
duration_start(&bench);
if (CMD_ARGC >= 2) {
image.base_address_set = true;
COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address);
} else {
image.base_address_set = false;
image.base_address = 0x0;
}
image.start_address_set = false;
retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL);
if (retval != ERROR_OK)
return retval;
retval = flash_write_unlock_verify(target, &image, &written, auto_erase,
auto_unlock, true, false);
if (retval != ERROR_OK) {
image_close(&image);
return retval;
}
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD, "wrote %" PRIu32 " bytes from file %s "
"in %fs (%0.3f KiB/s)", written, CMD_ARGV[0],
duration_elapsed(&bench), duration_kbps(&bench, written));
}
image_close(&image);
return retval;
}
COMMAND_HANDLER(handle_flash_verify_image_command)
{
struct target *target = get_current_target(CMD_CTX);
struct image image;
uint32_t verified;
int retval;
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!target) {
LOG_ERROR("no target selected");
return ERROR_FAIL;
}
struct duration bench;
duration_start(&bench);
if (CMD_ARGC >= 2) {
image.base_address_set = 1;
COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address);
@ -454,16 +506,17 @@ COMMAND_HANDLER(handle_flash_write_image_command)
if (retval != ERROR_OK)
return retval;
retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock);
retval = flash_write_unlock_verify(target, &image, &verified, false,
false, false, true);
if (retval != ERROR_OK) {
image_close(&image);
return retval;
}
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD, "wrote %" PRIu32 " bytes from file %s "
"in %fs (%0.3f KiB/s)", written, CMD_ARGV[0],
duration_elapsed(&bench), duration_kbps(&bench, written));
command_print(CMD, "verified %" PRIu32 " bytes from file %s "
"in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0],
duration_elapsed(&bench), duration_kbps(&bench, verified));
}
image_close(&image);
@ -1143,7 +1196,15 @@ static const struct command_registration flash_exec_command_handlers[] = {
.mode = COMMAND_EXEC,
.usage = "[erase] [unlock] filename [offset [file_type]]",
.help = "Write an image to flash. Optionally first unprotect "
"and/or erase the region to be used. Allow optional "
"and/or erase the region to be used. Allow optional "
"offset from beginning of bank (defaults to zero)",
},
{
.name = "verify_image",
.handler = handle_flash_verify_image_command,
.mode = COMMAND_EXEC,
.usage = "filename [offset [file_type]]",
.help = "Verify an image against flash. Allow optional "
"offset from beginning of bank (defaults to zero)",
},
{

View File

@ -45,7 +45,7 @@
#define ID_XCF32P 0x05059093
#define ID_MEANINGFUL_MASK 0x0FFFFFFF
const char *xcf_name_list[] = {
static const char * const xcf_name_list[] = {
"XCF08P",
"XCF16P",
"XCF32P",
@ -399,7 +399,7 @@ static void flip_u8(uint8_t *out, const uint8_t *in, int len)
* Function presumes need of bit reversing if it can not exactly detects
* the opposite.
*/
bool need_bit_reverse(const uint8_t *buffer)
static bool need_bit_reverse(const uint8_t *buffer)
{
const size_t L = 20;
uint8_t reference[L];

View File

@ -116,6 +116,7 @@ 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 stm32l5x args { eval stm32l4x $args }
proc stm32wbx args { eval stm32l4x $args }
proc stm32wlx args { eval stm32l4x $args }

View File

@ -349,7 +349,9 @@ static int register_command_handler(struct command_context *cmd_ctx,
{
Jim_Interp *interp = cmd_ctx->interp;
#if 0
LOG_DEBUG("registering '%s'...", c->name);
#endif
Jim_CmdProc *func = c->handler ? &script_command : &command_unknown;
int retval = Jim_CreateCommand(interp, c->name, func, c, NULL);
@ -920,39 +922,29 @@ COMMAND_HANDLER(handle_help_command)
bool full = strcmp(CMD_NAME, "help") == 0;
int retval;
struct command *c = CMD_CTX->commands;
char *cmd_match = NULL;
char *cmd_match;
if (CMD_ARGC == 0)
cmd_match = "";
else if (CMD_ARGC >= 1) {
unsigned i;
if (CMD_ARGC <= 0)
cmd_match = strdup("");
for (i = 0; i < CMD_ARGC; ++i) {
if (NULL != cmd_match) {
char *prev = cmd_match;
else {
cmd_match = strdup(CMD_ARGV[0]);
cmd_match = alloc_printf("%s %s", cmd_match, CMD_ARGV[i]);
free(prev);
if (NULL == cmd_match) {
LOG_ERROR("unable to build search string");
return -ENOMEM;
}
} else {
cmd_match = alloc_printf("%s", CMD_ARGV[i]);
if (NULL == cmd_match) {
LOG_ERROR("unable to build search string");
return -ENOMEM;
}
}
for (unsigned int i = 1; i < CMD_ARGC && cmd_match; ++i) {
char *prev = cmd_match;
cmd_match = alloc_printf("%s %s", prev, CMD_ARGV[i]);
free(prev);
}
} else
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (cmd_match == NULL) {
LOG_ERROR("unable to build search string");
return -ENOMEM;
}
retval = CALL_COMMAND_HANDLER(command_help_show_list,
c, 0, full, cmd_match);
if (CMD_ARGC >= 1)
free(cmd_match);
free(cmd_match);
return retval;
}

View File

@ -1,4 +1,9 @@
/* Autogenerated with update_jep106.pl*/
/*
* Should be autogenerated with update_jep106.pl but latest
* file from JEDEC is only available in PDF form. The PDF
* also breaks the pdftotext flow due to embedded watermarks.
* Created with a mix of scripts and manual editing.
*/
[0][0x01 - 1] = "AMD",
[0][0x02 - 1] = "AMI",
[0][0x03 - 1] = "Fairchild",
@ -194,7 +199,7 @@
[1][0x43 - 1] = "Suwa Electronics",
[1][0x44 - 1] = "Transmeta",
[1][0x45 - 1] = "Micron CMS",
[1][0x46 - 1] = "American Computer & Digital",
[1][0x46 - 1] = "American Computer & Digital Components Inc",
[1][0x47 - 1] = "Enhance 3000 Inc",
[1][0x48 - 1] = "Tower Semiconductor",
[1][0x49 - 1] = "CPU Design",
@ -438,7 +443,7 @@
[3][0x3b - 1] = "Concept Computer",
[3][0x3c - 1] = "SILCOM",
[3][0x3d - 1] = "3Dlabs",
[3][0x3e - 1] = "ct Magazine",
[3][0x3e - 1] = "c't Magazine",
[3][0x3f - 1] = "Sanera Systems",
[3][0x40 - 1] = "Silicon Packets",
[3][0x41 - 1] = "Viasystems Group",
@ -532,7 +537,7 @@
[4][0x1b - 1] = "Phonex Broadband",
[4][0x1c - 1] = "Skyworks Solutions",
[4][0x1d - 1] = "Entropic Communications",
[4][0x1e - 1] = "IM Intelligent Memory Ltd",
[4][0x1e - 1] = "I'M Intelligent Memory Ltd",
[4][0x1f - 1] = "Zensys A/S",
[4][0x20 - 1] = "Legend Silicon Corp",
[4][0x21 - 1] = "Sci-worx GmbH",
@ -610,7 +615,7 @@
[4][0x69 - 1] = "Century Micro Inc",
[4][0x6a - 1] = "Icera Semiconductor",
[4][0x6b - 1] = "Mediaworks Integrated Systems",
[4][0x6c - 1] = "ONeil Product Development",
[4][0x6c - 1] = "O'Neil Product Development",
[4][0x6d - 1] = "Supreme Top Technology Ltd",
[4][0x6e - 1] = "MicroDisplay Corporation",
[4][0x6f - 1] = "Team Group Inc",
@ -837,7 +842,7 @@
[6][0x50 - 1] = "Silego Technology Inc",
[6][0x51 - 1] = "Kinglife",
[6][0x52 - 1] = "Ability Industries Ltd",
[6][0x53 - 1] = "Silicon Power Computer &",
[6][0x53 - 1] = "Silicon Power Computer & Communications",
[6][0x54 - 1] = "Augusta Technology Inc",
[6][0x55 - 1] = "Nantronics Semiconductors",
[6][0x56 - 1] = "Hilscher Gesellschaft",
@ -961,7 +966,7 @@
[7][0x4e - 1] = "Mustang",
[7][0x4f - 1] = "Orca Systems",
[7][0x50 - 1] = "Passif Semiconductor",
[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing)",
[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing) Inc",
[7][0x52 - 1] = "Memphis Electronic",
[7][0x53 - 1] = "Beckhoff Automation GmbH",
[7][0x54 - 1] = "Harmony Semiconductor Corp",
@ -985,7 +990,7 @@
[7][0x66 - 1] = "Avalanche Technology",
[7][0x67 - 1] = "R&D Center ELVEES OJSC",
[7][0x68 - 1] = "KingboMars Technology Co Ltd",
[7][0x69 - 1] = "High Bridge Solutions Industria",
[7][0x69 - 1] = "High Bridge Solutions Industria Eletronica",
[7][0x6a - 1] = "Transcend Technology Co Ltd",
[7][0x6b - 1] = "Everspin Technologies",
[7][0x6c - 1] = "Hon-Hai Precision",
@ -1031,7 +1036,7 @@
[8][0x17 - 1] = "Axell Corporation",
[8][0x18 - 1] = "Essencore Limited",
[8][0x19 - 1] = "Phytium",
[8][0x1a - 1] = "Xian UniIC Semiconductors Co Ltd",
[8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd",
[8][0x1b - 1] = "Ambiq Micro",
[8][0x1c - 1] = "eveRAM Technology Inc",
[8][0x1d - 1] = "Infomax",
@ -1083,7 +1088,7 @@
[8][0x4b - 1] = "in2H2 inc",
[8][0x4c - 1] = "Shenzhen Pango Microsystems Co Ltd",
[8][0x4d - 1] = "Vasekey",
[8][0x4e - 1] = "Cal-Comp Industria de",
[8][0x4e - 1] = "Cal-Comp Industria de Semicondutores",
[8][0x4f - 1] = "Eyenix Co Ltd",
[8][0x50 - 1] = "Heoriady",
[8][0x51 - 1] = "Accelerated Memory Production Inc",
@ -1114,7 +1119,7 @@
[8][0x6a - 1] = "Axign",
[8][0x6b - 1] = "Kingred Electronic Technology Ltd",
[8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.",
[8][0x6d - 1] = "Guangzhou Si Nuo Electronic",
[8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.",
[8][0x6e - 1] = "Crocus Technology Inc",
[8][0x6f - 1] = "Creative Chips GmbH",
[8][0x70 - 1] = "GE Aviation Systems LLC.",
@ -1130,6 +1135,8 @@
[8][0x7a - 1] = "AltoBeam",
[8][0x7b - 1] = "Wave Computing",
[8][0x7c - 1] = "Beijing TrustNet Technology Co Ltd",
[8][0x7d - 1] = "Innovium Inc",
[8][0x7e - 1] = "Starsway Technology Limited",
[9][0x01 - 1] = "Weltronics Co LTD",
[9][0x02 - 1] = "VMware Inc",
[9][0x03 - 1] = "Hewlett Packard Enterprise",
@ -1160,6 +1167,7 @@
[9][0x1c - 1] = "MemxPro Inc",
[9][0x1d - 1] = "Tammuz Co Ltd",
[9][0x1e - 1] = "Allwinner Technology",
[9][0x1f - 1] = "Shenzhen City Futian District Qing Xuan Tong Computer Trading Firm",
[9][0x20 - 1] = "XMC",
[9][0x21 - 1] = "Teclast",
[9][0x22 - 1] = "Maxsun",
@ -1272,7 +1280,7 @@
[10][0x0f - 1] = "UNIC Memory Technology Co Ltd",
[10][0x10 - 1] = "Shenzhen Huafeng Science Technology",
[10][0x11 - 1] = "ChangXin Memory Technologies Inc",
[10][0x12 - 1] = "Guangzhou Xinyi Heng Computer",
[10][0x12 - 1] = "Guangzhou Xinyi Heng Computer Trading Firm",
[10][0x13 - 1] = "SambaNova Systems",
[10][0x14 - 1] = "V-GEN",
[10][0x15 - 1] = "Jump Trading",
@ -1291,7 +1299,7 @@
[10][0x22 - 1] = "Shenzhen Chuangshifeida Technology",
[10][0x23 - 1] = "Guangzhou MiaoYuanJi Technology",
[10][0x24 - 1] = "ADVAN Inc",
[10][0x25 - 1] = "Shenzhen Qianhai Weishengda",
[10][0x25 - 1] = "Shenzhen Qianhai Weishengda Electronic Commerce Company Ltd",
[10][0x26 - 1] = "Guangzhou Guang Xie Cheng Trading",
[10][0x27 - 1] = "StarRam International Co Ltd",
[10][0x28 - 1] = "Shen Zhen XinShenHua Tech Co Ltd",
@ -1321,7 +1329,7 @@
[10][0x40 - 1] = "Shenzhen Zhongguang Yunhe Trading",
[10][0x41 - 1] = "Smart Shine(QingDao) Microelectronics",
[10][0x42 - 1] = "Thermaltake Technology Co Ltd",
[10][0x43 - 1] = "Shenzhen OYang Maile Technology Ltd",
[10][0x43 - 1] = "Shenzhen O'Yang Maile Technology Ltd",
[10][0x44 - 1] = "UPMEM",
[10][0x45 - 1] = "Chun Well Technology Holding Limited",
[10][0x46 - 1] = "Astera Labs Inc",
@ -1397,7 +1405,7 @@
[11][0x0e - 1] = "MLOONG",
[11][0x0f - 1] = "Quadratica LLC",
[11][0x10 - 1] = "Anpec Electronics",
[11][0x11 - 1] = "Xian Morebeck Semiconductor Tech Co",
[11][0x11 - 1] = "Xi'an Morebeck Semiconductor Tech Co",
[11][0x12 - 1] = "Kingbank Technology Co Ltd",
[11][0x13 - 1] = "ITRenew Inc",
[11][0x14 - 1] = "Shenzhen Eaget Innovation Tech Ltd",

View File

@ -35,8 +35,8 @@
#ifdef _WIN32
PROCESS_INFORMATION proc_info;
HANDLE aice_pipe_output[2];
HANDLE aice_pipe_input[2];
static HANDLE aice_pipe_output[2];
static HANDLE aice_pipe_input[2];
static int aice_pipe_write(const void *buffer, int count)
{
@ -158,8 +158,8 @@ static int aice_pipe_open(struct aice_port_param_s *param)
#else
int aice_pipe_output[2];
int aice_pipe_input[2];
static int aice_pipe_output[2];
static int aice_pipe_input[2];
static int aice_pipe_write(const void *buffer, int count)
{

View File

@ -683,7 +683,7 @@ int aice_write_ctrl(uint32_t address, uint32_t data)
return ERROR_OK;
}
int aice_read_dtr(uint8_t target_id, uint32_t *data)
static int aice_read_dtr(uint8_t target_id, uint32_t *data)
{
int retry_times = 0;
@ -733,7 +733,7 @@ int aice_read_dtr(uint8_t target_id, uint32_t *data)
return ERROR_OK;
}
int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx)
static int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx)
{
int retry_times = 0;
@ -784,7 +784,7 @@ int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx)
return ERROR_OK;
}
int aice_write_dtr(uint8_t target_id, uint32_t data)
static int aice_write_dtr(uint8_t target_id, uint32_t data)
{
int retry_times = 0;
@ -836,7 +836,7 @@ int aice_write_dtr(uint8_t target_id, uint32_t data)
return ERROR_OK;
}
int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx)
static int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx)
{
int retry_times = 0;
@ -887,7 +887,7 @@ int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx)
return ERROR_OK;
}
int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data)
static int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data)
{
int retry_times = 0;
@ -936,7 +936,7 @@ int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data)
return ERROR_OK;
}
int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data)
static int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data)
{
int retry_times = 0;
@ -992,7 +992,7 @@ int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data)
return ERROR_OK;
}
int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data)
static int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data)
{
int retry_times = 0;
@ -1042,7 +1042,7 @@ int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data)
return ERROR_OK;
}
int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data)
static int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data)
{
int retry_times = 0;
@ -1236,7 +1236,7 @@ static int aice_do_execute(uint8_t target_id)
return ERROR_OK;
}
int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data)
static int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data)
{
int retry_times = 0;
@ -1290,7 +1290,7 @@ int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data)
return ERROR_OK;
}
int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data)
static int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data)
{
int retry_times = 0;
@ -1345,7 +1345,7 @@ int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data)
return ERROR_OK;
}
int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data)
static int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data)
{
int retry_times = 0;
@ -1400,7 +1400,7 @@ int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data)
return ERROR_OK;
}
int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words)
static int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words)
{
int retry_times = 0;
@ -1450,7 +1450,7 @@ int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words)
return ERROR_OK;
}
int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_words)
static int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_words)
{
int retry_times = 0;
@ -1506,7 +1506,7 @@ int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_w
return ERROR_OK;
}
int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data)
static int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data)
{
int retry_times = 0;
@ -1556,7 +1556,7 @@ int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data)
return ERROR_OK;
}
int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data)
static int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data)
{
int retry_times = 0;
@ -1606,7 +1606,7 @@ int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data)
return ERROR_OK;
}
int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data)
static int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data)
{
int retry_times = 0;
@ -1657,7 +1657,7 @@ int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data)
return ERROR_OK;
}
int aice_batch_buffer_read(uint8_t buf_index, uint32_t *word, uint32_t num_of_words)
static int aice_batch_buffer_read(uint8_t buf_index, uint32_t *word, uint32_t num_of_words)
{
int retry_times = 0;
@ -1760,7 +1760,7 @@ int aice_batch_buffer_write(uint8_t buf_index, const uint8_t *word, uint32_t num
typedef int (*read_mem_func_t)(uint32_t coreid, uint32_t address, uint32_t *data);
typedef int (*write_mem_func_t)(uint32_t coreid, uint32_t address, uint32_t data);
struct aice_nds32_info core_info[AICE_MAX_NUM_CORE];
static struct aice_nds32_info core_info[AICE_MAX_NUM_CORE];
static uint8_t total_num_of_core;
static char *custom_srst_script;

View File

@ -209,7 +209,7 @@ unsigned jtag_tap_count_enabled(void)
}
/** Append a new TAP to the chain of all taps. */
void jtag_tap_add(struct jtag_tap *t)
static void jtag_tap_add(struct jtag_tap *t)
{
unsigned jtag_num_taps = 0;
@ -953,12 +953,12 @@ int default_interface_jtag_execute_queue(void)
int result = jtag->jtag_ops->execute_queue();
#if !BUILD_ZY1000
#if !HAVE_JTAG_MINIDRIVER_H
/* 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. */
* aren't accessible here. Use HAVE_JTAG_MINIDRIVER_H */
struct jtag_command *cmd = jtag_command_queue;
while (debug_level >= LOG_LVL_DEBUG_IO && cmd) {
switch (cmd->type) {

View File

@ -170,8 +170,15 @@ endif
if OPENJTAG
DRIVERFILES += %D%/openjtag.c
endif
if CMSIS_DAP
DRIVERFILES += %D%/cmsis_dap_usb.c
if CMSIS_DAP_HID
DRIVERFILES += %D%/cmsis_dap_usb_hid.c
DRIVERFILES += %D%/cmsis_dap.c
endif
if CMSIS_DAP_USB
DRIVERFILES += %D%/cmsis_dap_usb_bulk.c
if !CMSIS_DAP_HID
DRIVERFILES += %D%/cmsis_dap.c
endif
endif
if IMX_GPIO
DRIVERFILES += %D%/imx_gpio.c
@ -187,7 +194,9 @@ DRIVERHEADERS = \
%D%/bitbang.h \
%D%/bitq.h \
%D%/jtag_usb_common.h \
%D%/libftdi_helper.h \
%D%/libusb_helper.h \
%D%/cmsis_dap.h \
%D%/minidriver_imp.h \
%D%/mpsse.h \
%D%/rlink.h \

View File

@ -1,4 +1,7 @@
/***************************************************************************
* Copyright (C) 2018 by Mickaël Thomas *
* mickael9@gmail.com *
* *
* Copyright (C) 2016 by Maksym Hilliaka *
* oter@frozen-team.com *
* *
@ -38,12 +41,17 @@
#include <jtag/commands.h>
#include <jtag/tcl.h>
#include <hidapi.h>
#include "cmsis_dap.h"
/*
* See CMSIS-DAP documentation:
* Version 0.01 - Beta.
*/
static const struct cmsis_dap_backend *const cmsis_dap_backends[] = {
#if BUILD_CMSIS_DAP_USB == 1
&cmsis_dap_usb_backend,
#endif
#if BUILD_CMSIS_DAP_HID == 1
&cmsis_dap_hid_backend,
#endif
};
/* USB Config */
@ -52,6 +60,7 @@
* PID 0xf001: LPC-Link-II CMSIS_DAP
* PID 0xf002: OPEN-SDA CMSIS_DAP (Freedom Board)
* PID 0x2722: Keil ULINK2 CMSIS-DAP
* PID 0x2750: Keil ULINKplus CMSIS-DAP
*
* VID 0x0d28: mbed Software
* PID 0x0204: MBED CMSIS-DAP
@ -61,10 +70,10 @@
/* vid = pid = 0 marks the end of the list */
static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 };
static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 };
static wchar_t *cmsis_dap_serial;
static char *cmsis_dap_serial;
static int cmsis_dap_backend = -1;
static bool swd_mode;
#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */
#define USB_TIMEOUT 1000
/* CMSIS-DAP General Commands */
@ -163,14 +172,6 @@ static const char * const info_caps_str[] = {
/* max clock speed (kHz) */
#define DAP_MAX_CLOCK 5000
struct cmsis_dap {
hid_device *dev_handle;
uint16_t packet_size;
int packet_count;
uint8_t *packet_buffer;
uint8_t caps;
uint8_t mode;
};
struct pending_transfer_result {
uint8_t cmd;
@ -223,91 +224,10 @@ static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST;
static struct cmsis_dap *cmsis_dap_handle;
static int cmsis_dap_usb_open(void)
static int cmsis_dap_open(void)
{
hid_device *dev = NULL;
int i;
struct hid_device_info *devs, *cur_dev;
unsigned short target_vid, target_pid;
bool found = false;
target_vid = 0;
target_pid = 0;
if (hid_init() != 0) {
LOG_ERROR("unable to open HIDAPI");
return ERROR_FAIL;
}
/*
* The CMSIS-DAP specification stipulates:
* "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the
* debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer."
*/
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
while (NULL != cur_dev) {
if (0 == cmsis_dap_vid[0]) {
if (NULL == cur_dev->product_string) {
LOG_DEBUG("Cannot read product string of device 0x%x:0x%x",
cur_dev->vendor_id, cur_dev->product_id);
} else {
if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) {
/* if the user hasn't specified VID:PID *and*
* product string contains "CMSIS-DAP", pick it
*/
found = true;
}
}
} else {
/* otherwise, exhaustively compare against all VID:PID in list */
for (i = 0; cmsis_dap_vid[i] || cmsis_dap_pid[i]; i++) {
if ((cmsis_dap_vid[i] == cur_dev->vendor_id) && (cmsis_dap_pid[i] == cur_dev->product_id))
found = true;
}
if (cmsis_dap_vid[i] || cmsis_dap_pid[i])
found = true;
}
/* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */
if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0)
found = false;
if (found) {
/* we have found an adapter, so exit further checks */
/* check serial number matches if given */
if (cmsis_dap_serial != NULL) {
if ((cur_dev->serial_number != NULL) && wcscmp(cmsis_dap_serial, cur_dev->serial_number) == 0) {
break;
}
} else
break;
found = false;
}
cur_dev = cur_dev->next;
}
if (NULL != cur_dev) {
target_vid = cur_dev->vendor_id;
target_pid = cur_dev->product_id;
}
if (target_vid == 0 && target_pid == 0) {
LOG_ERROR("unable to find CMSIS-DAP device");
hid_free_enumeration(devs);
return ERROR_FAIL;
}
dev = hid_open_path(cur_dev->path);
hid_free_enumeration(devs);
if (dev == NULL) {
LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid);
return ERROR_FAIL;
}
const struct cmsis_dap_backend *backend = NULL;
struct cmsis_dap *dap = malloc(sizeof(struct cmsis_dap));
if (dap == NULL) {
@ -315,42 +235,55 @@ static int cmsis_dap_usb_open(void)
return ERROR_FAIL;
}
dap->dev_handle = dev;
dap->caps = 0;
dap->mode = 0;
dap->packet_size = 0; /* initialized by backend */
cmsis_dap_handle = dap;
if (cmsis_dap_backend >= 0) {
/* Use forced backend */
backend = cmsis_dap_backends[cmsis_dap_backend];
if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, cmsis_dap_serial) != ERROR_OK)
backend = NULL;
} else {
/* Try all backends */
for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) {
backend = cmsis_dap_backends[i];
if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, cmsis_dap_serial) == ERROR_OK)
break;
else
backend = NULL;
}
}
/* allocate default packet buffer, may be changed later.
* currently with HIDAPI we have no way of getting the output report length
* without this info we cannot communicate with the adapter.
* For the moment we ahve to hard code the packet size */
int packet_size = PACKET_SIZE;
/* atmel cmsis-dap uses 512 byte reports */
/* except when it doesn't e.g. with mEDBG on SAMD10 Xplained
* board */
/* TODO: HID report descriptor should be parsed instead of
* hardcoding a match by VID */
if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175)
packet_size = 512 + 1;
cmsis_dap_handle->packet_buffer = malloc(packet_size);
cmsis_dap_handle->packet_size = packet_size;
if (cmsis_dap_handle->packet_buffer == NULL) {
LOG_ERROR("unable to allocate memory");
if (backend == NULL) {
LOG_ERROR("unable to find a matching CMSIS-DAP device");
free(dap);
return ERROR_FAIL;
}
assert(dap->packet_size > 0);
dap->backend = backend;
dap->packet_buffer = malloc(dap->packet_size);
if (dap->packet_buffer == NULL) {
LOG_ERROR("unable to allocate memory");
dap->backend->close(dap);
free(dap);
return ERROR_FAIL;
}
cmsis_dap_handle = dap;
return ERROR_OK;
}
static void cmsis_dap_usb_close(struct cmsis_dap *dap)
static void cmsis_dap_close(struct cmsis_dap *dap)
{
hid_close(dap->dev_handle);
hid_exit();
if (dap->backend) {
dap->backend->close(dap);
dap->backend = NULL;
}
free(cmsis_dap_handle->packet_buffer);
free(cmsis_dap_handle);
@ -364,47 +297,27 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
}
}
static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen)
{
#ifdef CMSIS_DAP_JTAG_DEBUG
LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]);
#endif
/* Pad the rest of the TX buffer with 0's */
memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen);
/* write data to device */
int retval = hid_write(dap->dev_handle, dap->packet_buffer, dap->packet_size);
if (retval == -1) {
LOG_ERROR("error writing data: %ls", hid_error(dap->dev_handle));
return ERROR_FAIL;
}
return ERROR_OK;
}
/* Send a message and receive the reply */
static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen)
{
if (pending_fifo_block_count) {
LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count);
while (pending_fifo_block_count) {
hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10);
dap->backend->read(dap, 10);
pending_fifo_block_count--;
}
pending_fifo_put_idx = 0;
pending_fifo_get_idx = 0;
}
int retval = cmsis_dap_usb_write(dap, txlen);
if (retval != ERROR_OK)
int retval = dap->backend->write(dap, txlen, USB_TIMEOUT);
if (retval < 0)
return retval;
/* get reply */
retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT);
if (retval == -1 || retval == 0) {
LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle));
return ERROR_FAIL;
}
retval = dap->backend->read(dap, USB_TIMEOUT);
if (retval < 0)
return retval;
return ERROR_OK;
}
@ -422,7 +335,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay
buffer[5] = (delay >> 8) & 0xff;
buffer[6] = (delay >> 16) & 0xff;
buffer[7] = (delay >> 24) & 0xff;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 8);
retval = cmsis_dap_xfer(cmsis_dap_handle, 8);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed.");
@ -448,7 +361,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock)
buffer[3] = (swj_clock >> 8) & 0xff;
buffer[4] = (swj_clock >> 16) & 0xff;
buffer[5] = (swj_clock >> 24) & 0xff;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 6);
retval = cmsis_dap_xfer(cmsis_dap_handle, 6);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed.");
@ -477,7 +390,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence
buffer[2] = s_len;
bit_copy(&buffer[3], 0, sequence, 0, s_len);
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3);
retval = cmsis_dap_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3);
if (retval != ERROR_OK || buffer[1] != DAP_OK)
return ERROR_FAIL;
@ -493,7 +406,7 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data)
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_INFO;
buffer[2] = info;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3);
retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command CMD_INFO failed.");
@ -514,7 +427,7 @@ static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state)
buffer[1] = CMD_DAP_LED;
buffer[2] = led;
buffer[3] = state;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4);
retval = cmsis_dap_xfer(cmsis_dap_handle, 4);
if (retval != ERROR_OK || buffer[1] != 0x00) {
LOG_ERROR("CMSIS-DAP command CMD_LED failed.");
@ -532,7 +445,7 @@ static int cmsis_dap_cmd_DAP_Connect(uint8_t mode)
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_CONNECT;
buffer[2] = mode;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3);
retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed.");
@ -554,7 +467,7 @@ static int cmsis_dap_cmd_DAP_Disconnect(void)
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_DISCONNECT;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 2);
retval = cmsis_dap_xfer(cmsis_dap_handle, 2);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed.");
@ -576,7 +489,7 @@ static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count,
buffer[4] = (retry_count >> 8) & 0xff;
buffer[5] = match_retry & 0xff;
buffer[6] = (match_retry >> 8) & 0xff;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7);
retval = cmsis_dap_xfer(cmsis_dap_handle, 7);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed.");
@ -594,7 +507,7 @@ static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg)
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_SWD_CONFIGURE;
buffer[2] = cfg;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3);
retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed.");
@ -614,7 +527,7 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
buffer[1] = CMD_DAP_DELAY;
buffer[2] = delay_us & 0xff;
buffer[3] = (delay_us >> 8) & 0xff;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4);
retval = cmsis_dap_xfer(cmsis_dap_handle, 4);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_Delay failed.");
@ -684,9 +597,14 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
}
}
queued_retval = cmsis_dap_usb_write(dap, idx);
if (queued_retval != ERROR_OK)
int retval = dap->backend->write(dap, idx, USB_TIMEOUT);
if (retval < 0) {
queued_retval = retval;
goto skip;
} else {
queued_retval = ERROR_OK;
}
pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count;
pending_fifo_block_count++;
@ -708,12 +626,12 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
LOG_ERROR("no pending write");
/* get reply */
int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms);
if (retval == 0 && timeout_ms < USB_TIMEOUT)
int retval = dap->backend->read(dap, timeout_ms);
if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < USB_TIMEOUT)
return;
if (retval == -1 || retval == 0) {
LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle));
if (retval <= 0) {
LOG_DEBUG("error reading data");
queued_retval = ERROR_FAIL;
goto skip;
}
@ -969,7 +887,7 @@ static int cmsis_dap_init(void)
int retval;
uint8_t *data;
retval = cmsis_dap_usb_open();
retval = cmsis_dap_open();
if (retval != ERROR_OK)
return retval;
@ -1048,7 +966,7 @@ static int cmsis_dap_init(void)
LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt);
}
LOG_DEBUG("Allocating FIFO for %d pending HID requests", cmsis_dap_handle->packet_count);
LOG_DEBUG("Allocating FIFO for %d pending packets", cmsis_dap_handle->packet_count);
for (int i = 0; i < cmsis_dap_handle->packet_count; i++) {
pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result));
if (!pending_fifo[i].transfers) {
@ -1120,7 +1038,7 @@ static int cmsis_dap_quit(void)
cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF);
cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF);
cmsis_dap_usb_close(cmsis_dap_handle);
cmsis_dap_close(cmsis_dap_handle);
return ERROR_OK;
}
@ -1261,7 +1179,7 @@ static void cmsis_dap_flush(void)
#endif
/* send command to USB device */
int retval = cmsis_dap_usb_xfer(cmsis_dap_handle, queued_seq_buf_end + 3);
int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 3);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed.");
exit(-1);
@ -1668,7 +1586,7 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command)
for (i = 0; i < CMD_ARGC; i++)
buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16);
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, CMD_ARGC + 1);
retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC + 1);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command failed.");
@ -1712,21 +1630,32 @@ COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command)
}
COMMAND_HANDLER(cmsis_dap_handle_serial_command)
{
if (CMD_ARGC == 1)
cmsis_dap_serial = strdup(CMD_ARGV[0]);
else
LOG_ERROR("expected exactly one argument to cmsis_dap_serial <serial-number>");
return ERROR_OK;
}
COMMAND_HANDLER(cmsis_dap_handle_backend_command)
{
if (CMD_ARGC == 1) {
size_t len = mbstowcs(NULL, CMD_ARGV[0], 0);
cmsis_dap_serial = calloc(len + 1, sizeof(wchar_t));
if (cmsis_dap_serial == NULL) {
LOG_ERROR("unable to allocate memory");
return ERROR_OK;
}
if (mbstowcs(cmsis_dap_serial, CMD_ARGV[0], len + 1) == (size_t)-1) {
free(cmsis_dap_serial);
cmsis_dap_serial = NULL;
LOG_ERROR("unable to convert serial");
if (strcmp(CMD_ARGV[0], "auto") == 0) {
cmsis_dap_backend = -1; /* autoselect */
} else {
for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) {
if (strcasecmp(cmsis_dap_backends[i]->name, CMD_ARGV[0]) == 0) {
cmsis_dap_backend = i;
return ERROR_OK;
}
}
LOG_ERROR("invalid backend argument to cmsis_dap_backend <backend>");
}
} else {
LOG_ERROR("expected exactly one argument to cmsis_dap_serial <serial-number>");
LOG_ERROR("expected exactly one argument to cmsis_dap_backend <backend>");
}
return ERROR_OK;
@ -1750,6 +1679,7 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = {
COMMAND_REGISTRATION_DONE
};
static const struct command_registration cmsis_dap_command_handlers[] = {
{
.name = "cmsis-dap",
@ -1772,6 +1702,22 @@ static const struct command_registration cmsis_dap_command_handlers[] = {
.help = "set the serial number of the adapter",
.usage = "serial_string",
},
{
.name = "cmsis_dap_backend",
.handler = &cmsis_dap_handle_backend_command,
.mode = COMMAND_CONFIG,
.help = "set the communication backend to use (USB bulk or HID).",
.usage = "(auto | usb_bulk | hid)",
},
#if BUILD_CMSIS_DAP_USB
{
.name = "cmsis_dap_usb",
.chain = cmsis_dap_usb_subcommand_handlers,
.mode = COMMAND_ANY,
.help = "USB bulk backend-specific commands",
.usage = "<cmd>",
},
#endif
COMMAND_REGISTRATION_DONE
};

View File

@ -0,0 +1,32 @@
#ifndef OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H
#define OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H
#include <stdint.h>
struct cmsis_dap_backend;
struct cmsis_dap_backend_data;
struct command_registration;
struct cmsis_dap {
struct cmsis_dap_backend_data *bdata;
const struct cmsis_dap_backend *backend;
uint16_t packet_size;
int packet_count;
uint8_t *packet_buffer;
uint8_t caps;
uint8_t mode;
};
struct cmsis_dap_backend {
const char *name;
int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial);
void (*close)(struct cmsis_dap *dap);
int (*read)(struct cmsis_dap *dap, int timeout_ms);
int (*write)(struct cmsis_dap *dap, int len, int timeout_ms);
};
extern const struct cmsis_dap_backend cmsis_dap_hid_backend;
extern const struct cmsis_dap_backend cmsis_dap_usb_backend;
extern const struct command_registration cmsis_dap_usb_subcommand_handlers[];
#endif

View File

@ -0,0 +1,454 @@
/***************************************************************************
* Copyright (C) 2018 by Mickaël Thomas *
* mickael9@gmail.com *
* *
* Copyright (C) 2016 by Maksym Hilliaka *
* oter@frozen-team.com *
* *
* Copyright (C) 2016 by Phillip Pearson *
* pp@myelin.co.nz *
* *
* Copyright (C) 2014 by Paul Fertser *
* fercerpav@gmail.com *
* *
* Copyright (C) 2013 by mike brown *
* mike@theshedworks.org.uk *
* *
* Copyright (C) 2013 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <libusb.h>
#include <helper/log.h>
#include "cmsis_dap.h"
struct cmsis_dap_backend_data {
libusb_context *usb_ctx;
libusb_device_handle *dev_handle;
unsigned int ep_out;
unsigned int ep_in;
int interface;
};
static int cmsis_dap_usb_interface = -1;
static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
{
int err;
libusb_context *ctx;
libusb_device **device_list;
err = libusb_init(&ctx);
if (err) {
LOG_ERROR("libusb initialization failed: %s", libusb_strerror(err));
return ERROR_FAIL;
}
int num_devices = libusb_get_device_list(ctx, &device_list);
if (num_devices < 0) {
LOG_ERROR("could not enumerate USB devices: %s", libusb_strerror(num_devices));
libusb_exit(ctx);
return ERROR_FAIL;
}
for (int i = 0; i < num_devices; i++) {
libusb_device *dev = device_list[i];
struct libusb_device_descriptor dev_desc;
err = libusb_get_device_descriptor(dev, &dev_desc);
if (err) {
LOG_ERROR("could not get device descriptor for device %d: %s", i, libusb_strerror(err));
continue;
}
/* Match VID/PID */
bool id_match = false;
bool id_filter = vids[0] || pids[0];
for (int id = 0; vids[id] || pids[id]; id++) {
id_match = !vids[id] || dev_desc.idVendor == vids[id];
id_match &= !pids[id] || dev_desc.idProduct == pids[id];
if (id_match)
break;
}
if (id_filter && !id_match)
continue;
/* Don't continue if we asked for a serial number and the device doesn't have one */
if (dev_desc.iSerialNumber == 0 && serial && serial[0])
continue;
libusb_device_handle *dev_handle = NULL;
err = libusb_open(dev, &dev_handle);
if (err) {
/* It's to be expected that most USB devices can't be opened
* so only report an error if it was explicitly selected
*/
if (id_filter) {
LOG_ERROR("could not open device 0x%04x:0x%04x: %s",
dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
} else {
LOG_DEBUG("could not open device 0x%04x:0x%04x: %s",
dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
}
continue;
}
/* Match serial number */
bool serial_match = false;
char dev_serial[256] = {0};
if (dev_desc.iSerialNumber > 0) {
err = libusb_get_string_descriptor_ascii(
dev_handle, dev_desc.iSerialNumber,
(uint8_t *)dev_serial, sizeof(dev_serial));
if (err < 0) {
const char *msg = "could not read serial number for device 0x%04x:0x%04x: %s";
if (serial)
LOG_WARNING(msg, dev_desc.idVendor, dev_desc.idProduct,
libusb_strerror(err));
else
LOG_DEBUG(msg, dev_desc.idVendor, dev_desc.idProduct,
libusb_strerror(err));
} else if (serial && strncmp(dev_serial, serial, sizeof(dev_serial)) == 0) {
serial_match = true;
}
}
if (serial && !serial_match) {
libusb_close(dev_handle);
continue;
}
/* Find the CMSIS-DAP string in product string */
bool cmsis_dap_in_product_str = false;
char product_string[256] = {0};
if (dev_desc.iProduct > 0) {
err = libusb_get_string_descriptor_ascii(
dev_handle, dev_desc.iProduct,
(uint8_t *)product_string, sizeof(product_string));
if (err < 0) {
LOG_WARNING("could not read product string for device 0x%04x:0x%04x: %s",
dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
} else if (strstr(product_string, "CMSIS-DAP")) {
LOG_DEBUG("found product string of 0x%04x:0x%04x '%s'",
dev_desc.idVendor, dev_desc.idProduct, product_string);
cmsis_dap_in_product_str = true;
}
}
bool device_identified_reliably = cmsis_dap_in_product_str
|| serial_match || id_match;
/* Find the CMSIS-DAP interface */
for (int config = 0; config < dev_desc.bNumConfigurations; config++) {
struct libusb_config_descriptor *config_desc;
err = libusb_get_config_descriptor(dev, config, &config_desc);
if (err) {
LOG_ERROR("could not get configuration descriptor %d for device 0x%04x:0x%04x: %s",
config, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
continue;
}
LOG_DEBUG("enumerating interfaces of 0x%04x:0x%04x",
dev_desc.idVendor, dev_desc.idProduct);
int config_num = config_desc->bConfigurationValue;
const struct libusb_interface_descriptor *intf_desc_candidate = NULL;
const struct libusb_interface_descriptor *intf_desc_found = NULL;
for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) {
const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0];
int interface_num = intf_desc->bInterfaceNumber;
/* Skip this interface if another one was requested explicitly */
if (cmsis_dap_usb_interface != -1 && cmsis_dap_usb_interface != interface_num)
continue;
/* CMSIS-DAP v2 spec says:
*
* CMSIS-DAP with default V2 configuration uses WinUSB and is therefore faster.
* Optionally support for streaming SWO trace is provided via an additional USB endpoint.
*
* The WinUSB configuration requires custom class support with the interface setting
* Class Code: 0xFF (Vendor specific)
* Subclass: 0x00
* Protocol code: 0x00
*
* Depending on the configuration it uses the following USB endpoints which should be configured
* in the interface descriptor in this order:
* - Endpoint 1: Bulk Out used for commands received from host PC.
* - Endpoint 2: Bulk In used for responses send to host PC.
* - Endpoint 3: Bulk In (optional) used for streaming SWO trace (if enabled with SWO_STREAM).
*/
/* Search for "CMSIS-DAP" in the interface string */
bool cmsis_dap_in_interface_str = false;
if (intf_desc->iInterface != 0) {
char interface_str[256] = {0};
err = libusb_get_string_descriptor_ascii(
dev_handle, intf_desc->iInterface,
(uint8_t *)interface_str, sizeof(interface_str));
if (err < 0) {
LOG_DEBUG("could not read interface string %d for device 0x%04x:0x%04x: %s",
intf_desc->iInterface,
dev_desc.idVendor, dev_desc.idProduct,
libusb_strerror(err));
} else if (strstr(interface_str, "CMSIS-DAP")) {
cmsis_dap_in_interface_str = true;
LOG_DEBUG("found interface %d string '%s'",
interface_num, interface_str);
}
}
/* Bypass the following check if this interface was explicitly requested. */
if (cmsis_dap_usb_interface == -1) {
if (!cmsis_dap_in_product_str && !cmsis_dap_in_interface_str)
continue;
}
/* check endpoints */
if (intf_desc->bNumEndpoints < 2) {
LOG_DEBUG("skipping interface %d, has only %d endpoints",
interface_num, intf_desc->bNumEndpoints);
continue;
}
if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK ||
(intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) {
LOG_DEBUG("skipping interface %d, endpoint[0] is not bulk out",
interface_num);
continue;
}
if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK ||
(intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) {
LOG_DEBUG("skipping interface %d, endpoint[1] is not bulk in",
interface_num);
continue;
}
/* We can rely on the interface is really CMSIS-DAP if
* - we've seen CMSIS-DAP in the interface string
* - config asked explicitly for an interface number
* - the device has only one interface
* The later two cases should be honored only if we know
* we are on the rigt device */
bool intf_identified_reliably = cmsis_dap_in_interface_str
|| (device_identified_reliably &&
(cmsis_dap_usb_interface != -1
|| config_desc->bNumInterfaces == 1));
if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC ||
intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) {
/* If the interface is reliably identified
* then we need not insist on setting USB class, subclass and protocol
* exactly as the specification requires.
* At least KitProg3 uses class 0 contrary to the specification */
if (intf_identified_reliably) {
LOG_WARNING("Using CMSIS-DAPv2 interface %d with wrong class %" PRId8
" subclass %" PRId8 " or protocol %" PRId8,
interface_num,
intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass,
intf_desc->bInterfaceProtocol);
} else {
LOG_DEBUG("skipping interface %d, class %" PRId8
" subclass %" PRId8 " protocol %" PRId8,
interface_num,
intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass,
intf_desc->bInterfaceProtocol);
continue;
}
}
if (intf_identified_reliably) {
/* That's the one! */
intf_desc_found = intf_desc;
break;
}
if (!intf_desc_candidate && device_identified_reliably) {
/* This interface looks suitable for CMSIS-DAP. Store the pointer to it
* and keep searching for another one with CMSIS-DAP in interface string */
intf_desc_candidate = intf_desc;
}
}
if (!intf_desc_found) {
/* We were not able to identify reliably which interface is CMSIS-DAP.
* Let's use the first suitable if we found one */
intf_desc_found = intf_desc_candidate;
}
if (!intf_desc_found) {
libusb_free_config_descriptor(config_desc);
continue;
}
/* We've chosen an interface, connect to it */
int interface_num = intf_desc_found->bInterfaceNumber;
int packet_size = intf_desc_found->endpoint[0].wMaxPacketSize;
int ep_out = intf_desc_found->endpoint[0].bEndpointAddress;
int ep_in = intf_desc_found->endpoint[1].bEndpointAddress;
libusb_free_config_descriptor(config_desc);
libusb_free_device_list(device_list, true);
LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s",
dev_desc.idVendor, dev_desc.idProduct, dev_serial);
int current_config;
err = libusb_get_configuration(dev_handle, &current_config);
if (err) {
LOG_ERROR("could not find current configuration: %s", libusb_strerror(err));
libusb_close(dev_handle);
libusb_exit(ctx);
return ERROR_FAIL;
}
if (config_num != current_config) {
err = libusb_set_configuration(dev_handle, config_num);
if (err) {
LOG_ERROR("could not set configuration: %s", libusb_strerror(err));
libusb_close(dev_handle);
libusb_exit(ctx);
return ERROR_FAIL;
}
}
err = libusb_claim_interface(dev_handle, interface_num);
if (err)
LOG_WARNING("could not claim interface: %s", libusb_strerror(err));
dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data));
if (dap->bdata == NULL) {
LOG_ERROR("unable to allocate memory");
libusb_release_interface(dev_handle, interface_num);
libusb_close(dev_handle);
libusb_exit(ctx);
return ERROR_FAIL;
}
dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */
dap->bdata->usb_ctx = ctx;
dap->bdata->dev_handle = dev_handle;
dap->bdata->ep_out = ep_out;
dap->bdata->ep_in = ep_in;
dap->bdata->interface = interface_num;
return ERROR_OK;
}
libusb_close(dev_handle);
}
libusb_free_device_list(device_list, true);
libusb_exit(ctx);
return ERROR_FAIL;
}
static void cmsis_dap_usb_close(struct cmsis_dap *dap)
{
libusb_release_interface(dap->bdata->dev_handle, dap->bdata->interface);
libusb_close(dap->bdata->dev_handle);
libusb_exit(dap->bdata->usb_ctx);
free(dap->bdata);
dap->bdata = NULL;
}
static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms)
{
int transferred = 0;
int err;
err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_in,
dap->packet_buffer, dap->packet_size, &transferred, timeout_ms);
if (err) {
if (err == LIBUSB_ERROR_TIMEOUT) {
return ERROR_TIMEOUT_REACHED;
} else {
LOG_ERROR("error reading data: %s", libusb_strerror(err));
return ERROR_FAIL;
}
}
memset(&dap->packet_buffer[transferred], 0, dap->packet_size - transferred);
return transferred;
}
static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
{
int transferred = 0;
int err;
/* skip the first byte that is only used by the HID backend */
err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out,
dap->packet_buffer + 1, txlen - 1, &transferred, timeout_ms);
if (err) {
if (err == LIBUSB_ERROR_TIMEOUT) {
return ERROR_TIMEOUT_REACHED;
} else {
LOG_ERROR("error writing data: %s", libusb_strerror(err));
return ERROR_FAIL;
}
}
return transferred;
}
COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command)
{
if (CMD_ARGC == 1)
cmsis_dap_usb_interface = strtoul(CMD_ARGV[0], NULL, 10);
else
LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface <interface_number>");
return ERROR_OK;
}
const struct command_registration cmsis_dap_usb_subcommand_handlers[] = {
{
.name = "interface",
.handler = &cmsis_dap_handle_usb_interface_command,
.mode = COMMAND_CONFIG,
.help = "set the USB interface number to use (for USB bulk backend only)",
.usage = "<interface_number>",
},
COMMAND_REGISTRATION_DONE
};
const struct cmsis_dap_backend cmsis_dap_usb_backend = {
.name = "usb_bulk",
.open = cmsis_dap_usb_open,
.close = cmsis_dap_usb_close,
.read = cmsis_dap_usb_read,
.write = cmsis_dap_usb_write,
};

View File

@ -0,0 +1,208 @@
/***************************************************************************
* Copyright (C) 2018 by Mickaël Thomas *
* mickael9@gmail.com *
* *
* Copyright (C) 2016 by Maksym Hilliaka *
* oter@frozen-team.com *
* *
* Copyright (C) 2016 by Phillip Pearson *
* pp@myelin.co.nz *
* *
* Copyright (C) 2014 by Paul Fertser *
* fercerpav@gmail.com *
* *
* Copyright (C) 2013 by mike brown *
* mike@theshedworks.org.uk *
* *
* Copyright (C) 2013 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <hidapi.h>
#include <helper/log.h>
#include "cmsis_dap.h"
#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */
struct cmsis_dap_backend_data {
hid_device *dev_handle;
};
static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
{
hid_device *dev = NULL;
int i;
struct hid_device_info *devs, *cur_dev;
unsigned short target_vid, target_pid;
target_vid = 0;
target_pid = 0;
if (hid_init() != 0) {
LOG_ERROR("unable to open HIDAPI");
return ERROR_FAIL;
}
/*
* The CMSIS-DAP specification stipulates:
* "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the
* debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer."
*/
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
while (NULL != cur_dev) {
bool found = false;
if (0 == vids[0]) {
if (NULL == cur_dev->product_string) {
LOG_DEBUG("Cannot read product string of device 0x%x:0x%x",
cur_dev->vendor_id, cur_dev->product_id);
} else if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) {
/* if the user hasn't specified VID:PID *and*
* product string contains "CMSIS-DAP", pick it
*/
found = true;
}
} else {
/* otherwise, exhaustively compare against all VID:PID in list */
for (i = 0; vids[i] || pids[i]; i++) {
if ((vids[i] == cur_dev->vendor_id) && (pids[i] == cur_dev->product_id))
found = true;
}
}
/* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */
if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0)
found = false;
if (found) {
/* check serial number matches if given */
if (serial == NULL)
break;
if (cur_dev->serial_number != NULL) {
size_t len = (strlen(serial) + 1) * sizeof(wchar_t);
wchar_t *wserial = malloc(len);
mbstowcs(wserial, serial, len);
if (wcscmp(wserial, cur_dev->serial_number) == 0) {
free(wserial);
break;
} else {
free(wserial);
wserial = NULL;
}
}
}
cur_dev = cur_dev->next;
}
if (NULL != cur_dev) {
target_vid = cur_dev->vendor_id;
target_pid = cur_dev->product_id;
}
if (target_vid == 0 && target_pid == 0) {
hid_free_enumeration(devs);
return ERROR_FAIL;
}
dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data));
if (dap->bdata == NULL) {
LOG_ERROR("unable to allocate memory");
return ERROR_FAIL;
}
dev = hid_open_path(cur_dev->path);
hid_free_enumeration(devs);
if (dev == NULL) {
LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid);
return ERROR_FAIL;
}
/* allocate default packet buffer, may be changed later.
* currently with HIDAPI we have no way of getting the output report length
* without this info we cannot communicate with the adapter.
* For the moment we have to hard code the packet size */
dap->packet_size = PACKET_SIZE;
/* atmel cmsis-dap uses 512 byte reports */
/* except when it doesn't e.g. with mEDBG on SAMD10 Xplained
* board */
/* TODO: HID report descriptor should be parsed instead of
* hardcoding a match by VID */
if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175)
dap->packet_size = 512 + 1;
dap->bdata->dev_handle = dev;
return ERROR_OK;
}
static void cmsis_dap_hid_close(struct cmsis_dap *dap)
{
hid_close(dap->bdata->dev_handle);
hid_exit();
free(dap->bdata);
dap->bdata = NULL;
}
static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms)
{
int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms);
if (retval == 0) {
return ERROR_TIMEOUT_REACHED;
} else if (retval == -1) {
LOG_ERROR("error reading data: %ls", hid_error(dap->bdata->dev_handle));
return ERROR_FAIL;
}
return retval;
}
static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
{
(void) timeout_ms;
/* Pad the rest of the TX buffer with 0's */
memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen);
/* write data to device */
int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size);
if (retval == -1) {
LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle));
return ERROR_FAIL;
}
return retval;
}
const struct cmsis_dap_backend cmsis_dap_hid_backend = {
.name = "hid",
.open = cmsis_dap_hid_open,
.close = cmsis_dap_hid_close,
.read = cmsis_dap_hid_read,
.write = cmsis_dap_hid_write,
};

View File

@ -170,7 +170,7 @@ static int ft232r_send_recv(void)
return ERROR_OK;
}
void ft232r_increase_buf_size(size_t new_buf_size)
static void ft232r_increase_buf_size(size_t new_buf_size)
{
uint8_t *new_buf_ptr;
if (new_buf_size >= ft232r_buf_size) {

View File

@ -63,7 +63,7 @@
#endif
/* configuration */
uint16_t gw16012_port;
static uint16_t gw16012_port;
/* interface variables
*/

View File

@ -1270,7 +1270,7 @@ static bool calculate_swo_prescaler(unsigned int traceclkin_freq,
uint32_t trace_freq, uint16_t *prescaler)
{
unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq;
if (presc > TPIU_ACPR_MAX_SWOSCALER)
if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1)
return false;
/* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */
@ -1296,7 +1296,7 @@ static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed,
*trace_freq = speed.freq / divider;
presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1;
if (presc > TPIU_ACPR_MAX_SWOSCALER)
if (presc > TPIU_ACPR_MAX_SWOSCALER + 1)
break;
deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq));

View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H
#define OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H
#include <ftdi.h>
#ifndef HAVE_LIBFTDI_TCIOFLUSH
/* Backward compatibility with libftdi pre 1.5 */
static inline int ftdi_tciflush(struct ftdi_context *ftdi)
{
return ftdi_usb_purge_rx_buffer(ftdi);
}
static inline int ftdi_tcoflush(struct ftdi_context *ftdi)
{
return ftdi_usb_purge_tx_buffer(ftdi);
}
static inline int ftdi_tcioflush(struct ftdi_context *ftdi)
{
return ftdi_usb_purge_buffers(ftdi);
}
#endif
#endif /* OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H */

View File

@ -411,7 +411,7 @@ static int nulink_usb_step(void *handle)
return res;
}
static int nulink_usb_read_reg(void *handle, int num, uint32_t *val)
static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
struct nulink_usb_handle_s *h = handle;
@ -434,7 +434,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val)
h->cmdbuf[h->cmdidx] = 0;
h->cmdidx += 1;
/* u32Addr */
h_u32_to_le(h->cmdbuf + h->cmdidx, num);
h_u32_to_le(h->cmdbuf + h->cmdidx, regsel);
h->cmdidx += 4;
/* u32Data */
h_u32_to_le(h->cmdbuf + h->cmdidx, 0);
@ -450,7 +450,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val)
return res;
}
static int nulink_usb_write_reg(void *handle, int num, uint32_t val)
static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
struct nulink_usb_handle_s *h = handle;
@ -473,7 +473,7 @@ static int nulink_usb_write_reg(void *handle, int num, uint32_t val)
h->cmdbuf[h->cmdidx] = 0;
h->cmdidx += 1;
/* u32Addr */
h_u32_to_le(h->cmdbuf + h->cmdidx, num);
h_u32_to_le(h->cmdbuf + h->cmdidx, regsel);
h->cmdidx += 4;
/* u32Data */
h_u32_to_le(h->cmdbuf + h->cmdidx, val);

View File

@ -144,7 +144,7 @@ static int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_lengt
static int opendous_usb_read(struct opendous_jtag *opendous_jtag);
/* helper functions */
int opendous_get_version_info(void);
static int opendous_get_version_info(void);
#ifdef _DEBUG_USB_COMMS_
static void opendous_debug_buffer(uint8_t *buffer, int length);
@ -544,7 +544,7 @@ int opendous_get_status(void)
return ERROR_OK;
}
int opendous_get_version_info(void)
static int opendous_get_version_info(void)
{
return ERROR_OK;
}

View File

@ -82,7 +82,7 @@ typedef enum openjtag_tap_state {
} openjtag_tap_state_t;
/* OPENJTAG access library includes */
#include <ftdi.h>
#include "libftdi_helper.h"
/* OpenJTAG vid/pid */
static uint16_t openjtag_vid = 0x0403;
@ -436,8 +436,8 @@ static int openjtag_init_standard(void)
return ERROR_JTAG_DEVICE_ERROR;
}
if (ftdi_usb_purge_buffers(&ftdic) < 0) {
LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
if (ftdi_tcioflush(&ftdic) < 0) {
LOG_ERROR("ftdi flush: %s", ftdic.error_str);
return ERROR_JTAG_INIT_FAILED;
}

View File

@ -34,7 +34,7 @@
#include "bitq.h"
/* PRESTO access library includes */
#include <ftdi.h>
#include "libftdi_helper.h"
/* -------------------------------------------------------------------------- */
@ -160,8 +160,8 @@ static int presto_open_libftdi(char *req_serial)
return ERROR_JTAG_DEVICE_ERROR;
}
if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) {
LOG_ERROR("unable to purge PRESTO buffers");
if (ftdi_tcioflush(&presto->ftdic) < 0) {
LOG_ERROR("unable to flush PRESTO buffers");
return ERROR_JTAG_DEVICE_ERROR;
}
@ -174,7 +174,7 @@ static int presto_open_libftdi(char *req_serial)
if (presto_read(&presto_data, 1) != ERROR_OK) {
LOG_DEBUG("no response from PRESTO, retrying");
if (ftdi_usb_purge_buffers(&presto->ftdic) < 0)
if (ftdi_tcioflush(&presto->ftdic) < 0)
return ERROR_JTAG_DEVICE_ERROR;
presto_data = 0xD0;

View File

@ -299,6 +299,7 @@ struct stlink_usb_handle_s {
#define STLINK_TRACE_SIZE 4096
#define STLINK_TRACE_MAX_HZ 2000000
#define STLINK_V3_TRACE_MAX_HZ 24000000
#define STLINK_V3_MAX_FREQ_NB 10
@ -323,6 +324,9 @@ struct stlink_usb_handle_s {
/* aliases */
#define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE
#define STLINK_F_HAS_FPU_REG STLINK_F_HAS_GETLASTRWSTATUS2
#define STLINK_REGSEL_IS_FPU(x) ((x) > 0x1F)
struct speed_map {
int speed;
@ -358,7 +362,7 @@ static const struct speed_map stlink_khz_to_speed_map_jtag[] = {
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
static int stlink_swim_status(void *handle);
void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size);
static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size);
static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map);
static int stlink_speed(void *handle, int khz, bool query);
static int stlink_usb_open_ap(void *handle, unsigned short apsel);
@ -2015,13 +2019,22 @@ static int stlink_usb_read_regs(void *handle)
}
/** */
static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) {
res = stlink_usb_write_debug_reg(h, DCB_DCRSR, regsel & 0x7f);
if (res != ERROR_OK)
return res;
/* FIXME: poll DHCSR.S_REGRDY before read DCRDR */
return stlink_usb_v2_read_debug_reg(h, DCB_DCRDR, val);
}
stlink_usb_init_buffer(handle, h->rx_ep, h->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
@ -2029,7 +2042,7 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG;
else
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG;
h->cmdbuf[h->cmdidx++] = num;
h->cmdbuf[h->cmdidx++] = regsel;
if (h->version.jtag_api == STLINK_JTAG_API_V1) {
res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4);
@ -2047,12 +2060,21 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
}
/** */
static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) {
int res = stlink_usb_write_debug_reg(h, DCB_DCRDR, val);
if (res != ERROR_OK)
return res;
return stlink_usb_write_debug_reg(h, DCB_DCRSR, DCRSR_WnR | (regsel & 0x7f));
/* FIXME: poll DHCSR.S_REGRDY after write DCRSR */
}
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
@ -2060,7 +2082,7 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG;
else
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG;
h->cmdbuf[h->cmdidx++] = num;
h->cmdbuf[h->cmdidx++] = regsel;
h_u32_to_le(h->cmdbuf+h->cmdidx, val);
h->cmdidx += 4;
@ -2577,7 +2599,7 @@ static int stlink_speed_jtag(void *handle, int khz, bool query)
return stlink_khz_to_speed_map_jtag[speed_index].speed;
}
void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size)
static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size)
{
unsigned int i;
@ -2725,7 +2747,7 @@ static int stlink_usb_close(void *handle)
* based on the length (0x1a = 26) we could easily decide if we have to fixup the serial
* and then we have just to convert the raw data into printable characters using sprintf
*/
char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
static char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
struct libusb_device_descriptor *dev_desc)
{
int usb_retval;
@ -2982,13 +3004,12 @@ static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
return stlink_usb_open(param, stlink_get_mode(param->transport), fd);
}
int stlink_config_trace(void *handle, bool enabled,
static int stlink_config_trace(void *handle, bool enabled,
enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
unsigned int *trace_freq, unsigned int traceclkin_freq,
uint16_t *prescaler)
{
struct stlink_usb_handle_s *h = handle;
uint16_t presc;
if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) ||
pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
@ -2996,34 +3017,42 @@ int stlink_config_trace(void *handle, bool enabled,
return ERROR_FAIL;
}
if (!enabled) {
stlink_usb_trace_disable(h);
return ERROR_OK;
}
unsigned int max_trace_freq = (h->version.stlink == 3) ?
STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ;
if (*trace_freq > STLINK_TRACE_MAX_HZ) {
/* Only concern ourselves with the frequency if the STlink is processing it. */
if (enabled && *trace_freq > max_trace_freq) {
LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u",
STLINK_TRACE_MAX_HZ);
max_trace_freq);
return ERROR_FAIL;
}
stlink_usb_trace_disable(h);
if (!*trace_freq)
*trace_freq = STLINK_TRACE_MAX_HZ;
*trace_freq = max_trace_freq;
presc = traceclkin_freq / *trace_freq;
unsigned int presc = (traceclkin_freq + *trace_freq / 2) / *trace_freq;
if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) {
LOG_ERROR("SWO frequency is not suitable. Please choose a different "
"frequency.");
return ERROR_FAIL;
}
if (traceclkin_freq % *trace_freq > 0)
presc++;
if (presc > TPIU_ACPR_MAX_SWOSCALER) {
/* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */
unsigned int max_deviation = (traceclkin_freq * 3) / 100;
if (presc * *trace_freq < traceclkin_freq - max_deviation ||
presc * *trace_freq > traceclkin_freq + max_deviation) {
LOG_ERROR("SWO frequency is not suitable. Please choose a different "
"frequency.");
return ERROR_FAIL;
}
*prescaler = presc;
if (!enabled)
return ERROR_OK;
h->trace.source_hz = *trace_freq;
return stlink_usb_trace_enable(h);

View File

@ -31,7 +31,7 @@
#include <target/cortex_m.h>
#include <libusb.h>
#include "libusb_helper.h"
#define ICDI_WRITE_ENDPOINT 0x02
#define ICDI_READ_ENDPOINT 0x83
@ -44,8 +44,7 @@
#define PACKET_END "#"
struct icdi_usb_handle_s {
libusb_context *usb_ctx;
libusb_device_handle *usb_dev;
struct libusb_device_handle *usb_dev;
char *read_buffer;
char *write_buffer;
@ -476,13 +475,13 @@ static int icdi_usb_read_regs(void *handle)
return ERROR_OK;
}
static int icdi_usb_read_reg(void *handle, int num, uint32_t *val)
static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
int result;
struct icdi_usb_handle_s *h = handle;
char cmd[10];
snprintf(cmd, sizeof(cmd), "p%x", num);
snprintf(cmd, sizeof(cmd), "p%x", regsel);
result = icdi_send_cmd(handle, cmd);
if (result != ERROR_OK)
return result;
@ -505,14 +504,14 @@ static int icdi_usb_read_reg(void *handle, int num, uint32_t *val)
return result;
}
static int icdi_usb_write_reg(void *handle, int num, uint32_t val)
static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
int result;
char cmd[20];
uint8_t buf[4];
h_u32_to_le(buf, val);
int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num);
int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", regsel);
hexify(cmd + cmd_len, buf, 4, sizeof(cmd));
result = icdi_send_cmd(handle, cmd);
@ -657,10 +656,7 @@ static int icdi_usb_close(void *handle)
return ERROR_OK;
if (h->usb_dev)
libusb_close(h->usb_dev);
if (h->usb_ctx)
libusb_exit(h->usb_ctx);
jtag_libusb_close(h->usb_dev);
free(h->read_buffer);
free(h->write_buffer);
@ -670,6 +666,7 @@ static int icdi_usb_close(void *handle)
static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
{
/* TODO: Convert remaining libusb_ calls to jtag_libusb_ */
int retval;
struct icdi_usb_handle_s *h;
@ -682,19 +679,14 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
return ERROR_FAIL;
}
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
param->vid[0], param->pid[0]);
for (uint8_t i = 0; param->vid[i] && param->pid[i]; ++i)
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", param->transport,
param->vid[i], param->pid[i], param->serial ? param->serial : "");
/* TODO: convert libusb_ calls to jtag_libusb_ */
if (param->vid[1])
LOG_WARNING("Bad configuration: 'hla_vid_pid' command does not accept more than one VID PID pair on ti-icdi!");
/* TI (Stellaris) ICDI provides its serial number in the USB descriptor;
no need to provide a callback here. */
jtag_libusb_open(param->vid, param->pid, param->serial, &h->usb_dev, NULL);
if (libusb_init(&h->usb_ctx) != 0) {
LOG_ERROR("libusb init failed");
goto error_open;
}
h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid[0], param->pid[0]);
if (!h->usb_dev) {
LOG_ERROR("open failed");
goto error_open;

View File

@ -25,6 +25,7 @@
#include <jtag/commands.h>
#include <target/image.h>
#include <libusb.h>
#include "libusb_helper.h"
#include "OpenULINK/include/msgtypes.h"
/** USB Vendor ID of ULINK device in unconfigured state (no firmware loaded
@ -148,6 +149,9 @@ struct ulink {
struct libusb_device_handle *usb_device_handle;
enum ulink_type type;
unsigned int ep_in; /**< IN endpoint number */
unsigned int ep_out; /**< OUT endpoint number */
int delay_scan_in; /**< Delay value for SCAN_IN commands */
int delay_scan_out; /**< Delay value for SCAN_OUT commands */
int delay_scan_io; /**< Delay value for SCAN_IO commands */
@ -162,34 +166,34 @@ struct ulink {
/**************************** Function Prototypes *****************************/
/* USB helper functions */
int ulink_usb_open(struct ulink **device);
int ulink_usb_close(struct ulink **device);
static int ulink_usb_open(struct ulink **device);
static int ulink_usb_close(struct ulink **device);
/* ULINK MCU (Cypress EZ-USB) specific functions */
int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit);
int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename,
static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit);
static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename,
uint32_t delay);
int ulink_load_firmware(struct ulink *device, const char *filename);
int ulink_write_firmware_section(struct ulink *device,
static int ulink_load_firmware(struct ulink *device, const char *filename);
static int ulink_write_firmware_section(struct ulink *device,
struct image *firmware_image, int section_index);
/* Generic helper functions */
void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals);
static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals);
/* OpenULINK command generation helper functions */
int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
enum ulink_payload_direction direction);
/* OpenULINK command queue helper functions */
int ulink_get_queue_size(struct ulink *device,
static int ulink_get_queue_size(struct ulink *device,
enum ulink_payload_direction direction);
void ulink_clear_queue(struct ulink *device);
int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd);
int ulink_execute_queued_commands(struct ulink *device, int timeout);
static void ulink_clear_queue(struct ulink *device);
static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd);
static int ulink_execute_queued_commands(struct ulink *device, int timeout);
static void ulink_print_queue(struct ulink *device);
int ulink_append_scan_cmd(struct ulink *device,
static int ulink_append_scan_cmd(struct ulink *device,
enum scan_type scan_type,
int scan_size_bits,
uint8_t *tdi,
@ -201,39 +205,39 @@ int ulink_append_scan_cmd(struct ulink *device,
uint8_t tms_sequence_end,
struct jtag_command *origin,
bool postprocess);
int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count,
static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count,
uint8_t sequence);
int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count);
int ulink_append_get_signals_cmd(struct ulink *device);
int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count);
static int ulink_append_get_signals_cmd(struct ulink *device);
static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
uint8_t high);
int ulink_append_sleep_cmd(struct ulink *device, uint32_t us);
int ulink_append_configure_tck_cmd(struct ulink *device,
static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us);
static int ulink_append_configure_tck_cmd(struct ulink *device,
int delay_scan_in,
int delay_scan_out,
int delay_scan_io,
int delay_tck,
int delay_tms);
int ulink_append_led_cmd(struct ulink *device, uint8_t led_state);
int ulink_append_test_cmd(struct ulink *device);
static int __attribute__((unused)) ulink_append_led_cmd(struct ulink *device, uint8_t led_state);
static int ulink_append_test_cmd(struct ulink *device);
/* OpenULINK TCK frequency helper functions */
int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay);
static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay);
/* Interface between OpenULINK and OpenOCD */
static void ulink_set_end_state(tap_state_t endstate);
int ulink_queue_statemove(struct ulink *device);
static int ulink_queue_statemove(struct ulink *device);
int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd);
static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd);
int ulink_post_process_scan(struct ulink_cmd *ulink_cmd);
int ulink_post_process_queue(struct ulink *device);
static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd);
static int ulink_post_process_queue(struct ulink *device);
/* adapter driver functions */
static int ulink_execute_queue(void);
@ -245,12 +249,12 @@ static int ulink_quit(void);
/****************************** Global Variables ******************************/
struct ulink *ulink_handle;
static struct ulink *ulink_handle;
/**************************** USB helper functions ****************************/
/**
* Opens the ULINK device and claims its USB interface.
* Opens the ULINK device
*
* Currently, only the original ULINK is supported
*
@ -258,7 +262,7 @@ struct ulink *ulink_handle;
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_usb_open(struct ulink **device)
static int ulink_usb_open(struct ulink **device)
{
ssize_t num_devices, i;
bool found;
@ -288,9 +292,6 @@ int ulink_usb_open(struct ulink **device)
return ERROR_FAIL;
libusb_free_device_list(usb_devices, 1);
if (libusb_claim_interface(usb_device_handle, 0) != 0)
return ERROR_FAIL;
(*device)->usb_device_handle = usb_device_handle;
(*device)->type = ULINK_1;
@ -304,7 +305,7 @@ int ulink_usb_open(struct ulink **device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_usb_close(struct ulink **device)
static int ulink_usb_close(struct ulink **device)
{
if (libusb_release_interface((*device)->usb_device_handle, 0) != 0)
return ERROR_FAIL;
@ -327,7 +328,7 @@ int ulink_usb_close(struct ulink **device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit)
static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit)
{
int ret;
@ -354,7 +355,7 @@ int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_load_firmware_and_renumerate(struct ulink **device,
static int ulink_load_firmware_and_renumerate(struct ulink **device,
const char *filename, uint32_t delay)
{
int ret;
@ -390,10 +391,10 @@ int ulink_load_firmware_and_renumerate(struct ulink **device,
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_load_firmware(struct ulink *device, const char *filename)
static int ulink_load_firmware(struct ulink *device, const char *filename)
{
struct image ulink_firmware_image;
int ret, i;
int ret;
ret = ulink_cpu_reset(device, CPU_RESET);
if (ret != ERROR_OK) {
@ -402,7 +403,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename)
}
ulink_firmware_image.base_address = 0;
ulink_firmware_image.base_address_set = 0;
ulink_firmware_image.base_address_set = false;
ret = image_open(&ulink_firmware_image, filename, "ihex");
if (ret != ERROR_OK) {
@ -411,7 +412,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename)
}
/* Download all sections in the image to ULINK */
for (i = 0; i < ulink_firmware_image.num_sections; i++) {
for (unsigned int i = 0; i < ulink_firmware_image.num_sections; i++) {
ret = ulink_write_firmware_section(device, &ulink_firmware_image, i);
if (ret != ERROR_OK)
return ret;
@ -439,7 +440,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_write_firmware_section(struct ulink *device,
static int ulink_write_firmware_section(struct ulink *device,
struct image *firmware_image, int section_index)
{
uint16_t addr, size, bytes_remaining, chunk_size;
@ -499,7 +500,7 @@ int ulink_write_firmware_section(struct ulink *device,
* @param input_signals input signal states as returned by CMD_GET_SIGNALS
* @param output_signals output signal states as returned by CMD_GET_SIGNALS
*/
void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals)
static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals)
{
LOG_INFO("ULINK signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i,"
" SRST: %i",
@ -522,7 +523,7 @@ void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
enum ulink_payload_direction direction)
{
uint8_t *payload;
@ -576,7 +577,7 @@ int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
* @return the number of bytes currently stored in the queue for the specified
* direction.
*/
int ulink_get_queue_size(struct ulink *device,
static int ulink_get_queue_size(struct ulink *device,
enum ulink_payload_direction direction)
{
struct ulink_cmd *current = device->queue_start;
@ -605,7 +606,7 @@ int ulink_get_queue_size(struct ulink *device,
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
void ulink_clear_queue(struct ulink *device)
static void ulink_clear_queue(struct ulink *device)
{
struct ulink_cmd *current = device->queue_start;
struct ulink_cmd *next = NULL;
@ -647,7 +648,7 @@ void ulink_clear_queue(struct ulink *device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
{
int newsize_out, newsize_in;
int ret = ERROR_OK;
@ -698,7 +699,7 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_execute_queued_commands(struct ulink *device, int timeout)
static int ulink_execute_queued_commands(struct ulink *device, int timeout)
{
struct ulink_cmd *current;
int ret, i, index_out, index_in, count_out, count_in, transferred;
@ -725,7 +726,7 @@ int ulink_execute_queued_commands(struct ulink *device, int timeout)
}
/* Send packet to ULINK */
ret = libusb_bulk_transfer(device->usb_device_handle, (2 | LIBUSB_ENDPOINT_OUT),
ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_out,
(unsigned char *)buffer, count_out, &transferred, timeout);
if (ret != 0)
return ERROR_FAIL;
@ -734,7 +735,7 @@ int ulink_execute_queued_commands(struct ulink *device, int timeout)
/* Wait for response if commands contain IN payload data */
if (count_in > 0) {
ret = libusb_bulk_transfer(device->usb_device_handle, (2 | LIBUSB_ENDPOINT_IN),
ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_in,
(unsigned char *)buffer, 64, &transferred, timeout);
if (ret != 0)
return ERROR_FAIL;
@ -865,7 +866,7 @@ static void ulink_print_queue(struct ulink *device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type,
static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type,
int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo,
uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end,
uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess)
@ -966,7 +967,7 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type,
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count,
static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count,
uint8_t sequence)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
@ -1003,7 +1004,7 @@ int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count,
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count)
static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
@ -1036,7 +1037,7 @@ int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_get_signals_cmd(struct ulink *device)
static int ulink_append_get_signals_cmd(struct ulink *device)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
@ -1075,7 +1076,7 @@ int ulink_append_get_signals_cmd(struct ulink *device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
uint8_t high)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
@ -1108,7 +1109,7 @@ int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_sleep_cmd(struct ulink *device, uint32_t us)
static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
@ -1144,7 +1145,7 @@ int ulink_append_sleep_cmd(struct ulink *device, uint32_t us)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in,
static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in,
int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
@ -1206,7 +1207,7 @@ int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in,
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_led_cmd(struct ulink *device, uint8_t led_state)
static int ulink_append_led_cmd(struct ulink *device, uint8_t led_state)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
@ -1236,7 +1237,7 @@ int ulink_append_led_cmd(struct ulink *device, uint8_t led_state)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_append_test_cmd(struct ulink *device)
static int ulink_append_test_cmd(struct ulink *device)
{
struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
@ -1292,7 +1293,7 @@ int ulink_append_test_cmd(struct ulink *device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay)
static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay)
{
float t, x, x_ceil;
@ -1423,7 +1424,7 @@ static void ulink_set_end_state(tap_state_t endstate)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_statemove(struct ulink *device)
static int ulink_queue_statemove(struct ulink *device)
{
uint8_t tms_sequence, tms_count;
int ret;
@ -1452,7 +1453,7 @@ int ulink_queue_statemove(struct ulink *device)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd)
{
uint32_t scan_size_bits, scan_size_bytes, bits_last_scan;
uint32_t scans_max_payload, bytecount;
@ -1631,7 +1632,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd)
{
int ret;
@ -1654,7 +1655,7 @@ int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd)
{
int ret;
@ -1685,7 +1686,7 @@ int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd)
{
uint8_t low = 0, high = 0;
@ -1711,7 +1712,7 @@ int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd)
{
int ret, i, num_states, batch_size, state_count;
tap_state_t *path;
@ -1770,7 +1771,7 @@ int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd)
{
/* IMPORTANT! Due to the time offset in command execution introduced by
* command queueing, this needs to be implemented in the ULINK device */
@ -1783,7 +1784,7 @@ int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd)
* @param device pointer to struct ulink identifying ULINK driver instance.
* @param cmd pointer to the command that shall be executed.
*/
int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd)
static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd)
{
int ret;
unsigned num_cycles;
@ -1828,7 +1829,7 @@ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_post_process_scan(struct ulink_cmd *ulink_cmd)
static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd)
{
struct jtag_command *cmd = ulink_cmd->cmd_origin;
int ret;
@ -1859,7 +1860,7 @@ int ulink_post_process_scan(struct ulink_cmd *ulink_cmd)
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
int ulink_post_process_queue(struct ulink *device)
static int ulink_post_process_queue(struct ulink *device)
{
struct ulink_cmd *current;
struct jtag_command *openocd_cmd;
@ -2156,6 +2157,12 @@ static int ulink_init(void)
} else
LOG_INFO("ULINK device is already running OpenULINK firmware");
/* Get OpenULINK USB IN/OUT endpoints and claim the interface */
ret = jtag_libusb_choose_interface(ulink_handle->usb_device_handle,
&ulink_handle->ep_in, &ulink_handle->ep_out, -1, -1, -1, -1);
if (ret != ERROR_OK)
return ret;
/* Initialize OpenULINK command queue */
ulink_clear_queue(ulink_handle);
@ -2171,7 +2178,7 @@ static int ulink_init(void)
* shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */
dummy = calloc(64, sizeof(uint8_t));
ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, (2 | LIBUSB_ENDPOINT_IN),
ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, ulink_handle->ep_in,
dummy, 64, &transferred, 200);
free(dummy);

View File

@ -134,7 +134,7 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
}
ublast2_firmware_image.base_address = 0;
ublast2_firmware_image.base_address_set = 0;
ublast2_firmware_image.base_address_set = false;
int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex");
if (ret != ERROR_OK) {
@ -162,7 +162,7 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
100);
/* Download all sections in the image to ULINK */
for (int i = 0; i < ublast2_firmware_image.num_sections; i++) {
for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) {
ret = ublast2_write_firmware_section(libusb_dev,
&ublast2_firmware_image, i);
if (ret != ERROR_OK) {

View File

@ -275,7 +275,7 @@ static void ublast_queue_byte(uint8_t abyte)
*
* Returns pin value (1 means driven high, 0 mean driven low)
*/
bool ublast_compute_pin(enum gpio_steer steer)
static bool ublast_compute_pin(enum gpio_steer steer)
{
switch (steer) {
case FIXED_0:

View File

@ -28,7 +28,7 @@
#include "usbtoxxx.h"
#include "usbtoxxx_internal.h"
RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed)
static RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed)
{
struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p;
@ -38,7 +38,7 @@ RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed)
return ERROR_OK;
}
RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed)
static RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed)
{
struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p;

View File

@ -29,7 +29,7 @@
#define N_A "n/a"
const char *types_name[96] = {
static const char *types_name[96] = {
"usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm",
"usbtoadc", "usbtodac",
"usbtomicrowire", "usbtoswim", "usbtodusi", N_A, N_A, N_A, "usbtopower", "usbtodelay",
@ -55,8 +55,8 @@ static uint16_t usbtoxxx_buffer_index;
static uint16_t usbtoxxx_current_cmd_index;
static uint8_t *usbtoxxx_buffer;
uint16_t collect_index;
uint8_t collect_cmd;
static uint16_t collect_index;
static uint8_t collect_cmd;
static uint8_t poll_nesting;
struct usbtoxxx_context_t {
@ -86,7 +86,7 @@ static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c)
versaloon_pending_idx = c->versaloon_pending_idx;
}
RESULT usbtoxxx_validate_current_command_type(void)
static RESULT usbtoxxx_validate_current_command_type(void)
{
if (type_pre > 0) {
/* not the first command */
@ -272,7 +272,7 @@ bool usbtoxxx_interface_supported(uint8_t cmd)
return (usbtoxxx_abilities[cmd / 8] & (1 << (cmd % 8))) > 0;
}
RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen)
static RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen)
{
/* check free space, commit if not enough */
if (((usbtoxxx_buffer_index + usbtoxxx_current_cmd_index + cmdlen)

View File

@ -38,12 +38,12 @@ uint16_t versaloon_pending_idx;
libusb_device_handle *versaloon_usb_device_handle;
static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
RESULT versaloon_init(void);
RESULT versaloon_fini(void);
RESULT versaloon_get_target_voltage(uint16_t *voltage);
RESULT versaloon_set_target_voltage(uint16_t voltage);
RESULT versaloon_delay_ms(uint16_t ms);
RESULT versaloon_delay_us(uint16_t us);
static RESULT versaloon_init(void);
static RESULT versaloon_fini(void);
static RESULT versaloon_get_target_voltage(uint16_t *voltage);
static RESULT versaloon_set_target_voltage(uint16_t voltage);
static RESULT versaloon_delay_ms(uint16_t ms);
static RESULT versaloon_delay_us(uint16_t us);
struct versaloon_interface_t versaloon_interface = {
.init = versaloon_init,
@ -233,7 +233,7 @@ RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
}
#define VERSALOON_RETRY_CNT 10
RESULT versaloon_init(void)
static RESULT versaloon_init(void)
{
uint16_t ret = 0;
uint8_t retry;
@ -291,7 +291,7 @@ RESULT versaloon_init(void)
return versaloon_get_target_voltage(&ret);
}
RESULT versaloon_fini(void)
static RESULT versaloon_fini(void)
{
if (versaloon_usb_device_handle != NULL) {
usbtoxxx_fini();
@ -309,7 +309,7 @@ RESULT versaloon_fini(void)
return ERROR_OK;
}
RESULT versaloon_set_target_voltage(uint16_t voltage)
static RESULT versaloon_set_target_voltage(uint16_t voltage)
{
usbtopwr_init(0);
usbtopwr_config(0);
@ -319,7 +319,7 @@ RESULT versaloon_set_target_voltage(uint16_t voltage)
return usbtoxxx_execute_command();
}
RESULT versaloon_get_target_voltage(uint16_t *voltage)
static RESULT versaloon_get_target_voltage(uint16_t *voltage)
{
uint16_t inlen;
@ -345,12 +345,12 @@ RESULT versaloon_get_target_voltage(uint16_t *voltage)
}
}
RESULT versaloon_delay_ms(uint16_t ms)
static RESULT versaloon_delay_ms(uint16_t ms)
{
return usbtodelay_delay(ms | 0x8000);
}
RESULT versaloon_delay_us(uint16_t us)
static RESULT versaloon_delay_us(uint16_t us)
{
return usbtodelay_delay(us & 0x7FFF);
}

View File

@ -186,7 +186,7 @@
#define CMD_STABLECLOCKS 4
/* Array to convert from OpenOCD tap_state_t to XDS JTAG state */
const uint32_t xds_jtag_state[] = {
static const uint32_t xds_jtag_state[] = {
XDS_JTAG_STATE_EXIT2_DR, /* TAP_DREXIT2 = 0x0 */
XDS_JTAG_STATE_EXIT1_DR, /* TAP_DREXIT1 = 0x1 */
XDS_JTAG_STATE_SHIFT_DR, /* TAP_DRSHIFT = 0x2 */

View File

@ -120,7 +120,7 @@ static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi,
return ERROR_OK;
}
int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd)
static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd)
{
int tms = tap_get_state() == TAP_RESET ? 1 : 0;
size_t left = cmd->cmd.stableclocks->num_cycles;

View File

@ -188,7 +188,7 @@ int hl_interface_override_target(const char **targetname)
return ERROR_FAIL;
}
int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
static int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq,
unsigned int traceclkin_freq, uint16_t *prescaler)
{
@ -203,7 +203,7 @@ int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
return ERROR_OK;
}
int hl_interface_poll_trace(uint8_t *buf, size_t *size)
static int hl_interface_poll_trace(uint8_t *buf, size_t *size)
{
if (hl_if.layout->api->poll_trace)
return hl_if.layout->api->poll_trace(hl_if.handle, buf, size);

View File

@ -51,10 +51,25 @@ struct hl_layout_api_s {
int (*step)(void *handle);
/** */
int (*read_regs)(void *handle);
/** */
int (*read_reg)(void *handle, int num, uint32_t *val);
/** */
int (*write_reg)(void *handle, int num, uint32_t val);
/**
* Read one register from the target
*
* @param handle A pointer to the device-specific handle
* @param regsel Register selection index compatible with all the
* values allowed by armv7m DCRSR.REGSEL
* @param val A pointer to retrieve the register value
* @returns ERROR_OK on success, or an error code on failure.
*/
int (*read_reg)(void *handle, unsigned int regsel, uint32_t *val);
/**
* Write one register to the target
* @param handle A pointer to the device-specific handle
* @param regsel Register selection index compatible with all the
* values allowed by armv7m DCRSR.REGSEL
* @param val The value to be written in the register
* @returns ERROR_OK on success, or an error code on failure.
*/
int (*write_reg)(void *handle, unsigned int regsel, uint32_t val);
/** */
int (*read_mem)(void *handle, uint32_t addr, uint32_t size,
uint32_t count, uint8_t *buffer);

View File

@ -134,7 +134,7 @@ extern struct adapter_driver aice_adapter_driver;
#if BUILD_BCM2835GPIO == 1
extern struct adapter_driver bcm2835gpio_adapter_driver;
#endif
#if BUILD_CMSIS_DAP == 1
#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1
extern struct adapter_driver cmsis_dap_adapter_driver;
#endif
#if BUILD_KITPROG == 1
@ -254,7 +254,7 @@ struct adapter_driver *adapter_drivers[] = {
#if BUILD_BCM2835GPIO == 1
&bcm2835gpio_adapter_driver,
#endif
#if BUILD_CMSIS_DAP == 1
#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1
&cmsis_dap_adapter_driver,
#endif
#if BUILD_KITPROG == 1

View File

@ -194,6 +194,11 @@ static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
Jim_SetResultString(interp, "drscan: jtag execute failed", -1);
for (i = 0; i < field_count; i++)
free(fields[i].in_value);
free(fields);
return JIM_ERR;
}

View File

@ -38,9 +38,11 @@
#include <pld/pld.h>
#include <target/arm_cti.h>
#include <target/arm_adi_v5.h>
#include <rtt/rtt.h>
#include <server/server.h>
#include <server/gdb_server.h>
#include <server/rtt_server.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
@ -230,10 +232,7 @@ static int openocd_register_commands(struct command_context *cmd_ctx)
struct command_context *global_cmd_ctx;
/* NB! this fn can be invoked outside this file for non PC hosted builds
* NB! do not change to 'static'!!!!
*/
struct command_context *setup_command_handler(Jim_Interp *interp)
static struct command_context *setup_command_handler(Jim_Interp *interp)
{
log_init();
LOG_DEBUG("log_init: complete");
@ -247,6 +246,7 @@ struct command_context *setup_command_handler(Jim_Interp *interp)
&server_register_commands,
&gdb_register_commands,
&log_register_commands,
&rtt_server_register_commands,
&transport_register_commands,
&interface_register_commands,
&target_register_commands,
@ -338,6 +338,9 @@ int openocd_main(int argc, char *argv[])
if (ioutil_init(cmd_ctx) != ERROR_OK)
return EXIT_FAILURE;
if (rtt_init() != ERROR_OK)
return EXIT_FAILURE;
LOG_OUTPUT("For bug reports, read\n\t"
"http://openocd.org/doc/doxygen/bugs.html"
"\n");
@ -367,6 +370,7 @@ int openocd_main(int argc, char *argv[])
/* Shutdown commandline interface */
command_exit(cmd_ctx);
rtt_exit();
free_config();
if (ERROR_FAIL == ret)

View File

@ -110,7 +110,7 @@ static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_i
{ 16, 0x04, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
{
ARM926EJS_REGISTERS_SIZE_SOLICITED, /* stack_registers_size */
-1, /* stack_growth_direction */

View File

@ -37,11 +37,11 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
static int hwthread_smp_init(struct target *target);
int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
bool hwthread_needs_fake_step(struct target *target, int64_t thread_id);
int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id);
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, uint8_t *buffer);
int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, const uint8_t *buffer);
#define HW_THREAD_NAME_STR_SIZE (32)
@ -247,23 +247,35 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
if (!target_was_examined(curr))
return ERROR_FAIL;
int reg_list_size;
struct reg **reg_list;
int retval = target_get_gdb_reg_list(curr, &reg_list, rtos_reg_list_size,
int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
REG_CLASS_GENERAL);
if (retval != ERROR_OK)
return retval;
int j = 0;
for (int i = 0; i < reg_list_size; i++) {
if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
j++;
}
*rtos_reg_list_size = j;
*rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
if (*rtos_reg_list == NULL) {
free(reg_list);
return ERROR_FAIL;
}
for (int i = 0; i < *rtos_reg_list_size; i++) {
(*rtos_reg_list)[i].number = (*reg_list)[i].number;
(*rtos_reg_list)[i].size = (*reg_list)[i].size;
memcpy((*rtos_reg_list)[i].value, (*reg_list)[i].value,
j = 0;
for (int i = 0; i < reg_list_size; i++) {
if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
(*rtos_reg_list)[j].number = (*reg_list)[i].number;
(*rtos_reg_list)[j].size = (*reg_list)[i].size;
memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value,
((*reg_list)[i].size + 7) / 8);
j++;
}
free(reg_list);
@ -308,7 +320,7 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
return ERROR_OK;
}
int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
{
if (rtos == NULL)
return ERROR_FAIL;
@ -395,12 +407,12 @@ static int hwthread_create(struct target *target)
return 0;
}
bool hwthread_needs_fake_step(struct target *target, int64_t thread_id)
static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id)
{
return false;
}
int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, uint8_t *buffer)
{
if (rtos == NULL)
@ -415,7 +427,7 @@ int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
return target_read_buffer(curr, address, size, buffer);
}
int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, const uint8_t *buffer)
{
if (rtos == NULL)

View File

@ -92,7 +92,7 @@ struct cpu_context {
uint32_t PC;
uint32_t preempt_count;
};
struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
uint32_t *info_addr);
static int insert_into_threadlist(struct target *target, struct threads *t);
@ -144,7 +144,7 @@ static int linux_read_memory(struct target *target,
return ERROR_OK;
}
int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
{
if ((addr & 0xfffffffc) != addr)
@ -155,7 +155,7 @@ int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
}
uint32_t get_buffer(struct target *target, const uint8_t *buffer)
static uint32_t get_buffer(struct target *target, const uint8_t *buffer)
{
uint32_t value = 0;
const uint8_t *value_ptr = buffer;
@ -293,7 +293,7 @@ int fill_task_pid(struct target *target, struct threads *t)
}
#endif
int fill_task(struct target *target, struct threads *t)
static int fill_task(struct target *target, struct threads *t)
{
int retval;
uint32_t pid_addr = t->base_addr + PID;
@ -349,7 +349,7 @@ int fill_task(struct target *target, struct threads *t)
return retval;
}
int get_name(struct target *target, struct threads *t)
static int get_name(struct target *target, struct threads *t)
{
int retval;
uint32_t full_name[4];
@ -395,7 +395,7 @@ int get_name(struct target *target, struct threads *t)
}
int get_current(struct target *target, int create)
static int get_current(struct target *target, int create)
{
struct target_list *head;
head = target->head;
@ -483,7 +483,7 @@ int get_current(struct target *target, int create)
return ERROR_OK;
}
struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
uint32_t *thread_info_addr_old)
{
struct cpu_context *context = calloc(1, sizeof(struct cpu_context));
@ -579,7 +579,7 @@ retry:
return context;
}
uint32_t next_task(struct target *target, struct threads *t)
static uint32_t next_task(struct target *target, struct threads *t)
{
uint8_t *buffer = calloc(1, 4);
uint32_t next_addr = t->base_addr + NEXT;
@ -598,7 +598,7 @@ uint32_t next_task(struct target *target, struct threads *t)
return 0;
}
struct current_thread *add_current_thread(struct current_thread *currents,
static struct current_thread *add_current_thread(struct current_thread *currents,
struct current_thread *ct)
{
ct->next = NULL;
@ -617,7 +617,7 @@ struct current_thread *add_current_thread(struct current_thread *currents,
}
}
struct threads *liste_del_task(struct threads *task_list, struct threads **t,
static struct threads *liste_del_task(struct threads *task_list, struct threads **t,
struct threads *prev)
{
LOG_INFO("del task %" PRId64, (*t)->threadid);
@ -634,7 +634,7 @@ struct threads *liste_del_task(struct threads *task_list, struct threads **t,
return task_list;
}
struct threads *liste_add_task(struct threads *task_list, struct threads *t,
static struct threads *liste_add_task(struct threads *task_list, struct threads *t,
struct threads **last)
{
t->next = NULL;
@ -683,7 +683,7 @@ static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr)
return 0;
}
int linux_get_tasks(struct target *target, int context)
static int linux_get_tasks(struct target *target, int context)
{
int loop = 0;
int retval = 0;
@ -1033,7 +1033,7 @@ static int linux_task_update(struct target *target, int context)
return ERROR_OK;
}
int linux_gdb_thread_packet(struct target *target,
static int linux_gdb_thread_packet(struct target *target,
struct connection *connection, char const *packet,
int packet_size)
{
@ -1070,7 +1070,7 @@ int linux_gdb_thread_packet(struct target *target,
return ERROR_OK;
}
int linux_gdb_thread_update(struct target *target,
static int linux_gdb_thread_update(struct target *target,
struct connection *connection, char const *packet,
int packet_size)
{
@ -1117,7 +1117,7 @@ int linux_gdb_thread_update(struct target *target,
return ERROR_OK;
}
int linux_thread_extra_info(struct target *target,
static int linux_thread_extra_info(struct target *target,
struct connection *connection, char const *packet,
int packet_size)
{
@ -1163,7 +1163,7 @@ int linux_thread_extra_info(struct target *target,
return ERROR_OK;
}
int linux_gdb_T_packet(struct connection *connection,
static int linux_gdb_T_packet(struct connection *connection,
struct target *target, char const *packet, int packet_size)
{
int64_t threadid;
@ -1223,7 +1223,7 @@ int linux_gdb_T_packet(struct connection *connection,
return retval;
}
int linux_gdb_h_packet(struct connection *connection,
static int linux_gdb_h_packet(struct connection *connection,
struct target *target, char const *packet, int packet_size)
{
struct linux_os *linux_os = (struct linux_os *)

View File

@ -72,7 +72,7 @@ struct tcb {
uint8_t dat[512];
};
struct {
static struct {
uint32_t addr;
uint32_t prio;
} g_tasklist[TASK_QUEUE_NUM];

View File

@ -59,6 +59,8 @@ static struct rtos_type *rtos_types[] = {
NULL
};
static int rtos_try_next(struct target *target);
int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
int rtos_smp_init(struct target *target)
@ -632,7 +634,7 @@ int rtos_generic_stack_read(struct target *target,
return ERROR_OK;
}
int rtos_try_next(struct target *target)
static int rtos_try_next(struct target *target)
{
struct rtos *os = target->rtos;
struct rtos_type **type = rtos_types;

View File

@ -134,7 +134,6 @@ int rtos_generic_stack_read(struct target *target,
int64_t stack_ptr,
struct rtos_reg **reg_list,
int *num_regs);
int rtos_try_next(struct target *target);
int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size);
int rtos_get_gdb_reg(struct connection *connection, int reg_num);
int rtos_get_gdb_reg_list(struct connection *connection);

2
src/rtt/Makefile.am Normal file
View File

@ -0,0 +1,2 @@
noinst_LTLIBRARIES += %D%/librtt.la
%C%_librtt_la_SOURCES = %D%/rtt.c %D%/rtt.h %D%/tcl.c

332
src/rtt/rtt.c Normal file
View File

@ -0,0 +1,332 @@
/*
* Copyright (C) 2016-2020 by Marc Schink <dev@zapb.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/>.
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <helper/log.h>
#include <helper/list.h>
#include <target/target.h>
#include <target/rtt.h>
#include "rtt.h"
static struct {
struct rtt_source source;
/** Control block. */
struct rtt_control ctrl;
struct target *target;
/** Start address to search for the control block. */
target_addr_t addr;
/** Size of the control block search area. */
size_t size;
/** Control block identifier. */
char id[RTT_CB_MAX_ID_LENGTH];
/** Whether RTT is configured. */
bool configured;
/** Whether RTT is started. */
bool started;
/** Whether configuration changed. */
bool changed;
/** Whether the control block was found. */
bool found_cb;
struct rtt_sink_list **sink_list;
size_t sink_list_length;
unsigned int polling_interval;
} rtt;
int rtt_init(void)
{
rtt.sink_list_length = 1;
rtt.sink_list = calloc(rtt.sink_list_length,
sizeof(struct rtt_sink_list *));
if (!rtt.sink_list)
return ERROR_FAIL;
rtt.sink_list[0] = NULL;
rtt.started = false;
rtt.polling_interval = 100;
return ERROR_OK;
}
int rtt_exit(void)
{
free(rtt.sink_list);
return ERROR_OK;
}
static int read_channel_callback(void *user_data)
{
int ret;
ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list,
rtt.sink_list_length, NULL);
if (ret != ERROR_OK) {
target_unregister_timer_callback(&read_channel_callback, NULL);
rtt.source.stop(rtt.target, NULL);
return ret;
}
return ERROR_OK;
}
int rtt_setup(target_addr_t address, size_t size, const char *id)
{
size_t id_length = strlen(id);
if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) {
LOG_ERROR("rtt: Invalid control block ID");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
rtt.addr = address;
rtt.size = size;
strncpy(rtt.id, id, id_length + 1);
rtt.changed = true;
rtt.configured = true;
return ERROR_OK;
}
int rtt_register_source(const struct rtt_source source,
struct target *target)
{
if (!source.find_cb || !source.read_cb || !source.read_channel_info)
return ERROR_FAIL;
if (!source.start || !source.stop)
return ERROR_FAIL;
if (!source.read || !source.write)
return ERROR_FAIL;
rtt.source = source;
rtt.target = target;
return ERROR_OK;
}
int rtt_start(void)
{
int ret;
target_addr_t addr = rtt.addr;
if (rtt.started)
return ERROR_OK;
if (!rtt.found_cb || rtt.changed) {
rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id,
&rtt.found_cb, NULL);
rtt.changed = false;
if (rtt.found_cb) {
LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR,
addr);
rtt.ctrl.address = addr;
} else {
LOG_INFO("rtt: No control block found");
return ERROR_OK;
}
}
ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL);
if (ret != ERROR_OK)
return ret;
ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL);
if (ret != ERROR_OK)
return ret;
target_register_timer_callback(&read_channel_callback,
rtt.polling_interval, 1, NULL);
rtt.started = true;
return ERROR_OK;
}
int rtt_stop(void)
{
int ret;
if (!rtt.configured) {
LOG_ERROR("rtt: Not configured");
return ERROR_FAIL;
}
target_unregister_timer_callback(&read_channel_callback, NULL);
rtt.started = false;
ret = rtt.source.stop(rtt.target, NULL);
if (ret != ERROR_OK)
return ret;
return ERROR_OK;
}
static int adjust_sink_list(size_t length)
{
struct rtt_sink_list **tmp;
if (length <= rtt.sink_list_length)
return ERROR_OK;
tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length);
if (!tmp)
return ERROR_FAIL;
for (size_t i = rtt.sink_list_length; i < length; i++)
tmp[i] = NULL;
rtt.sink_list = tmp;
rtt.sink_list_length = length;
return ERROR_OK;
}
int rtt_register_sink(unsigned int channel_index, rtt_sink_read read,
void *user_data)
{
struct rtt_sink_list *tmp;
if (channel_index >= rtt.sink_list_length) {
if (adjust_sink_list(channel_index + 1) != ERROR_OK)
return ERROR_FAIL;
}
LOG_DEBUG("rtt: Registering sink for channel %u", channel_index);
tmp = malloc(sizeof(struct rtt_sink_list));
if (!tmp)
return ERROR_FAIL;
tmp->read = read;
tmp->user_data = user_data;
tmp->next = rtt.sink_list[channel_index];
rtt.sink_list[channel_index] = tmp;
return ERROR_OK;
}
int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read,
void *user_data)
{
struct rtt_sink_list *prev_sink;
LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index);
if (channel_index >= rtt.sink_list_length)
return ERROR_FAIL;
prev_sink = rtt.sink_list[channel_index];
for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink;
prev_sink = sink, sink = sink->next) {
if (sink->read == read && sink->user_data == user_data) {
if (sink == rtt.sink_list[channel_index])
rtt.sink_list[channel_index] = sink->next;
else
prev_sink->next = sink->next;
free(sink);
return ERROR_OK;
}
}
return ERROR_OK;
}
int rtt_get_polling_interval(unsigned int *interval)
{
if (!interval)
return ERROR_FAIL;
*interval = rtt.polling_interval;
return ERROR_OK;
}
int rtt_set_polling_interval(unsigned int interval)
{
if (!interval)
return ERROR_FAIL;
if (rtt.polling_interval != interval) {
target_unregister_timer_callback(&read_channel_callback, NULL);
target_register_timer_callback(&read_channel_callback, interval, 1,
NULL);
}
rtt.polling_interval = interval;
return ERROR_OK;
}
int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer,
size_t *length)
{
if (channel_index >= rtt.ctrl.num_up_channels) {
LOG_WARNING("rtt: Down-channel %u is not available", channel_index);
return ERROR_OK;
}
return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer,
length, NULL);
}
bool rtt_started(void)
{
return rtt.started;
}
bool rtt_configured(void)
{
return rtt.configured;
}
bool rtt_found_cb(void)
{
return rtt.found_cb;
}
const struct rtt_control *rtt_get_control(void)
{
return &rtt.ctrl;
}
int rtt_read_channel_info(unsigned int channel_index,
enum rtt_channel_type type, struct rtt_channel_info *info)
{
return rtt.source.read_channel_info(rtt.target, &rtt.ctrl,
channel_index, type, info, NULL);
}

287
src/rtt/rtt.h Normal file
View File

@ -0,0 +1,287 @@
/*
* Copyright (C) 2016-2020 by Marc Schink <dev@zapb.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_RTT_RTT_H
#define OPENOCD_RTT_RTT_H
#include <stdint.h>
#include <stdbool.h>
#include <helper/command.h>
#include <target/target.h>
/**
* Control block ID length in bytes, including the trailing null-terminator.
*/
#define RTT_CB_MAX_ID_LENGTH 16
/* Control block size in bytes. */
#define RTT_CB_SIZE (RTT_CB_MAX_ID_LENGTH + 2 * sizeof(uint32_t))
/* Channel structure size in bytes. */
#define RTT_CHANNEL_SIZE 24
/* Minimal channel buffer size in bytes. */
#define RTT_CHANNEL_BUFFER_MIN_SIZE 2
/** RTT control block. */
struct rtt_control {
/** Control block address on the target. */
target_addr_t address;
/** Control block identifier, including trailing null-terminator. */
char id[RTT_CB_MAX_ID_LENGTH];
/** Maximum number of up-channels. */
uint32_t num_up_channels;
/** Maximum number of down-channels. */
uint32_t num_down_channels;
};
/** RTT channel. */
struct rtt_channel {
/** Channel structure address on the target. */
target_addr_t address;
/** Channel name address on the target. */
uint32_t name_addr;
/** Buffer address on the target. */
uint32_t buffer_addr;
/** Channel buffer size in bytes. */
uint32_t size;
/** Write position within the buffer in bytes. */
uint32_t write_pos;
/** Read position within the buffer in bytes. */
uint32_t read_pos;
/**
* Buffer flags.
*
* @note: Not used at the moment.
*/
uint32_t flags;
};
/** RTT channel information. */
struct rtt_channel_info {
/** Channel name. */
char *name;
/** Length of the name in bytes, including the trailing null-terminator. */
size_t name_length;
/** Buffer size in bytes. */
uint32_t size;
/**
* Buffer flags.
*
* @note: Not used at the moment.
*/
uint32_t flags;
};
typedef int (*rtt_sink_read)(unsigned int channel, const uint8_t *buffer,
size_t length, void *user_data);
struct rtt_sink_list {
rtt_sink_read read;
void *user_data;
struct rtt_sink_list *next;
};
/** Channel type. */
enum rtt_channel_type {
/** Up channel (target to host). */
RTT_CHANNEL_TYPE_UP,
/** Down channel (host to target). */
RTT_CHANNEL_TYPE_DOWN
};
typedef int (*rtt_source_find_ctrl_block)(struct target *target,
target_addr_t *address, size_t size, const char *id, bool *found,
void *user_data);
typedef int (*rtt_source_read_ctrl_block)(struct target *target,
target_addr_t address, struct rtt_control *ctrl_block,
void *user_data);
typedef int (*rtt_source_read_channel_info)(struct target *target,
const struct rtt_control *ctrl, unsigned int channel,
enum rtt_channel_type type, struct rtt_channel_info *info,
void *user_data);
typedef int (*rtt_source_start)(struct target *target,
const struct rtt_control *ctrl, void *user_data);
typedef int (*rtt_source_stop)(struct target *target, void *user_data);
typedef int (*rtt_source_read)(struct target *target,
const struct rtt_control *ctrl, struct rtt_sink_list **sinks,
size_t num_channels, void *user_data);
typedef int (*rtt_source_write)(struct target *target,
struct rtt_control *ctrl, unsigned int channel,
const uint8_t *buffer, size_t *length, void *user_data);
/** RTT source. */
struct rtt_source {
rtt_source_find_ctrl_block find_cb;
rtt_source_read_ctrl_block read_cb;
rtt_source_read_channel_info read_channel_info;
rtt_source_start start;
rtt_source_stop stop;
rtt_source_read read;
rtt_source_write write;
};
/**
* Initialize Real-Time Transfer (RTT).
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_init(void);
/**
* Shutdown Real-Time Transfer (RTT).
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_exit(void);
/**
* Register an RTT source for a target.
*
* @param[in] source RTT source.
* @param[in,out] target Target.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_register_source(const struct rtt_source source,
struct target *target);
/**
* Setup RTT.
*
* @param[in] address Start address to search for the control block.
* @param[in] size Size of the control block search area.
* @param[in] id Identifier of the control block. Must be null-terminated.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_setup(target_addr_t address, size_t size, const char *id);
/**
* Start Real-Time Transfer (RTT).
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_start(void);
/**
* Stop Real-Time Transfer (RTT).
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_stop(void);
/**
* Get the polling interval.
*
* @param[out] interval Polling interval in milliseconds.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_get_polling_interval(unsigned int *interval);
/**
* Set the polling interval.
*
* @param[in] interval Polling interval in milliseconds.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_set_polling_interval(unsigned int interval);
/**
* Get whether RTT is started.
*
* @returns Whether RTT is started.
*/
bool rtt_started(void);
/**
* Get whether RTT is configured.
*
* @returns Whether RTT is configured.
*/
bool rtt_configured(void);
/**
* Get whether RTT control block was found.
*
* @returns Whether RTT was found.
*/
bool rtt_found_cb(void);
/**
* Get the RTT control block.
*
* @returns The RTT control block.
*/
const struct rtt_control *rtt_get_control(void);
/**
* Read channel information.
*
* @param[in] channel_index Channel index.
* @param[in] channel_type Channel type.
* @param[out] info Channel information.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_read_channel_info(unsigned int channel_index,
enum rtt_channel_type type, struct rtt_channel_info *info);
/**
* Register an RTT sink.
*
* @param[in] channel_index Channel index.
* @param[in] read Read callback function.
* @param[in,out] user_data User data to be passed to the callback function.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_register_sink(unsigned int channel_index, rtt_sink_read read,
void *user_data);
/**
* Unregister an RTT sink.
*
* @param[in] channel_index Channel index.
* @param[in] read Read callback function.
* @param[in,out] user_data User data to be passed to the callback function.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read,
void *user_data);
/**
* Write to an RTT channel.
*
* @param[in] channel_index Channel index.
* @param[in] buffer Buffer with data that should be written to the channel.
* @param[in,out] length Number of bytes to write. On success, the argument gets
* updated with the actual number of written bytes.
*
* @returns ERROR_OK on success, an error code on failure.
*/
int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer,
size_t *length);
extern const struct command_registration rtt_target_command_handlers[];
#endif /* OPENOCD_RTT_RTT_H */

311
src/rtt/tcl.c Normal file
View File

@ -0,0 +1,311 @@
/*
* Copyright (C) 2019-2020 by Marc Schink <dev@zapb.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/>.
*/
#include <helper/log.h>
#include <target/rtt.h>
#include "rtt.h"
#define CHANNEL_NAME_SIZE 128
COMMAND_HANDLER(handle_rtt_setup_command)
{
struct rtt_source source;
if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;
source.find_cb = &target_rtt_find_control_block;
source.read_cb = &target_rtt_read_control_block;
source.start = &target_rtt_start;
source.stop = &target_rtt_stop;
source.read = &target_rtt_read_callback;
source.write = &target_rtt_write_callback;
source.read_channel_info = &target_rtt_read_channel_info;
target_addr_t address;
uint32_t size;
COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], address);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
rtt_register_source(source, get_current_target(CMD_CTX));
if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
COMMAND_HANDLER(handle_rtt_start_command)
{
if (CMD_ARGC > 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!rtt_configured()) {
command_print(CMD, "RTT is not configured");
return ERROR_FAIL;
}
return rtt_start();
}
COMMAND_HANDLER(handle_rtt_stop_command)
{
if (CMD_ARGC > 0)
return ERROR_COMMAND_SYNTAX_ERROR;
return rtt_stop();
}
COMMAND_HANDLER(handle_rtt_polling_interval_command)
{
if (CMD_ARGC == 0) {
int ret;
unsigned int interval;
ret = rtt_get_polling_interval(&interval);
if (ret != ERROR_OK) {
command_print(CMD, "Failed to get polling interval");
return ret;
}
command_print(CMD, "%u ms", interval);
} else if (CMD_ARGC == 1) {
int ret;
unsigned int interval;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], interval);
ret = rtt_set_polling_interval(interval);
if (ret != ERROR_OK) {
command_print(CMD, "Failed to set polling interval");
return ret;
}
} else {
return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
}
COMMAND_HANDLER(handle_rtt_channels_command)
{
int ret;
char channel_name[CHANNEL_NAME_SIZE];
const struct rtt_control *ctrl;
struct rtt_channel_info info;
if (!rtt_found_cb()) {
command_print(CMD, "rtt: Control block not available");
return ERROR_FAIL;
}
ctrl = rtt_get_control();
command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels,
ctrl->num_down_channels);
command_print(CMD, "Up-channels:");
info.name = channel_name;
info.name_length = sizeof(channel_name);
for (unsigned int i = 0; i < ctrl->num_up_channels; i++) {
ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info);
if (ret != ERROR_OK)
return ret;
if (!info.size)
continue;
command_print(CMD, "%u: %s %u %u", i, info.name, info.size,
info.flags);
}
command_print(CMD, "Down-channels:");
for (unsigned int i = 0; i < ctrl->num_down_channels; i++) {
ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info);
if (ret != ERROR_OK)
return ret;
if (!info.size)
continue;
command_print(CMD, "%u: %s %u %u", i, info.name, info.size,
info.flags);
}
return ERROR_OK;
}
static int jim_channel_list(Jim_Interp *interp, int argc,
Jim_Obj * const *argv)
{
Jim_Obj *list;
Jim_Obj *channel_list;
char channel_name[CHANNEL_NAME_SIZE];
const struct rtt_control *ctrl;
struct rtt_channel_info info;
if (!rtt_found_cb()) {
Jim_SetResultFormatted(interp, "rtt: Control block not available");
return ERROR_FAIL;
}
ctrl = rtt_get_control();
info.name = channel_name;
info.name_length = sizeof(channel_name);
list = Jim_NewListObj(interp, NULL, 0);
channel_list = Jim_NewListObj(interp, NULL, 0);
for (unsigned int i = 0; i < ctrl->num_up_channels; i++) {
int ret;
Jim_Obj *tmp;
ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info);
if (ret != ERROR_OK)
return ret;
if (!info.size)
continue;
tmp = Jim_NewListObj(interp, NULL, 0);
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"name", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
info.name, -1));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"size", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.size));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"flags", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.flags));
Jim_ListAppendElement(interp, channel_list, tmp);
}
Jim_ListAppendElement(interp, list, channel_list);
channel_list = Jim_NewListObj(interp, NULL, 0);
for (unsigned int i = 0; i < ctrl->num_down_channels; i++) {
int ret;
Jim_Obj *tmp;
ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info);
if (ret != ERROR_OK)
return ret;
if (!info.size)
continue;
tmp = Jim_NewListObj(interp, NULL, 0);
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"name", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
info.name, -1));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"size", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.size));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"flags", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.flags));
Jim_ListAppendElement(interp, channel_list, tmp);
}
Jim_ListAppendElement(interp, list, channel_list);
Jim_SetResult(interp, list);
return JIM_OK;
}
static const struct command_registration rtt_subcommand_handlers[] = {
{
.name = "setup",
.handler = handle_rtt_setup_command,
.mode = COMMAND_ANY,
.help = "setup RTT",
.usage = "<address> <size> <ID>"
},
{
.name = "start",
.handler = handle_rtt_start_command,
.mode = COMMAND_EXEC,
.help = "start RTT",
.usage = ""
},
{
.name = "stop",
.handler = handle_rtt_stop_command,
.mode = COMMAND_EXEC,
.help = "stop RTT",
.usage = ""
},
{
.name = "polling_interval",
.handler = handle_rtt_polling_interval_command,
.mode = COMMAND_EXEC,
.help = "show or set polling interval in ms",
.usage = "[interval]"
},
{
.name = "channels",
.handler = handle_rtt_channels_command,
.mode = COMMAND_EXEC,
.help = "list available channels",
.usage = ""
},
{
.name = "channellist",
.jim_handler = jim_channel_list,
.mode = COMMAND_EXEC,
.help = "list available channels",
.usage = ""
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration rtt_target_command_handlers[] = {
{
.name = "rtt",
.mode = COMMAND_EXEC,
.help = "RTT target commands",
.usage = "",
.chain = rtt_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};

View File

@ -8,7 +8,9 @@ noinst_LTLIBRARIES += %D%/libserver.la
%D%/gdb_server.h \
%D%/server_stubs.c \
%D%/tcl_server.c \
%D%/tcl_server.h
%D%/tcl_server.h \
%D%/rtt_server.c \
%D%/rtt_server.h
%C%_libserver_la_CFLAGS = $(AM_CFLAGS)
if IS_MINGW

View File

@ -967,15 +967,6 @@ static int gdb_new_connection(struct connection *connection)
breakpoint_clear_target(target);
watchpoint_clear_target(target);
if (target->rtos) {
/* clean previous rtos session if supported*/
if (target->rtos->type->clean)
target->rtos->type->clean(target);
/* update threads */
rtos_update_threads(target);
}
/* remove the initial ACK from the incoming buffer */
retval = gdb_get_char(connection, &initial_ack);
if (retval != ERROR_OK)
@ -988,6 +979,15 @@ static int gdb_new_connection(struct connection *connection)
gdb_putback_char(connection, initial_ack);
target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH);
if (target->rtos) {
/* clean previous rtos session if supported*/
if (target->rtos->type->clean)
target->rtos->type->clean(target);
/* update threads */
rtos_update_threads(target);
}
if (gdb_use_memory_map) {
/* Connect must fail if the memory map can't be set up correctly.
*
@ -1187,7 +1187,7 @@ static int gdb_get_registers_packet(struct connection *connection,
return gdb_error(connection, retval);
for (i = 0; i < reg_list_size; i++) {
if (reg_list[i] == NULL || reg_list[i]->exist == false)
if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
}
@ -1201,7 +1201,7 @@ static int gdb_get_registers_packet(struct connection *connection,
reg_packet_p = reg_packet;
for (i = 0; i < reg_list_size; i++) {
if (reg_list[i] == NULL || reg_list[i]->exist == false)
if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
if (!reg_list[i]->valid) {
retval = reg_list[i]->type->get(reg_list[i]);
@ -1330,7 +1330,7 @@ static int gdb_get_register_packet(struct connection *connection,
}
}
reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */
reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */
gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
@ -2187,7 +2187,7 @@ static int get_reg_features_list(struct target *target, char const **feature_lis
*feature_list = calloc(1, sizeof(char *));
for (int i = 0; i < reg_list_size; i++) {
if (reg_list[i]->exist == false)
if (reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
if (reg_list[i]->feature != NULL
@ -2353,7 +2353,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
int i;
for (i = 0; i < reg_list_size; i++) {
if (reg_list[i]->exist == false)
if (reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
if (strcmp(reg_list[i]->feature->name, features[current_feature]))
@ -2600,7 +2600,7 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
transfer_type = 'l';
*chunk = malloc(length + 2 + 3);
/* Allocating extra 3 bytes prevents false positive valgrind report
/* Allocating extra 3 bytes prevents false positive valgrind report
* of strlen(chunk) word access:
* Invalid read of size 4
* Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */
@ -3614,8 +3614,8 @@ static int gdb_target_start(struct target *target, const char *port)
target->gdb_service = gdb_service;
ret = add_service("gdb",
port, 1, &gdb_new_connection, &gdb_input,
&gdb_connection_closed, gdb_service);
port, target->gdb_max_connections, &gdb_new_connection, &gdb_input,
&gdb_connection_closed, gdb_service, NULL);
/* initialize all targets gdb service with the same pointer */
{
struct target_list *head;

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