mirror of
https://github.com/linux-msm/openocd.git
synced 2026-02-25 13:15:07 -08:00
Add Linux SPI device SWD adapter support
To alleviate the need to bitbang SWD, I've written a SWD SPI implementation. This code is inspired by the work of luppy@appkaki.com as shown at github.com/lupyuen/openocd-spi but with the desire to be more generic. This implementation makes use of the more common 4 wire SPI port using full duplex transfers to be able to capture the SWD ACK bits when a SWD TX operation is in progress. TEST: Connects successfully with the following combinations: Hosts: Raspberry Pi 4B Unnamed Qualcomm SoC with QUPv3 based SPI port Targets: Raspberry Pi 2040 Nordic nRF52840 NXP RT500 Change-Id: Ic2f38a1806085d527e6f999a3d15aea6f32d1019 Signed-off-by: Richard Pasek <rpasek@google.com> Reviewed-on: https://review.openocd.org/c/openocd/+/8645 Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: zapb <dev@zapb.de> Tested-by: jenkins
This commit is contained in:
committed by
Tomas Vanek
parent
26f2df80c3
commit
83e0293f7b
@@ -163,6 +163,9 @@ m4_define([PCIE_ADAPTERS],
|
||||
m4_define([SERIAL_PORT_ADAPTERS],
|
||||
[[[buspirate], [Bus Pirate], [BUS_PIRATE]]])
|
||||
|
||||
m4_define([LINUXSPIDEV_ADAPTER],
|
||||
[[[linuxspidev], [Linux spidev driver], [LINUXSPIDEV]]])
|
||||
|
||||
# The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter
|
||||
# because there is an M4 macro called 'adapter'.
|
||||
m4_define([DUMMY_ADAPTER],
|
||||
@@ -289,6 +292,7 @@ AC_ARG_ADAPTERS([
|
||||
LIBFTDI_ADAPTERS,
|
||||
LIBFTDI_USB1_ADAPTERS,
|
||||
LIBGPIOD_ADAPTERS,
|
||||
LINUXSPIDEV_ADAPTER,
|
||||
SERIAL_PORT_ADAPTERS,
|
||||
DUMMY_ADAPTER,
|
||||
PCIE_ADAPTERS,
|
||||
@@ -726,6 +730,7 @@ PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o
|
||||
PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build])
|
||||
PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"],
|
||||
[internal error: validation should happen beforehand])
|
||||
PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes"], [Linux spidev])
|
||||
PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused])
|
||||
|
||||
AS_IF([test "x$enable_linuxgpiod" != "xno"], [
|
||||
@@ -875,6 +880,7 @@ m4_foreach([adapter], [USB1_ADAPTERS,
|
||||
LIBFTDI_USB1_ADAPTERS,
|
||||
LIBGPIOD_ADAPTERS,
|
||||
LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS,
|
||||
LINUXSPIDEV_ADAPTER,
|
||||
DUMMY_ADAPTER,
|
||||
OPTIONAL_LIBRARIES,
|
||||
COVERAGE],
|
||||
|
||||
@@ -614,6 +614,9 @@ 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{linuxspidev}
|
||||
@* A SPI based SWD driver using Linux SPI devices.
|
||||
|
||||
@item @b{linuxgpiod}
|
||||
@* A bitbang JTAG driver using Linux GPIO through library libgpiod.
|
||||
|
||||
@@ -3401,6 +3404,70 @@ See @file{interface/beaglebone-swd-native.cfg} for a sample configuration file.
|
||||
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Driver} {linuxspidev}
|
||||
Linux provides userspace access to SPI through spidev. Full duplex SPI
|
||||
transactions are used to simultaneously read and write to/from the target to
|
||||
emulate the SWD transport.
|
||||
|
||||
@deffn {Config Command} {spidev path} path
|
||||
Specifies the path to the spidev device.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {spidev mode} value
|
||||
Set the mode of the spi port with optional bit flags (default=3).
|
||||
See /usr/include/linux/spi/spidev.h for all of the SPI mode options.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {spidev queue_entries} value
|
||||
Set the maximum number of queued transactions per spi exchange (default=64).
|
||||
More queued transactions may offer greater performance when the target doesn't
|
||||
need to wait. On the contrary higher numbers will reduce performance when the
|
||||
target requests a wait as all queued transactions will need to be exchanged
|
||||
before spidev can see the wait request.
|
||||
@end deffn
|
||||
|
||||
See @file{tcl/interface/spidev_example.cfg} for a sample configuration file.
|
||||
|
||||
Electrical connections:
|
||||
@example
|
||||
+--------------+ +--------------+
|
||||
| | 1K | |
|
||||
| MOSI|---/\/\/\---+ | |
|
||||
| Host | | | Target |
|
||||
| MISO|------------+---|SWDIO |
|
||||
| | | |
|
||||
| SCK|----------------|SWDCLK |
|
||||
| | | |
|
||||
+--------------+ +--------------+
|
||||
@end example
|
||||
|
||||
The 1K resistor works well with most MCUs up to 3 MHz. A lower resistance
|
||||
could be used to achieve higher speeds granted that the target SWDIO pin has
|
||||
enough drive strength to pull the signal high while being pulled low by this
|
||||
resistor.
|
||||
|
||||
If you are having trouble here are some tips:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@item @b{Make sure MISO and MOSI are tied together with a 1K resistor.}
|
||||
MISO should be attached to the target.
|
||||
|
||||
@item @b{Make sure that your host and target are using the same I/O voltage}
|
||||
(for example both are using 3.3 volts).
|
||||
|
||||
@item @b{Your host's SPI port may not idle low.}
|
||||
This will lead to an additional clock edge being sent to the target, causing
|
||||
the host and target being 1 clock off from each other. Try setting
|
||||
SPI_MOSI_IDLE_LOW in spi_mode. Try using a different spi_mode (0 - 3).
|
||||
|
||||
@item @b{Your target may pull SWDIO and/or SWDCLK high.}
|
||||
This will create an extra edge when the host releases control of the SPI port
|
||||
at the end of a transaction. You'll need to confirm this with a scope or meter.
|
||||
Try installing 10K resistors on SWDIO and SWDCLK to ground to stop this.
|
||||
|
||||
@end itemize
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Driver} {linuxgpiod}
|
||||
Linux provides userspace access to GPIO through libgpiod since Linux kernel
|
||||
|
||||
@@ -176,6 +176,9 @@ endif
|
||||
if SYSFSGPIO
|
||||
DRIVERFILES += %D%/sysfsgpio.c
|
||||
endif
|
||||
if LINUXSPIDEV
|
||||
DRIVERFILES += %D%/linuxspidev.c
|
||||
endif
|
||||
if XLNX_PCIE_XVC
|
||||
DRIVERFILES += %D%/xlnx-pcie-xvc.c
|
||||
endif
|
||||
|
||||
622
src/jtag/drivers/linuxspidev.c
Normal file
622
src/jtag/drivers/linuxspidev.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -386,6 +386,7 @@ extern struct adapter_driver jtag_dpi_adapter_driver;
|
||||
extern struct adapter_driver jtag_vpi_adapter_driver;
|
||||
extern struct adapter_driver kitprog_adapter_driver;
|
||||
extern struct adapter_driver linuxgpiod_adapter_driver;
|
||||
extern struct adapter_driver linuxspidev_adapter_driver;
|
||||
extern struct adapter_driver opendous_adapter_driver;
|
||||
extern struct adapter_driver openjtag_adapter_driver;
|
||||
extern struct adapter_driver osbdm_adapter_driver;
|
||||
|
||||
@@ -123,6 +123,9 @@ struct adapter_driver *adapter_drivers[] = {
|
||||
#if BUILD_LINUXGPIOD == 1
|
||||
&linuxgpiod_adapter_driver,
|
||||
#endif
|
||||
#if BUILD_LINUXSPIDEV == 1
|
||||
&linuxspidev_adapter_driver,
|
||||
#endif
|
||||
#if BUILD_XLNX_PCIE_XVC == 1
|
||||
&xlnx_pcie_xvc_adapter_driver,
|
||||
#endif
|
||||
|
||||
9
tcl/interface/spidev_example.cfg
Normal file
9
tcl/interface/spidev_example.cfg
Normal file
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# Example config for using Linux spidev as a SWD adapter.
|
||||
|
||||
adapter driver linuxspidev
|
||||
adapter speed 3000
|
||||
spidev path "/dev/spidev0.0"
|
||||
spidev mode 3
|
||||
spidev queue_entries 64
|
||||
Reference in New Issue
Block a user