Merge commit '8289862b55e2a0dc658c3c7e2f6ab9878d0527fa' into sam-update
# Conflicts: # README.md # src/platforms/common/cdcacm.c
This commit is contained in:
commit
93cf62d944
2
Makefile
2
Makefile
@ -13,7 +13,7 @@ ifeq ($(PROBE_HOST), pc-stlinkv2)
|
||||
PC_HOSTED = true
|
||||
NO_LIBOPENCM3 = true
|
||||
endif
|
||||
ifeq ($(PROBE_HOST), pc-hosted)
|
||||
ifeq ($(PROBE_HOST), hosted)
|
||||
PC_HOSTED = true
|
||||
NO_LIBOPENCM3 = true
|
||||
endif
|
||||
|
9
UsingSWO
9
UsingSWO
@ -109,12 +109,13 @@ Note that swolisten can be used with either BMP firmware, or with a
|
||||
conventional TTL serial dongle. See at the bottom of this file for
|
||||
information on how to use a dongle.
|
||||
|
||||
The command line to build the swolisten tool is;
|
||||
The command line to build the swolisten tool may look like:
|
||||
|
||||
gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib -lusb-1.0 swolisten.c -o swolisten
|
||||
E.g. for Ubuntu
|
||||
gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib swolisten.c -o swolisten -lusb-1.0
|
||||
|
||||
For Opensuse:
|
||||
gcc -I /usr/include/libusb-1.0 -lusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og
|
||||
E.g. For Opensuse:
|
||||
gcc -I /usr/include/libusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og -lusb-1.0
|
||||
|
||||
...you will obviously need to change the paths to your libusb files.
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from time import sleep
|
||||
import struct
|
||||
import os
|
||||
@ -27,9 +28,9 @@ import argparse
|
||||
import usb
|
||||
import dfu
|
||||
|
||||
CMD_GETCOMMANDS = 0x00
|
||||
CMD_SETADDRESSPOINTER = 0x21
|
||||
CMD_ERASE = 0x41
|
||||
CMD_GETCOMMANDS = 0x00
|
||||
CMD_SETADDRESSPOINTER = 0x21
|
||||
CMD_ERASE = 0x41
|
||||
|
||||
def stm32_erase(dev, addr):
|
||||
erase_cmd = struct.pack("<BL", CMD_ERASE, addr)
|
||||
@ -196,7 +197,7 @@ if __name__ == "__main__":
|
||||
exit(0)
|
||||
dfudev.make_idle()
|
||||
file = open(args.progfile, "rb")
|
||||
if (os.path.getsize(args.progfile) > 0x1f800):
|
||||
if (os.path.getsize(args.progfile) > 0x1f800):
|
||||
print("File too large")
|
||||
exit(0)
|
||||
|
||||
@ -212,7 +213,7 @@ if __name__ == "__main__":
|
||||
start = 0x8002000
|
||||
addr = start
|
||||
while bin:
|
||||
print ("Programming memory at 0x%08X\r" % addr),
|
||||
print ("Programming memory at 0x%08X" % addr, end="\r")
|
||||
stdout.flush()
|
||||
try:
|
||||
# STM DFU bootloader erases always.
|
||||
@ -243,7 +244,7 @@ if __name__ == "__main__":
|
||||
except:
|
||||
# Abort silent if bootloader does not support upload
|
||||
break
|
||||
print ("Verifying memory at 0x%08X\r" % addr),
|
||||
print ("Verifying memory at 0x%08X" % addr, end="\r")
|
||||
stdout.flush()
|
||||
if len > 1024 :
|
||||
size = 1024
|
||||
|
@ -490,19 +490,23 @@ handle_v_packet(char *packet, int plen)
|
||||
target_reset(cur_target);
|
||||
flash_mode = 1;
|
||||
}
|
||||
if(target_flash_erase(cur_target, addr, len) == 0)
|
||||
if(target_flash_erase(cur_target, addr, len) == 0) {
|
||||
gdb_putpacketz("OK");
|
||||
else
|
||||
} else {
|
||||
flash_mode = 0;
|
||||
gdb_putpacketz("EFF");
|
||||
}
|
||||
|
||||
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
|
||||
/* Write Flash Memory */
|
||||
len = plen - bin;
|
||||
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
|
||||
if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
|
||||
if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0) {
|
||||
gdb_putpacketz("OK");
|
||||
else
|
||||
} else {
|
||||
flash_mode = 0;
|
||||
gdb_putpacketz("EFF");
|
||||
}
|
||||
|
||||
} else if (!strcmp(packet, "vFlashDone")) {
|
||||
/* Commit flash operations. */
|
||||
|
23
src/platforms/Readme.md
Normal file
23
src/platforms/Readme.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Platforms and platform support files
|
||||
|
||||
This directory contains the implementation of platforms and support file
|
||||
used by (multiple) platforms.
|
||||
|
||||
## Implementation directories
|
||||
|
||||
native : Firmware for original Black Magic Probe<br>
|
||||
stlink : Firmware for STLINK-V2 and V21<br>
|
||||
swlink : Firmware for STLINK-V1 and Bluepill<br>
|
||||
hydrabus : Firmware https://hydrabus.com/ <br>
|
||||
f4discovery : Firmware for STM32F407DISCO<br>
|
||||
launchpad-icdi :<br>
|
||||
tm4c: <br>
|
||||
hosted: PC-hosted BMP running as PC application talking to firmware BMPs,
|
||||
STLINK-V2/21/3, FTDI MPSSE probes, CMSIS-DAP and JLINK
|
||||
|
||||
|
||||
## Support directories
|
||||
|
||||
common: libopencm3 based support for firmware BMPs<br>
|
||||
stm32: STM32 specific libopencm3 based support for firmware BMPs<br>
|
||||
pc: Support for PC-hosted BMPs.<br>
|
@ -61,7 +61,7 @@ static const struct usb_device_descriptor dev = {
|
||||
#ifdef SAMD21E17
|
||||
.bMaxPacketSize0 = 64,
|
||||
#else
|
||||
.bMaxPacketSize0 = 8,
|
||||
.bMaxPacketSize0 = 32,
|
||||
#endif
|
||||
.idVendor = 0x1D50,
|
||||
.idProduct = 0x6018,
|
||||
|
@ -52,6 +52,8 @@ static void swdptap_turnaround(int dir)
|
||||
SWDIO_MODE_FLOAT();
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
if(dir == SWDIO_STATUS_DRIVE)
|
||||
SWDIO_MODE_DRIVE();
|
||||
@ -68,6 +70,9 @@ static uint32_t swdptap_seq_in(int ticks)
|
||||
int res;
|
||||
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
if (res)
|
||||
ret |= index;
|
||||
index <<= 1;
|
||||
@ -90,20 +95,22 @@ static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||
|
||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||
while (len--) {
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
if (bit) {
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
if (bit)
|
||||
res |= index;
|
||||
}
|
||||
index <<= 1;
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
int parity = __builtin_popcount(res);
|
||||
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
if (bit)
|
||||
parity++;
|
||||
else
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
for (int i = 0; i < len; i++)
|
||||
@ -115,42 +122,39 @@ static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
int data = MS & 1;
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
for (int i = 0; i < ticks; i++)
|
||||
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
||||
#endif
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||
while (ticks--) {
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
MS >>= 1;
|
||||
data = MS & 1;
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
MS >>= 1;
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
int parity = __builtin_popcount(MS);
|
||||
int data = MS & 1;
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
for (int i = 0; i < ticks; i++)
|
||||
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
||||
#endif
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||
MS >>= 1;
|
||||
while (ticks--) {
|
||||
data = MS & 1;
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||
MS >>= 1;
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
|
@ -1,28 +0,0 @@
|
||||
System vs BMP Bootloader
|
||||
========================
|
||||
For the BMP bootloader, flashing was not reliable. So we use the system
|
||||
bootloder unconditional.
|
||||
|
||||
Connections:
|
||||
====================
|
||||
|
||||
PA0: User button to force system bootloader entry with reset
|
||||
PA2/PA3 eventual connected to the STLINK/ STM32F103C8
|
||||
|
||||
PC2: TDI
|
||||
PC4: TMS/SWDIO
|
||||
PC5: TCK/SWCLK
|
||||
PC6: TDO/TRACESWO
|
||||
|
||||
PC1: TRST
|
||||
PC8: SRST
|
||||
|
||||
PD15/Blue Led: Indicator that system bootloader is entered via BMP
|
||||
|
||||
Bootstrapping the F4Discovery on-board ST-Link
|
||||
==============================================
|
||||
http://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe has some hints
|
||||
how to modify the F4Discovery on-board ST-Link. If you try to do so and hit
|
||||
a problem that stands some test like that you load the right firmware to the
|
||||
right device via the right BMP probe, explain, report and ask on the
|
||||
blackmagic mailing list http://sourceforge.net/mail/?group_id=407419.
|
13
src/platforms/f4discovery/Readme.md
Normal file
13
src/platforms/f4discovery/Readme.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Firmware BMP for STM32F407 DISCO boards
|
||||
|
||||
Kept for historical reasons to load BMP bootloader to the STM32F103 of the onboard STLINK or external STLINKs. As stlink-tool now allows to load BMP firmware via the original STLINK bootloader is no longer really needed.
|
||||
|
||||
## Connections:
|
||||
|
||||
PC2: TDI<br>
|
||||
PC4: TMS/SWDIO<br>
|
||||
PC5: TCK/SWCLK<br>
|
||||
PC6: TDO/TRACESWO<br>
|
||||
|
||||
PC1: TRST<br>
|
||||
PC8: SRST<br>
|
@ -1,5 +1,6 @@
|
||||
SYS = $(shell $(CC) -dumpmachine)
|
||||
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
|
||||
CFLAGS += -DUSE_USB_VERSION_BIT
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
||||
|
||||
ifneq (, $(findstring linux, $(SYS)))
|
||||
@ -15,22 +16,28 @@ SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
LDFLAGS += -lsetupapi
|
||||
#https://github.com/dmlc/xgboost/issues/1945 indicates macosx as indicator
|
||||
else ifneq (filter, macosx darwin, $(SYS)))
|
||||
LDFLAGS += -lsetupapi
|
||||
LDFLAGS += hidapi/mac/.libs/libhidapi.a -framework IOKit
|
||||
LDFLAGS += -framework CoreFoundation hidapi/mac/.libs/libhidapi.a
|
||||
else ifneq (filter, macosx darwin, $(SYS))
|
||||
SRC += serial_unix.c
|
||||
LDFLAGS += -lhidapi
|
||||
LDFLAGS += -framework CoreFoundation
|
||||
CFLAGS += -Ihidapi/hidapi
|
||||
endif
|
||||
|
||||
LDFLAGS += -lusb-1.0
|
||||
CFLAGS += $(shell pkg-config --cflags libftdi1)
|
||||
LDFLAGS += $(shell pkg-config --libs libftdi1)
|
||||
CFLAGS += -Wno-missing-field-initializers
|
||||
|
||||
ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
|
||||
CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
|
||||
LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
|
||||
CFLAGS += -DCMSIS_DAP
|
||||
SRC += cmsis_dap.c dap.c
|
||||
ifneq (, $(findstring mingw, $(SYS)))
|
||||
SRC += cmsis_dap.c dap.c hid.c
|
||||
CFLAGS += -DCMSIS_DAP
|
||||
else
|
||||
ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
|
||||
CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
|
||||
LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
|
||||
CFLAGS += -DCMSIS_DAP
|
||||
SRC += cmsis_dap.c dap.c
|
||||
endif
|
||||
endif
|
||||
|
||||
VPATH += platforms/pc
|
||||
|
@ -13,19 +13,51 @@ connect to the BMP with the CDCACM GDB serial server. GDB functionality
|
||||
is the same, monitor option may vary.
|
||||
|
||||
More arguments allow to
|
||||
### print information on the connected target "blackmagiv -t"
|
||||
### directly flash a binary file at 0x0800000 "blackmagic <file.bin>"
|
||||
### Print information on the connected target
|
||||
```
|
||||
blackmagic -t
|
||||
```
|
||||
### Directly flash a binary file at lowest flash address
|
||||
```
|
||||
blackmagic <file.bin>
|
||||
```
|
||||
or with the -S argument at some other address
|
||||
### read flash to binary file "blackmagic -r <file>.bin
|
||||
### verify flash against binary file "blackmagic -V <file>.bin
|
||||
|
||||
Use "blackmagic -h" to see all options.
|
||||
```
|
||||
blackmagic -S 0x08002000 <file.bin>
|
||||
```
|
||||
|
||||
### Read flash to binary file
|
||||
```
|
||||
blackmagic -r <file>.bin
|
||||
```
|
||||
### Verify flash against binary file
|
||||
```
|
||||
blackmagic -V <file>.bin
|
||||
```
|
||||
### Show more options
|
||||
```
|
||||
blackmagic -h"
|
||||
```
|
||||
## Used libraries:
|
||||
### libusb
|
||||
### libftdi, for FTDI support
|
||||
### hidapi-libusb, for CMSIS-DAP support
|
||||
|
||||
## Compiling on windows
|
||||
|
||||
You can crosscompile blackmagic for windows with mingw or on windows
|
||||
with cygwin. For compilation, headers for libftdi1 and libusb-1.0 are
|
||||
needed. For running, libftdi1.dll and libusb-1.0.dll are needed and
|
||||
the executable must be able to find them. Mingw on cygwin does not provide
|
||||
a libftdi package yet.
|
||||
|
||||
To prepare libusb access to the ftdi device, run zadig https://zadig.akeo.ie/.
|
||||
Choose WinUSB(libusb-1.0) for the BMP Ftdi device.
|
||||
|
||||
Running cygwin/blackmagic in a cygwin console, the program does not react
|
||||
on ^C. In another console, run "ps ax" to find the WINPID of the process
|
||||
and then "taskkill /F ?PID (WINPID)".
|
||||
|
||||
## Supported debuggers
|
||||
REMOTE_BMP is a "normal" BMP usb connected
|
||||
|
||||
@ -39,16 +71,76 @@ REMOTE_BMP is a "normal" BMP usb connected
|
||||
| FTDI MPSSE | ++ | Requires a device descrition
|
||||
| JLINK | - | Usefull to add BMP support for MCUs with built-in JLINK
|
||||
|
||||
## Device matching
|
||||
As other USB dongles already connected to the host PC may use FTDI chips,
|
||||
cable descriptions must be provided to match with the dongle.
|
||||
To match the dongle, at least USB VID/PID that must match.
|
||||
If a description is given, the USB device must provide that string. If a
|
||||
serial number string is given on the command line, that number must match
|
||||
with serial number in the USB descriptor of the device.
|
||||
|
||||
## FTDI connection possibilities:
|
||||
|
||||
| Direct Connection |
|
||||
| ----------------------|
|
||||
| MPSSE_SK --> JTAG_TCK |
|
||||
| MPSSE_DO --> JTAG_TDI |
|
||||
| MPSSE_DI <-- JTAG_TDO |
|
||||
| MPSSE_CS <-> JTAG_TMS |
|
||||
|
||||
\+ JTAG and bitbanging SWD is possible<br>
|
||||
\- No level translation, no buffering, no isolation<br>
|
||||
Example: [Flossjtag](https://randomprojects.org/wiki/Floss-JTAG).
|
||||
|
||||
| Resistor SWD |
|
||||
|------------------------|
|
||||
| MPSSE_SK ---> JTAG_TCK |
|
||||
| MPSSE_DO -R-> JTAG_TMS |
|
||||
| MPSSE_DI <--- JTAG_TMS |
|
||||
|
||||
BMP would allow direct MPSSE_DO ->JTAG_TMS connections as BMP tristates DO
|
||||
when reading. Resistor defeats contentions anyways. R is typical choosen
|
||||
in the range of 470R
|
||||
|
||||
\+ MPSSE SWD possible<br>
|
||||
\- No Jtag, no level translation, no buffering, no isolation<br>
|
||||
|
||||
|Direct buffered Connection|
|
||||
|--------------------------|
|
||||
| MPSSE_SK -B-> JTAG_TCK |
|
||||
| MPSSE_DO -B-> JTAG_TDI |
|
||||
| MPSSE_DI <-B- JTAG_TDO |
|
||||
| MPSSE_CS -B-> JTAG_TMS |
|
||||
|
||||
\+ Only Jtag, buffered, possible level translation and isolation<br>
|
||||
\- No SWD<br>
|
||||
Example: [Turtelizer]http://www.ethernut.de/en/hardware/turtelizer/index.html)
|
||||
[schematics](http://www.ethernut.de/pdf/turtelizer20c-schematic.pdf)
|
||||
|
||||
The 'r' command line arguments allows to specify an external SWD
|
||||
resistor connection added to some existing cable. Jtag is not possible
|
||||
together with the 'r' argument.
|
||||
|
||||
### Many variants possible
|
||||
As the FTDI has more pins, these pins may be used to control
|
||||
enables of buffers and multiplexer selection in many variants.
|
||||
|
||||
### FTDI SWD speed
|
||||
SWD read needs two USB round trip, one for the acknowledge and one
|
||||
round-trip after the data phase, while JTAG only needs one round-trip.
|
||||
For that, SWD read speed is about half the JTAG read speed.
|
||||
|
||||
### Reset, Target voltage readback etc
|
||||
The additional pins may also control Reset functionality, provide
|
||||
information if target voltage is applied. etc.
|
||||
|
||||
### Cable descriptions
|
||||
Please help to verify the cable description and give feedback on the
|
||||
cables already listed and propose other cable. A link to the schematics
|
||||
is welcome.
|
||||
|
||||
## Feedback
|
||||
### Issues and Pull request on https://github.com/blacksphere/blackmagic/
|
||||
### Discussions on Discord.
|
||||
You can find the Discord link here: https://1bitsquared.com/pages/chat
|
||||
### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419
|
||||
|
||||
## Known deficiencies
|
||||
### For REMOTE_BMP
|
||||
#### On windows, the device node must be given on the command line
|
||||
Finding the device from USB VID/PID/Serial in not yet implemented
|
||||
### FTDI MPSSE
|
||||
#### No auto detection
|
||||
Cable description must be given on the command line
|
||||
|
@ -51,18 +51,7 @@ int remote_init(bool verbose)
|
||||
}
|
||||
if (verbose)
|
||||
DEBUG_WARN("Remote is %s\n", &construct[1]);
|
||||
char *p = strstr(&construct[1], "(Firmware v");
|
||||
if (!p)
|
||||
return -1;
|
||||
int major = 0, minor = 0, step = 0;
|
||||
int res = sscanf(p, "(Firmware v%d.%d.%d", &major, &minor, &step);
|
||||
if (res !=3)
|
||||
return -1;
|
||||
uint32_t version = major * 10000 + minor * 100 + step;
|
||||
/* check that firmare is > 1.6.1 */
|
||||
if (version < 10602)
|
||||
return -1;
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool remote_target_get_power(void)
|
||||
@ -346,7 +335,12 @@ static void remote_ap_mem_write_sized(
|
||||
|
||||
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||
{
|
||||
if (remote_init(false)) {
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s",
|
||||
REMOTE_HL_CHECK_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN(
|
||||
"Please update BMP firmware for substantial speed increase!\n");
|
||||
return;
|
||||
|
@ -51,6 +51,7 @@ static int report_size = 512 + 1; // TODO: read actual report size
|
||||
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
||||
int dap_init(bmp_info_t *info)
|
||||
{
|
||||
printf("dap_init\n");
|
||||
if (hid_init())
|
||||
return -1;
|
||||
int size = strlen(info->serial);
|
||||
@ -111,7 +112,7 @@ static uint32_t dap_dp_error(ADIv5_DP_t *dp)
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
bool APnDP = addr & ADIV5_APnDP;
|
||||
@ -128,7 +129,16 @@ static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
|
||||
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
return dap_read_reg(dp, addr);
|
||||
uint32_t res;
|
||||
if (addr & ADIV5_APnDP) {
|
||||
dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
res = dap_dp_low_access(dp, ADIV5_LOW_READ,
|
||||
ADIV5_DP_RDBUFF, 0);
|
||||
} else {
|
||||
res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
}
|
||||
DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void dap_exit_function(void)
|
||||
|
@ -374,11 +374,11 @@ void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
|
||||
} while (buf[1] == DAP_TRANSFER_WAIT);
|
||||
|
||||
if (buf[1] > DAP_TRANSFER_WAIT) {
|
||||
DEBUG_PROBE("dap_write_reg %02x data %08x:fault\n", reg, data);
|
||||
DEBUG_WARN("dap_write_reg %02x data %08x:fault\n", reg, data);
|
||||
dp->fault = 1;
|
||||
}
|
||||
if (buf[1] == DAP_TRANSFER_ERROR) {
|
||||
DEBUG_PROBE("dap_write_reg %02x data %08x: protocoll error\n",
|
||||
DEBUG_WARN("dap_write_reg %02x data %08x: protocoll error\n",
|
||||
reg, data);
|
||||
dap_line_reset();
|
||||
}
|
||||
@ -399,8 +399,8 @@ unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||
dbg_dap_cmd(buf, 1023, 5 + 1);
|
||||
unsigned int transferred = buf[0] + (buf[1] << 8);
|
||||
if (buf[2] > DAP_TRANSFER_FAULT) {
|
||||
DEBUG_PROBE("line_reset\n");
|
||||
if (buf[2] >= DAP_TRANSFER_FAULT) {
|
||||
DEBUG_WARN("dap_read_block @ %08 "PRIx32 " fault -> line reset\n", src);
|
||||
dap_line_reset();
|
||||
}
|
||||
if (sz != transferred) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Copyright (C) 2018 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -36,42 +37,110 @@ static uint8_t outbuf[BUF_SIZE];
|
||||
static uint16_t bufptr = 0;
|
||||
|
||||
cable_desc_t *active_cable;
|
||||
data_desc_t active_state;
|
||||
|
||||
cable_desc_t cable_desc[] = {
|
||||
{
|
||||
/* Direct connection from FTDI to Jtag/Swd.*/
|
||||
/* Direct connection from FTDI to Jtag/Swd.
|
||||
Pin 6 direct connected to RST.*/
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6014,
|
||||
.interface = INTERFACE_A,
|
||||
// No explicit reset
|
||||
.bb_swdio_in_port_cmd = GET_BITS_LOW,
|
||||
.bb_swdio_in_pin = MPSSE_CS,
|
||||
.description = "UM232H",
|
||||
.name = "um232h"
|
||||
},
|
||||
{
|
||||
/* Direct connection from FTDI to Jtag/Swd.
|
||||
Pin 6 direct connected to RST.*/
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6010,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x1B,
|
||||
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
|
||||
.bitbang_tms_in_pin = MPSSE_TMS,
|
||||
.init.data_low = PIN6, /* PULL nRST high*/
|
||||
.bb_swdio_in_port_cmd = GET_BITS_LOW,
|
||||
.bb_swdio_in_pin = MPSSE_CS,
|
||||
.assert_srst.data_low = ~PIN6,
|
||||
.assert_srst.ddr_low = PIN6,
|
||||
.deassert_srst.data_low = PIN6,
|
||||
.deassert_srst.ddr_low = ~PIN6,
|
||||
.description = "FLOSS-JTAG",
|
||||
.name = "flossjtag"
|
||||
},
|
||||
{
|
||||
/* MPSSE_SK (DB0) ----------- SWDCK/JTCK
|
||||
* MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS
|
||||
* MPSSE-DI (DB2) ----------- SWDIO/JTMS
|
||||
* DO is tristated with SWD read, so
|
||||
* resistor is not necessary, but protects
|
||||
* from contentions in case of errors.
|
||||
* JTAG not possible
|
||||
* PIN6 (DB6) ----------- NRST */
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6010,/*FT2232H*/
|
||||
.interface = INTERFACE_B,
|
||||
.init.data_low = PIN4, /* Pull up pin 4 */
|
||||
.init.ddr_low = PIN4, /* Pull up pin 4 */
|
||||
.mpsse_swd_read.set_data_low = MPSSE_DO,
|
||||
.mpsse_swd_write.set_data_low = MPSSE_DO,
|
||||
.assert_srst.data_low = ~PIN6,
|
||||
.assert_srst.ddr_low = PIN6,
|
||||
.deassert_srst.data_low = PIN6,
|
||||
.deassert_srst.ddr_low = ~PIN6,
|
||||
.target_voltage_cmd = GET_BITS_LOW,
|
||||
.target_voltage_pin = PIN4, /* Always read as target voltage present.*/
|
||||
.description = "USBMATE",
|
||||
.name = "usbmate"
|
||||
},
|
||||
{
|
||||
/* MPSSE_SK (DB0) ----------- SWDCK/JTCK
|
||||
* MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS
|
||||
* MPSSE-DI (DB2) ----------- SWDIO/JTMS
|
||||
* DO is tristated with SWD read, so
|
||||
* resistor is not necessary, but protects
|
||||
* from contentions in case of errors.
|
||||
* JTAG not possible.*/
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6014,/*FT232H*/
|
||||
.interface = INTERFACE_A,
|
||||
.mpsse_swd_read.set_data_low = MPSSE_DO,
|
||||
.mpsse_swd_write.set_data_low = MPSSE_DO,
|
||||
.name = "ft232h_resistor_swd"
|
||||
},
|
||||
{
|
||||
/* Buffered connection from FTDI to Jtag/Swd.
|
||||
* TCK and TMS not independant switchable!
|
||||
* SWD not possible. */
|
||||
* SWD not possible.
|
||||
* PIN4 low enables buffers
|
||||
* PIN5 Low indicates VRef applied
|
||||
* PIN6 reads back SRST
|
||||
* CBUS PIN1 Sets SRST
|
||||
* CBUS PIN2 low drives SRST
|
||||
*/
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6010,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x1B,
|
||||
.init.ddr_low = PIN4,
|
||||
.init.data_high = PIN4 | PIN3 | PIN2,
|
||||
.init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
|
||||
.assert_srst.data_high = ~PIN2,
|
||||
.deassert_srst.data_high = PIN2,
|
||||
.srst_get_port_cmd = GET_BITS_LOW,
|
||||
.srst_get_pin = PIN6,
|
||||
.description = "FTDIJTAG",
|
||||
.name = "ftdijtag"
|
||||
},
|
||||
{
|
||||
/* UART/SWO on Interface A
|
||||
* JTAG and control on INTERFACE_B
|
||||
* Bit 5 high selects SWD-READ (TMS routed to TDO)
|
||||
* Bit 6 high selects JTAG vs SWD (TMS routed to TDI/TDO)
|
||||
* Bit 5 high selects SWD-WRITE (TMS routed to MPSSE_DI)
|
||||
* Bit 6 high selects JTAG vs SWD (TMS routed to MPSSE_CS)
|
||||
* BCBUS 1 (Output) N_SRST
|
||||
* BCBUS 2 (Input) V_ISO available
|
||||
* BCBUS 2 (Input/ Internal Pull Up) V_ISO available
|
||||
*
|
||||
* For bitbanged SWD, set Bit 5 low and select SWD read with
|
||||
* Bit 6 low. Read Connector TMS as FTDI TDO.
|
||||
* Bit 6 low. Read Connector TMS as MPSSE_DI.
|
||||
*
|
||||
* TDO is routed to Interface 0 RXD as SWO or with Uart
|
||||
* Connector pin 10 pulled to ground will connect Interface 0 RXD
|
||||
@ -80,33 +149,51 @@ cable_desc_t cable_desc[] = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6010,
|
||||
.interface = INTERFACE_B,
|
||||
.dbus_data = 0x6A,
|
||||
.dbus_ddr = 0x6B,
|
||||
.cbus_data = 0x02,
|
||||
.cbus_ddr = 0x02,
|
||||
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
|
||||
.bitbang_tms_in_pin = MPSSE_TDO, /* keep bit 5 low*/
|
||||
.bitbang_swd_dbus_read_data = 0x02,
|
||||
.name = "ftdiswd"
|
||||
.init.data_low = PIN6 | PIN5,
|
||||
.init.ddr_low = PIN6 | PIN5,
|
||||
.init.data_high = PIN1 | PIN2,
|
||||
.assert_srst.data_high = ~PIN1,
|
||||
.assert_srst.ddr_high = PIN1,
|
||||
.deassert_srst.data_high = PIN1,
|
||||
.deassert_srst.ddr_high = ~PIN1,
|
||||
.mpsse_swd_read.clr_data_low = PIN5 | PIN6,
|
||||
.mpsse_swd_write.set_data_low = PIN5,
|
||||
.mpsse_swd_write.clr_data_low = PIN6,
|
||||
.jtag.set_data_low = PIN6,
|
||||
.target_voltage_cmd = GET_BITS_HIGH,
|
||||
.target_voltage_pin = ~PIN2,
|
||||
.name = "ftdiswd",
|
||||
.description = "FTDISWD"
|
||||
},
|
||||
{
|
||||
.vendor = 0x15b1,
|
||||
.product = 0x0003,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x1B,
|
||||
.init.ddr_low = PIN5,
|
||||
.name = "olimex"
|
||||
},
|
||||
{
|
||||
/* Buffered connection from FTDI to Jtag/Swd.
|
||||
* TCK and TMS not independant switchable!
|
||||
* => SWD not possible. */
|
||||
* => SWD not possible.
|
||||
* DBUS PIN4 / JTAGOE low enables buffers
|
||||
* DBUS PIN5 / TRST high drives nTRST low OC
|
||||
* DBUS PIN6 / RST high drives nSRST low OC
|
||||
* CBUS PIN0 reads back SRST
|
||||
*/
|
||||
.vendor = 0x0403,
|
||||
.product = 0xbdc8,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x1B,
|
||||
.name = "turtelizer"
|
||||
/* Drive low to activate JTAGOE and deassert TRST/RST.*/
|
||||
.init.data_low = 0,
|
||||
.init.ddr_low = PIN6 | PIN5 | PIN4,
|
||||
.init.ddr_high = PIN2, /* ONE LED */
|
||||
.assert_srst.data_low = PIN6,
|
||||
.deassert_srst.data_low = ~PIN6,
|
||||
.srst_get_port_cmd = GET_BITS_HIGH,
|
||||
.srst_get_pin = PIN0,
|
||||
.name = "turtelizer",
|
||||
.description = "Turtelizer JTAG/RS232 Adapter"
|
||||
},
|
||||
{
|
||||
/* https://reference.digilentinc.com/jtag_hs1/jtag_hs1
|
||||
@ -117,8 +204,6 @@ cable_desc_t cable_desc[] = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0xbdc8,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x1B,
|
||||
.name = "jtaghs1"
|
||||
},
|
||||
{
|
||||
@ -126,10 +211,10 @@ cable_desc_t cable_desc[] = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0xbdc8,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0xA8,
|
||||
.dbus_ddr = 0xAB,
|
||||
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
|
||||
.bitbang_tms_in_pin = MPSSE_TMS,
|
||||
.init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
|
||||
.init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
|
||||
.bb_swdio_in_port_cmd = GET_BITS_LOW,
|
||||
.bb_swdio_in_pin = MPSSE_CS,
|
||||
.name = "ftdi"
|
||||
},
|
||||
{
|
||||
@ -137,10 +222,10 @@ cable_desc_t cable_desc[] = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6014,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x88,
|
||||
.dbus_ddr = 0x8B,
|
||||
.cbus_data = 0x20,
|
||||
.cbus_ddr = 0x3f,
|
||||
.init.data_low = PIN7,
|
||||
.init.ddr_low = PIN7,
|
||||
.init.data_high = PIN5,
|
||||
.init.ddr_high = PIN5 | PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
|
||||
.name = "digilent"
|
||||
},
|
||||
{
|
||||
@ -148,10 +233,10 @@ cable_desc_t cable_desc[] = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6014,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x0B,
|
||||
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
|
||||
.bitbang_tms_in_pin = MPSSE_TMS,
|
||||
.init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
|
||||
.init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
|
||||
.bb_swdio_in_port_cmd = GET_BITS_LOW,
|
||||
.bb_swdio_in_pin = MPSSE_CS,
|
||||
.name = "ft232h"
|
||||
},
|
||||
{
|
||||
@ -159,45 +244,63 @@ cable_desc_t cable_desc[] = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6011,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x0B,
|
||||
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
|
||||
.bitbang_tms_in_pin = MPSSE_TMS,
|
||||
.bb_swdio_in_port_cmd = GET_BITS_LOW,
|
||||
.bb_swdio_in_pin = MPSSE_CS,
|
||||
.name = "ft4232h"
|
||||
},
|
||||
{
|
||||
/* http://www.olimex.com/dev/pdf/ARM-USB-OCD.pdf.
|
||||
* BDUS 4 global enables JTAG Buffer.
|
||||
* DBUS 4 global enables JTAG Buffer.
|
||||
* => TCK and TMS not independant switchable!
|
||||
* => SWD not possible. */
|
||||
.vendor = 0x15ba,
|
||||
.product = 0x002b,
|
||||
.interface = INTERFACE_A,
|
||||
.dbus_data = 0x08,
|
||||
.dbus_ddr = 0x1B,
|
||||
.cbus_data = 0x00,
|
||||
.cbus_ddr = 0x08,
|
||||
.init.ddr_low = PIN4,
|
||||
.init.data_high = PIN3 | PIN1 | PIN0,
|
||||
.init.ddr_high = PIN4 | PIN3 | PIN1 | PIN0,
|
||||
.name = "arm-usb-ocd-h"
|
||||
},
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||
{
|
||||
int err;
|
||||
unsigned index = 0;
|
||||
for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]);
|
||||
index++)
|
||||
if (strcmp(cable_desc[index].name, cl_opts->opt_cable) == 0)
|
||||
cable_desc_t *cable = &cable_desc[0];
|
||||
for(; cable->name; cable++) {
|
||||
if (strcmp(cable->name, cl_opts->opt_cable) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (index == sizeof(cable_desc)/sizeof(cable_desc[0])) {
|
||||
DEBUG_WARN( "No cable matching %s found\n", cl_opts->opt_cable);
|
||||
if (!cable->name ) {
|
||||
DEBUG_WARN( "No cable matching found for %s\n", cl_opts->opt_cable);
|
||||
return -1;
|
||||
}
|
||||
|
||||
active_cable = &cable_desc[index];
|
||||
|
||||
DEBUG_WARN("Black Magic Probe for FTDI/MPSSE\n");
|
||||
active_cable = cable;
|
||||
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
|
||||
/* If swd_(read|write) is not given for the selected cable and
|
||||
the 'r' command line argument is give, assume resistor SWD
|
||||
connection.*/
|
||||
if (cl_opts->external_resistor_swd &&
|
||||
(active_cable->mpsse_swd_read.set_data_low == 0) &&
|
||||
(active_cable->mpsse_swd_read.clr_data_low == 0) &&
|
||||
(active_cable->mpsse_swd_read.set_data_high == 0) &&
|
||||
(active_cable->mpsse_swd_read.clr_data_high == 0) &&
|
||||
(active_cable->mpsse_swd_write.set_data_low == 0) &&
|
||||
(active_cable->mpsse_swd_write.clr_data_low == 0) &&
|
||||
(active_cable->mpsse_swd_write.set_data_high == 0) &&
|
||||
(active_cable->mpsse_swd_write.clr_data_high == 0)) {
|
||||
DEBUG_INFO("Using external resistor SWD\n");
|
||||
active_cable->mpsse_swd_read.set_data_low = MPSSE_DO;
|
||||
active_cable->mpsse_swd_write.set_data_low = MPSSE_DO;
|
||||
} else if (!libftdi_swd_possible(NULL, NULL) &&
|
||||
!cl_opts->opt_usejtag) {
|
||||
DEBUG_WARN("SWD with cable not possible, trying JTAG\n");
|
||||
cl_opts->opt_usejtag = true;
|
||||
}
|
||||
if(ftdic) {
|
||||
ftdi_usb_close(ftdic);
|
||||
ftdi_free(ftdic);
|
||||
@ -237,7 +340,58 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
return 0;
|
||||
assert(ftdic != NULL);
|
||||
err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
/* Reset MPSSE controller. */
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
uint8_t ftdi_init[16];
|
||||
/* Test for pending garbage.*/
|
||||
int garbage = ftdi_read_data(ftdic, ftdi_init, sizeof(ftdi_init));
|
||||
if (garbage > 0) {
|
||||
DEBUG_WARN("FTDI init garbage at start:");
|
||||
for (int i = 0; i < garbage; i++)
|
||||
DEBUG_WARN(" %02x", ftdi_init[i]);
|
||||
DEBUG_WARN("\n");
|
||||
}
|
||||
int index = 0;
|
||||
ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/
|
||||
ftdi_init[index++]= TCK_DIVISOR;
|
||||
/* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
|
||||
ftdi_init[index++]= 1;
|
||||
ftdi_init[index++]= 0;
|
||||
ftdi_init[index++]= SET_BITS_LOW;
|
||||
ftdi_init[index++]= active_state.data_low;
|
||||
ftdi_init[index++]= active_state.ddr_low;
|
||||
ftdi_init[index++]= SET_BITS_HIGH;
|
||||
ftdi_init[index++]= active_state.data_high;
|
||||
ftdi_init[index++]= active_state.ddr_high;
|
||||
libftdi_buffer_write(ftdi_init, index);
|
||||
libftdi_buffer_flush();
|
||||
garbage = ftdi_read_data(ftdic, ftdi_init, sizeof(ftdi_init));
|
||||
if (garbage > 0) {
|
||||
DEBUG_WARN("FTDI init garbage at end:");
|
||||
for (int i = 0; i < garbage; i++)
|
||||
DEBUG_WARN(" %02x", ftdi_init[i]);
|
||||
DEBUG_WARN("\n");
|
||||
} return 0;
|
||||
|
||||
error_2:
|
||||
ftdi_usb_close(ftdic);
|
||||
error_1:
|
||||
@ -245,24 +399,106 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void libftdi_srst_set_val(bool assert)
|
||||
static void libftdi_set_data(data_desc_t* data)
|
||||
{
|
||||
(void)assert;
|
||||
libftdi_buffer_flush();
|
||||
uint8_t cmd[6];
|
||||
int index = 0;
|
||||
if ((data->data_low) || (data->ddr_low)) {
|
||||
if (data->data_low > 0)
|
||||
active_state.data_low |= (data->data_low & 0xff);
|
||||
else
|
||||
active_state.data_low &= (data->data_low & 0xff);
|
||||
if (data->ddr_low > 0)
|
||||
active_state.ddr_low |= (data->ddr_low & 0xff);
|
||||
else
|
||||
active_state.ddr_low &= (data->ddr_low & 0xff);
|
||||
cmd[index++] = SET_BITS_LOW;
|
||||
cmd[index++] = active_state.data_low;
|
||||
cmd[index++] = active_state.ddr_low;
|
||||
}
|
||||
if ((data->data_high) || (data->ddr_high)) {
|
||||
if (data->data_high > 0)
|
||||
active_state.data_high |= (data->data_high & 0xff);
|
||||
else
|
||||
active_state.data_high &= (data->data_high & 0xff);
|
||||
if (data->ddr_high > 0)
|
||||
active_state.ddr_high |= (data->ddr_high & 0xff);
|
||||
else
|
||||
active_state.ddr_high &= (data->ddr_high & 0xff);
|
||||
cmd[index++] = SET_BITS_HIGH;
|
||||
cmd[index++] = active_state.data_high;
|
||||
cmd[index++] = active_state.ddr_high;
|
||||
}
|
||||
if (index) {
|
||||
libftdi_buffer_write(cmd, index);
|
||||
libftdi_buffer_flush();
|
||||
}
|
||||
}
|
||||
|
||||
bool libftdi_srst_get_val(void) { return false; }
|
||||
void libftdi_srst_set_val(bool assert)
|
||||
{
|
||||
if (assert)
|
||||
libftdi_set_data(&active_cable->assert_srst);
|
||||
else
|
||||
libftdi_set_data(&active_cable->deassert_srst);
|
||||
}
|
||||
|
||||
bool libftdi_srst_get_val(void)
|
||||
{
|
||||
uint8_t cmd[1] = {0};
|
||||
uint8_t pin = 0;
|
||||
if (active_cable->srst_get_port_cmd && active_cable->srst_get_pin) {
|
||||
cmd[0]= active_cable->srst_get_port_cmd;
|
||||
pin = active_cable->srst_get_pin;
|
||||
} else if (active_cable->assert_srst.data_low &&
|
||||
active_cable->assert_srst.ddr_low) {
|
||||
cmd[0]= GET_BITS_LOW;
|
||||
pin = active_cable->assert_srst.data_low;
|
||||
} else if (active_cable->assert_srst.data_high &&
|
||||
active_cable->assert_srst.ddr_high) {
|
||||
cmd[0]= GET_BITS_HIGH;
|
||||
pin = active_cable->assert_srst.data_high;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
libftdi_buffer_write(cmd, 1);
|
||||
uint8_t data[1];
|
||||
libftdi_buffer_read(data, 1);
|
||||
bool res = false;
|
||||
if (((pin < 0x7f) || (pin == PIN7)))
|
||||
res = data[0] & pin;
|
||||
else
|
||||
res = !(data[0] & ~pin);
|
||||
return res;
|
||||
}
|
||||
|
||||
void libftdi_buffer_flush(void)
|
||||
{
|
||||
if (!bufptr)
|
||||
return;
|
||||
DEBUG_WIRE("Flush %d\n", bufptr);
|
||||
#if defined(USE_USB_VERSION_BIT)
|
||||
static struct ftdi_transfer_control *tc_write = NULL;
|
||||
if (tc_write)
|
||||
ftdi_transfer_data_done(tc_write);
|
||||
tc_write = ftdi_write_data_submit(ftdic, outbuf, bufptr);
|
||||
#else
|
||||
assert(ftdi_write_data(ftdic, outbuf, bufptr) == bufptr);
|
||||
DEBUG_WIRE("FT2232 libftdi_buffer flush: %d bytes\n", bufptr);
|
||||
#endif
|
||||
bufptr = 0;
|
||||
}
|
||||
|
||||
int libftdi_buffer_write(const uint8_t *data, int size)
|
||||
{
|
||||
if((bufptr + size) / BUF_SIZE > 0) libftdi_buffer_flush();
|
||||
DEBUG_WIRE("Write %d bytes:", size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
DEBUG_WIRE(" %02x", data[i]);
|
||||
if (i && ((i & 0xf) == 0xf))
|
||||
DEBUG_WIRE("\n\t");
|
||||
}
|
||||
DEBUG_WIRE("\n");
|
||||
memcpy(outbuf + bufptr, data, size);
|
||||
bufptr += size;
|
||||
return size;
|
||||
@ -270,14 +506,111 @@ int libftdi_buffer_write(const uint8_t *data, int size)
|
||||
|
||||
int libftdi_buffer_read(uint8_t *data, int size)
|
||||
{
|
||||
int index = 0;
|
||||
#if defined(USE_USB_VERSION_BIT)
|
||||
struct ftdi_transfer_control *tc;
|
||||
outbuf[bufptr++] = SEND_IMMEDIATE;
|
||||
libftdi_buffer_flush();
|
||||
tc = ftdi_read_data_submit(ftdic, data, size);
|
||||
ftdi_transfer_data_done(tc);
|
||||
#else
|
||||
int index = 0;
|
||||
const uint8_t cmd[1] = {SEND_IMMEDIATE};
|
||||
libftdi_buffer_write(cmd, 1);
|
||||
libftdi_buffer_flush();
|
||||
while((index += ftdi_read_data(ftdic, data + index, size-index)) != size);
|
||||
#endif
|
||||
DEBUG_WIRE("Read %d bytes:", size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
DEBUG_WIRE(" %02x", data[i]);
|
||||
if (i && ((i & 0xf) == 0xf))
|
||||
DEBUG_WIRE("\n\t");
|
||||
}
|
||||
DEBUG_WIRE("\n");
|
||||
return size;
|
||||
}
|
||||
|
||||
void libftdi_jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
int rsize, rticks;
|
||||
|
||||
if(!ticks) return;
|
||||
if (!DI && !DO) return;
|
||||
|
||||
// printf("ticks: %d\n", ticks);
|
||||
if(final_tms) ticks--;
|
||||
rticks = ticks & 7;
|
||||
ticks >>= 3;
|
||||
uint8_t data[8];
|
||||
uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) |
|
||||
((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB;
|
||||
rsize = ticks;
|
||||
if(ticks) {
|
||||
data[0] = cmd;
|
||||
data[1] = ticks - 1;
|
||||
data[2] = 0;
|
||||
libftdi_buffer_write(data, 3);
|
||||
if (DI)
|
||||
libftdi_buffer_write(DI, ticks);
|
||||
}
|
||||
int index = 0;
|
||||
if(rticks) {
|
||||
rsize++;
|
||||
data[index++] = cmd | MPSSE_BITMODE;
|
||||
data[index++] = rticks - 1;
|
||||
if (DI)
|
||||
data[index++] = DI[ticks];
|
||||
}
|
||||
if(final_tms) {
|
||||
rsize++;
|
||||
data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) |
|
||||
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
|
||||
data[index++] = 0;
|
||||
if (DI)
|
||||
data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
|
||||
}
|
||||
if (index)
|
||||
libftdi_buffer_write(data, index);
|
||||
if (DO) {
|
||||
int index = 0;
|
||||
uint8_t *tmp = alloca(rsize);
|
||||
libftdi_buffer_read(tmp, rsize);
|
||||
if(final_tms) rsize--;
|
||||
|
||||
while(rsize--) {
|
||||
/*if(rsize) printf("%02X ", tmp[index]);*/
|
||||
*DO++ = tmp[index++];
|
||||
}
|
||||
if (rticks == 0)
|
||||
*DO++ = 0;
|
||||
if(final_tms) {
|
||||
rticks++;
|
||||
*(--DO) >>= 1;
|
||||
*DO |= tmp[index] & 0x80;
|
||||
} else DO--;
|
||||
if(rticks) {
|
||||
*DO >>= (8-rticks);
|
||||
}
|
||||
/*printf("%02X\n", *DO);*/
|
||||
}
|
||||
}
|
||||
|
||||
const char *libftdi_target_voltage(void)
|
||||
{
|
||||
return "not supported";
|
||||
uint8_t pin = active_cable->target_voltage_pin;
|
||||
if (active_cable->target_voltage_cmd && pin) {
|
||||
libftdi_buffer_write(&active_cable->target_voltage_cmd, 1);
|
||||
uint8_t data[1];
|
||||
libftdi_buffer_read(data, 1);
|
||||
bool res = false;
|
||||
if (((pin < 0x7f) || (pin == PIN7)))
|
||||
res = data[0] & pin;
|
||||
else
|
||||
res = !(data[0] & ~pin);
|
||||
if (res)
|
||||
return "Present";
|
||||
else
|
||||
return "Absent";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Copyright (C) 2018 Uwe Bonnes (non@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -25,25 +26,82 @@
|
||||
#include "swdptap.h"
|
||||
#include "jtagtap.h"
|
||||
|
||||
typedef struct data_desc_s {
|
||||
int16_t data_low;
|
||||
int16_t ddr_low;
|
||||
int16_t data_high;
|
||||
int16_t ddr_high;
|
||||
}data_desc_t;
|
||||
|
||||
typedef struct pin_settings_s {
|
||||
uint8_t set_data_low;
|
||||
uint8_t clr_data_low;
|
||||
uint8_t set_data_high;
|
||||
uint8_t clr_data_high;
|
||||
}pin_settings_t;
|
||||
|
||||
typedef struct cable_desc_s {
|
||||
int vendor;
|
||||
int product;
|
||||
int interface;
|
||||
uint8_t dbus_data;
|
||||
uint8_t dbus_ddr;
|
||||
uint8_t cbus_data;
|
||||
uint8_t cbus_ddr;
|
||||
uint8_t bitbang_tms_in_port_cmd;
|
||||
uint8_t bitbang_tms_in_pin;
|
||||
uint8_t bitbang_swd_dbus_read_data;
|
||||
/* bitbang_swd_dbus_read_data is same as dbus_data,
|
||||
* as long as CBUS is not involved.*/
|
||||
/* Initial (C|D)(Bus|Ddr) values for additional pins.
|
||||
* MPSSE_CS|DI|DO|SK are initialized accordig to mode.*/
|
||||
data_desc_t init;
|
||||
/* MPSSE command to read TMS/SWDIO in bitbanging SWD.
|
||||
* In many cases this is the TMS port, so then use "GET_PIN_LOW".*/
|
||||
uint8_t bb_swdio_in_port_cmd;
|
||||
/* bus bit to read TMS/SWDIO in bitbanging SWD.
|
||||
* In many cases this is the TMS port, so then use "MPSSE_CS".*/
|
||||
uint8_t bb_swdio_in_pin;
|
||||
/* Bus data to allow bitbanging switched SWD read.
|
||||
* TMS is routed to bb_swdio_in_port/pin.*/
|
||||
pin_settings_t bb_swd_read;
|
||||
/* Bus data to allow bitbanging switched SWD write.
|
||||
* TMS is routed to MPSSE_CS.*/
|
||||
pin_settings_t bb_swd_write;
|
||||
/* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST.
|
||||
* E.g. with CBUS Pin 1 low,
|
||||
* give data_high = ~PIN1, ddr_high = PIN1 */
|
||||
data_desc_t assert_srst;
|
||||
/* Bus_data, dbus_ddr, cbus_data, cbus_ddr value to release SRST.
|
||||
* E.g. with CBUS Pin 1 floating with internal pull up,
|
||||
* give data_high = PIN1, ddr_high = ~PIN1 */
|
||||
data_desc_t deassert_srst;
|
||||
/* Command to read back SRST. If 0, port from assert_srst is used*/
|
||||
uint8_t srst_get_port_cmd;
|
||||
/* PIN to read back as SRST. if 0 port from assert_srst is ised.
|
||||
* Use PINX if active high, use Complement (~PINX) if active low*/
|
||||
uint8_t srst_get_pin;
|
||||
/* Bbus data for pure MPSSE SWD read.
|
||||
* Use together with swd_write if by some bits on DBUS,
|
||||
* SWDIO can be routed to TDI and TDO.
|
||||
* If both mpsse_swd_read|write and
|
||||
* bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
|
||||
* are provided, pure MPSSE SWD is choosen.
|
||||
* If neither a complete set of swd_read|write or
|
||||
* bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
|
||||
* are provided, SWD can not be done.
|
||||
* swd_read.set_data_low == swd_write.set_data_low == MPSSE_DO
|
||||
* indicated resistor SWD and inhibits Jtag.*/
|
||||
pin_settings_t mpsse_swd_read;
|
||||
/* dbus data for pure MPSSE SWD write.*/
|
||||
pin_settings_t mpsse_swd_write;
|
||||
/* dbus data for jtag.*/
|
||||
pin_settings_t jtag;
|
||||
/* Command to read port to check target voltage.*/
|
||||
uint8_t target_voltage_cmd;
|
||||
/* Pin to check target voltage.*/
|
||||
uint8_t target_voltage_pin;
|
||||
/* USB readable description of the device.*/
|
||||
char *description;
|
||||
/* Command line argument to -c option to select this device.*/
|
||||
char * name;
|
||||
}cable_desc_t;
|
||||
|
||||
extern cable_desc_t cable_desc[];
|
||||
extern cable_desc_t *active_cable;
|
||||
extern struct ftdi_context *ftdic;
|
||||
extern data_desc_t active_state;
|
||||
|
||||
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
|
||||
|
||||
@ -53,9 +111,20 @@ void libftdi_buffer_flush(void);
|
||||
int libftdi_buffer_write(const uint8_t *data, int size);
|
||||
int libftdi_buffer_read(uint8_t *data, int size);
|
||||
const char *libftdi_target_voltage(void);
|
||||
void libftdi_jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd);
|
||||
|
||||
#define MPSSE_TDI 2
|
||||
#define MPSSE_TDO 4
|
||||
#define MPSSE_TMS 8
|
||||
|
||||
#define MPSSE_SK 1
|
||||
#define PIN0 1
|
||||
#define MPSSE_DO 2
|
||||
#define PIN1 2
|
||||
#define MPSSE_DI 4
|
||||
#define PIN2 4
|
||||
#define MPSSE_CS 8
|
||||
#define PIN3 8
|
||||
#define PIN4 0x10
|
||||
#define PIN5 0x20
|
||||
#define PIN6 0x40
|
||||
#define PIN7 0x80
|
||||
#endif
|
||||
|
@ -20,8 +20,6 @@
|
||||
|
||||
/* Low level JTAG implementation using FT2232 with libftdi.
|
||||
*
|
||||
* Issues:
|
||||
* Should share interface with swdptap.c or at least clean up...
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -38,50 +36,59 @@ extern struct ftdi_context *ftdic;
|
||||
|
||||
static void jtagtap_reset(void);
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks);
|
||||
static void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks);
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
|
||||
|
||||
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
assert(ftdic != NULL);
|
||||
int err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
if ((active_cable->mpsse_swd_read.set_data_low == MPSSE_DO) &&
|
||||
(active_cable->mpsse_swd_write.set_data_low == MPSSE_DO)) {
|
||||
printf("Jtag not possible with resistor SWD!\n");
|
||||
return -1;
|
||||
}
|
||||
/* Reset MPSSE controller. */
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||
if (err != 0) {
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;
|
||||
}
|
||||
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||
if (err != 0) {
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;
|
||||
}
|
||||
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x00, 0x00, SET_BITS_LOW, 0,0,
|
||||
SET_BITS_HIGH, 0,0};
|
||||
ftdi_init[4]= active_cable->dbus_data;
|
||||
ftdi_init[5]= active_cable->dbus_ddr;
|
||||
ftdi_init[7]= active_cable->cbus_data;
|
||||
ftdi_init[8]= active_cable->cbus_ddr;
|
||||
libftdi_buffer_write(ftdi_init, 9);
|
||||
libftdi_buffer_flush();
|
||||
|
||||
jtag_proc->jtagtap_reset = jtagtap_reset;
|
||||
jtag_proc->jtagtap_next =jtagtap_next;
|
||||
jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = libftdi_jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
|
||||
|
||||
active_state.data_low |= active_cable->jtag.set_data_low |
|
||||
MPSSE_CS | MPSSE_DI | MPSSE_DO;
|
||||
active_state.data_low &= ~(active_cable->jtag.clr_data_low | MPSSE_SK);
|
||||
active_state.ddr_low |= MPSSE_CS | MPSSE_DO | MPSSE_SK;
|
||||
active_state.ddr_low &= ~(MPSSE_DI);
|
||||
active_state.data_high |= active_cable->jtag.set_data_high;
|
||||
active_state.data_high &= ~(active_cable->jtag.clr_data_high);
|
||||
uint8_t gab[16];
|
||||
int garbage = ftdi_read_data(ftdic, gab, sizeof(gab));
|
||||
if (garbage > 0) {
|
||||
DEBUG_WARN("FTDI JTAG init got garbage:");
|
||||
for (int i = 0; i < garbage; i++)
|
||||
DEBUG_WARN(" %02x", gab[i]);
|
||||
DEBUG_WARN("\n");
|
||||
}
|
||||
uint8_t cmd_write[16] = {
|
||||
SET_BITS_LOW, active_state.data_low,
|
||||
active_state.ddr_low,
|
||||
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
|
||||
libftdi_buffer_write(cmd_write, 6);
|
||||
libftdi_buffer_flush();
|
||||
/* Write out start condition and pull garbage from read buffer.
|
||||
* FT2232D otherwise misbehaves on runs follwoing the first run.*/
|
||||
garbage = ftdi_read_data(ftdic, cmd_write, sizeof(cmd_write));
|
||||
if (garbage > 0) {
|
||||
DEBUG_WARN("FTDI JTAG end init got garbage:");
|
||||
for (int i = 0; i < garbage; i++)
|
||||
DEBUG_WARN(" %02x", cmd_write[i]);
|
||||
DEBUG_WARN("\n");
|
||||
}
|
||||
/* Go to JTAG mode for SWJ-DP */
|
||||
for (int i = 0; i <= 50; i++)
|
||||
jtag_proc->jtagtap_next(1, 0); /* Reset SW-DP */
|
||||
jtag_proc->jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */
|
||||
jtag_proc->jtagtap_tms_seq(0x1F, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -93,7 +100,7 @@ static void jtagtap_reset(void)
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t tmp[3] = {
|
||||
MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0};
|
||||
MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0};
|
||||
while(ticks >= 0) {
|
||||
tmp[1] = ticks<7?ticks-1:6;
|
||||
tmp[2] = 0x80 | (MS & 0x7F);
|
||||
@ -103,77 +110,10 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
}
|
||||
}
|
||||
|
||||
static void jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
int rsize, rticks;
|
||||
|
||||
if(!ticks) return;
|
||||
if (!DI && !DO) return;
|
||||
|
||||
// DEBUG_PROBE("ticks: %d\n", ticks);
|
||||
if(final_tms) ticks--;
|
||||
rticks = ticks & 7;
|
||||
ticks >>= 3;
|
||||
uint8_t data[3];
|
||||
uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) |
|
||||
((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB;
|
||||
rsize = ticks;
|
||||
if(ticks) {
|
||||
data[0] = cmd;
|
||||
data[1] = ticks - 1;
|
||||
data[2] = 0;
|
||||
libftdi_buffer_write(data, 3);
|
||||
if (DI)
|
||||
libftdi_buffer_write(DI, ticks);
|
||||
}
|
||||
if(rticks) {
|
||||
int index = 0;
|
||||
rsize++;
|
||||
data[index++] = cmd | MPSSE_BITMODE;
|
||||
data[index++] = rticks - 1;
|
||||
if (DI)
|
||||
data[index++] = DI[ticks];
|
||||
libftdi_buffer_write(data, index);
|
||||
}
|
||||
if(final_tms) {
|
||||
int index = 0;
|
||||
rsize++;
|
||||
data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) |
|
||||
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
|
||||
data[index++] = 0;
|
||||
if (DI)
|
||||
data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
|
||||
libftdi_buffer_write(data, index);
|
||||
}
|
||||
if (DO) {
|
||||
int index = 0;
|
||||
uint8_t *tmp = alloca(ticks);
|
||||
libftdi_buffer_read(tmp, rsize);
|
||||
if(final_tms) rsize--;
|
||||
|
||||
while(rsize--) {
|
||||
if(rsize) DEBUG_WIRE("%02X ", tmp[index]);
|
||||
*DO++ = tmp[index++];
|
||||
}
|
||||
if (rticks == 0)
|
||||
*DO++ = 0;
|
||||
if(final_tms) {
|
||||
rticks++;
|
||||
*(--DO) >>= 1;
|
||||
*DO |= tmp[index] & 0x80;
|
||||
} else DO--;
|
||||
if(rticks) {
|
||||
*DO >>= (8-rticks);
|
||||
}
|
||||
DEBUG_WIRE("%02X\n", *DO);
|
||||
}
|
||||
}
|
||||
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
|
||||
return libftdi_jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
|
||||
}
|
||||
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
@ -187,7 +127,5 @@ static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
|
||||
ret &= 0x80;
|
||||
|
||||
// DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %02X\n", dTMS, dTDI, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -28,52 +28,183 @@
|
||||
#include "general.h"
|
||||
#include "ftdi_bmp.h"
|
||||
|
||||
static uint8_t olddir = 0;
|
||||
enum swdio_status{
|
||||
SWDIO_STATUS_DRIVE = 0,
|
||||
SWDIO_STATUS_FLOAT,
|
||||
};
|
||||
|
||||
#define MPSSE_MASK (MPSSE_TDI | MPSSE_TDO | MPSSE_TMS)
|
||||
#define MPSSE_TD_MASK (MPSSE_TDI | MPSSE_TDO)
|
||||
static enum swdio_status olddir;
|
||||
static bool do_mpsse;
|
||||
static bool direct_bb_swd;
|
||||
|
||||
#define MPSSE_MASK (MPSSE_DO | MPSSE_DI | MPSSE_CS)
|
||||
#define MPSSE_TD_MASK (MPSSE_DO | MPSSE_DI)
|
||||
#define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
|
||||
MPSSE_BITMODE | MPSSE_WRITE_NEG)
|
||||
#define MPSSE_TDO_SHIFT (MPSSE_DO_WRITE | MPSSE_LSB |\
|
||||
MPSSE_BITMODE | MPSSE_WRITE_NEG)
|
||||
static void swdptap_turnaround(enum swdio_status dir)
|
||||
{
|
||||
if (dir == olddir)
|
||||
return;
|
||||
olddir = dir;
|
||||
DEBUG_PROBE("Turnaround %s\n", (dir == SWDIO_STATUS_FLOAT) ? "float": "drive");
|
||||
if (do_mpsse) {
|
||||
if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ {
|
||||
active_state.data_low |= active_cable->mpsse_swd_read.set_data_low | MPSSE_DO;
|
||||
active_state.data_low &= ~active_cable->mpsse_swd_read.clr_data_low;
|
||||
active_state.ddr_low &= ~MPSSE_DO;
|
||||
active_state.data_high |= active_cable->mpsse_swd_read.set_data_high;
|
||||
active_state.data_high &= ~active_cable->mpsse_swd_read.clr_data_high;
|
||||
uint8_t cmd_read[6] = {
|
||||
SET_BITS_LOW, active_state.data_low,
|
||||
active_state.ddr_low,
|
||||
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
|
||||
libftdi_buffer_write(cmd_read, 6);
|
||||
}
|
||||
uint8_t cmd[] = {MPSSE_TDO_SHIFT, 0, 0}; /* One clock cycle */
|
||||
libftdi_buffer_write(cmd, sizeof(cmd));
|
||||
if (dir == SWDIO_STATUS_DRIVE) /* SWDIO goes to output */ {
|
||||
active_state.data_low |= active_cable->mpsse_swd_write.set_data_low | MPSSE_DO;
|
||||
active_state.data_low &= ~active_cable->mpsse_swd_write.clr_data_low;
|
||||
active_state.ddr_low |= MPSSE_DO;
|
||||
active_state.data_high |= active_cable->mpsse_swd_write.set_data_high;
|
||||
active_state.data_high &= ~active_cable->mpsse_swd_write.clr_data_high;
|
||||
uint8_t cmd_write[6] = {
|
||||
SET_BITS_LOW, active_state.data_low,
|
||||
active_state.ddr_low,
|
||||
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
|
||||
libftdi_buffer_write(cmd_write, 6);
|
||||
}
|
||||
} else {
|
||||
uint8_t cmd[9];
|
||||
int index = 0;
|
||||
|
||||
if(dir == SWDIO_STATUS_FLOAT) { /* SWDIO goes to input */
|
||||
if (direct_bb_swd) {
|
||||
active_state.data_low |= MPSSE_CS;
|
||||
active_state.ddr_low &= ~MPSSE_CS;
|
||||
} else {
|
||||
active_state.data_low |= active_cable->bb_swd_read.set_data_low;
|
||||
active_state.data_low &= ~active_cable->bb_swd_read.clr_data_low;
|
||||
active_state.data_high |= active_cable->bb_swd_read.set_data_high;
|
||||
active_state.data_high &= ~active_cable->bb_swd_read.clr_data_high;
|
||||
}
|
||||
cmd[index++] = SET_BITS_LOW;
|
||||
cmd[index++] = active_state.data_low;
|
||||
cmd[index++] = active_state.ddr_low;
|
||||
cmd[index++] = SET_BITS_HIGH;
|
||||
cmd[index++] = active_state.data_high;
|
||||
cmd[index++] = active_state.ddr_high;
|
||||
}
|
||||
/* One clock cycle */
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = 0;
|
||||
if (dir == SWDIO_STATUS_DRIVE) {
|
||||
if (direct_bb_swd) {
|
||||
active_state.data_low |= MPSSE_CS;
|
||||
active_state.ddr_low |= MPSSE_CS;
|
||||
} else {
|
||||
active_state.data_low |= active_cable->bb_swd_write.set_data_low;
|
||||
active_state.data_low &= ~active_cable->bb_swd_write.clr_data_low;
|
||||
active_state.data_high |= active_cable->bb_swd_write.set_data_high;
|
||||
active_state.data_high &= ~active_cable->bb_swd_write.clr_data_high;
|
||||
}
|
||||
cmd[index++] = SET_BITS_LOW;
|
||||
cmd[index++] = active_state.data_low;
|
||||
cmd[index++] = active_state.ddr_low;
|
||||
cmd[index++] = SET_BITS_HIGH;
|
||||
cmd[index++] = active_state.data_high;
|
||||
cmd[index++] = active_state.ddr_high;
|
||||
}
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
}
|
||||
|
||||
static bool swdptap_seq_in_parity(uint32_t *res, int ticks);
|
||||
static uint32_t swdptap_seq_in(int ticks);
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks);
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||
|
||||
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd)
|
||||
{
|
||||
bool swd_read =
|
||||
active_cable->mpsse_swd_read.set_data_low ||
|
||||
active_cable->mpsse_swd_read.clr_data_low ||
|
||||
active_cable->mpsse_swd_read.set_data_high ||
|
||||
active_cable->mpsse_swd_read.clr_data_high;
|
||||
bool swd_write =
|
||||
active_cable->mpsse_swd_write.set_data_low ||
|
||||
active_cable->mpsse_swd_write.clr_data_low ||
|
||||
active_cable->mpsse_swd_write.set_data_high ||
|
||||
active_cable->mpsse_swd_write.clr_data_high;
|
||||
bool mpsse = swd_read && swd_write;
|
||||
if (do_mpsse)
|
||||
*do_mpsse = mpsse;
|
||||
if (!mpsse) {
|
||||
bool bb_swd_read =
|
||||
active_cable->bb_swd_read.set_data_low ||
|
||||
active_cable->bb_swd_read.clr_data_low ||
|
||||
active_cable->bb_swd_read.set_data_high ||
|
||||
active_cable->bb_swd_read.clr_data_high;
|
||||
bool bb_swd_write =
|
||||
active_cable->bb_swd_write.set_data_low ||
|
||||
active_cable->bb_swd_write.clr_data_low ||
|
||||
active_cable->bb_swd_write.set_data_high ||
|
||||
active_cable->bb_swd_write.clr_data_high;
|
||||
bool bb_direct_possible =
|
||||
active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW &&
|
||||
active_cable->bb_swdio_in_pin == MPSSE_CS;
|
||||
if (!bb_swd_read && !bb_swd_write) {
|
||||
if (!bb_direct_possible)
|
||||
return false;
|
||||
}
|
||||
if (direct_bb_swd)
|
||||
*direct_bb_swd = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int libftdi_swdptap_init(swd_proc_t *swd_proc)
|
||||
{
|
||||
if (!active_cable->bitbang_tms_in_pin) {
|
||||
if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) {
|
||||
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
|
||||
return -1;
|
||||
}
|
||||
int err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;
|
||||
active_state.data_low |= MPSSE_CS | MPSSE_DI | MPSSE_DO;
|
||||
active_state.data_low &= MPSSE_SK;
|
||||
active_state.ddr_low |= MPSSE_SK;
|
||||
active_state.ddr_low &= ~(MPSSE_CS | MPSSE_DI | MPSSE_DO);
|
||||
if (do_mpsse) {
|
||||
DEBUG_INFO("Using genuine MPSSE for SWD.\n");
|
||||
active_state.data_low |= active_cable->mpsse_swd_read.set_data_low;
|
||||
active_state.data_low &= ~(active_cable->mpsse_swd_read.clr_data_low);
|
||||
active_state.data_high |= active_cable->mpsse_swd_read.set_data_high;
|
||||
active_state.data_high &= ~(active_cable->mpsse_swd_read.clr_data_high);
|
||||
} else if (direct_bb_swd) {
|
||||
DEBUG_INFO("Using direct bitbang with SWDIO %cBUS%d.\n",
|
||||
(active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW) ? 'C' : 'D',
|
||||
__builtin_ctz(active_cable->bb_swdio_in_pin));
|
||||
} else {
|
||||
DEBUG_INFO("Using switched bitbang for SWD.\n");
|
||||
active_state.data_low |= active_cable->bb_swd_read.set_data_low;
|
||||
active_state.data_low &= ~(active_cable->bb_swd_read.clr_data_low);
|
||||
active_state.data_high |= active_cable->bb_swd_read.set_data_high;
|
||||
active_state.data_high &= ~(active_cable->bb_swd_read.clr_data_high);
|
||||
active_state.ddr_low |= MPSSE_CS;
|
||||
if (active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW)
|
||||
active_state.ddr_low &= ~active_cable->bb_swdio_in_pin;
|
||||
else if (active_cable->bb_swdio_in_port_cmd == GET_BITS_HIGH)
|
||||
active_state.ddr_high &= ~active_cable->bb_swdio_in_pin;
|
||||
}
|
||||
/* Reset MPSSE controller. */
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||
if (err != 0) {
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;
|
||||
}
|
||||
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||
if (err != 0) {
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;
|
||||
}
|
||||
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
|
||||
SET_BITS_HIGH, 0,0};
|
||||
ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK;
|
||||
ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK;
|
||||
ftdi_init[7]= active_cable->cbus_data;
|
||||
ftdi_init[8]= active_cable->cbus_ddr;
|
||||
libftdi_buffer_write(ftdi_init, 9);
|
||||
uint8_t cmd_write[6] = {
|
||||
SET_BITS_LOW, active_state.data_low,
|
||||
active_state.ddr_low,
|
||||
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
|
||||
libftdi_buffer_write(cmd_write, 6);
|
||||
libftdi_buffer_flush();
|
||||
olddir = SWDIO_STATUS_FLOAT;
|
||||
|
||||
swd_proc->swdptap_seq_in = swdptap_seq_in;
|
||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
||||
@ -83,136 +214,185 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void swdptap_turnaround(uint8_t dir)
|
||||
bool swdptap_bit_in(void)
|
||||
{
|
||||
if (dir == olddir)
|
||||
return;
|
||||
olddir = dir;
|
||||
uint8_t cmd[6];
|
||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||
uint8_t cmd[4];
|
||||
int index = 0;
|
||||
bool result = false;
|
||||
|
||||
if(dir) { /* SWDIO goes to input */
|
||||
cmd[index++] = SET_BITS_LOW;
|
||||
if (active_cable->bitbang_swd_dbus_read_data)
|
||||
cmd[index] = active_cable->bitbang_swd_dbus_read_data;
|
||||
else
|
||||
cmd[index] = active_cable->dbus_data;
|
||||
index++;
|
||||
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK;
|
||||
if (do_mpsse) {
|
||||
uint8_t cmd[2] = {MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE, 0};
|
||||
libftdi_buffer_write(cmd, sizeof(cmd));
|
||||
uint8_t data[1];
|
||||
libftdi_buffer_read(data, sizeof(data));
|
||||
result = (data[0] & 0x80);
|
||||
} else {
|
||||
cmd[index++] = active_cable->bb_swdio_in_port_cmd;
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = 0;
|
||||
libftdi_buffer_write(cmd, index);
|
||||
uint8_t data[1];
|
||||
libftdi_buffer_read(data, sizeof(data));
|
||||
result = (data[0] &= active_cable->bb_swdio_in_pin);
|
||||
}
|
||||
/* One clock cycle */
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = 0;
|
||||
if (!dir) {
|
||||
cmd[index++] = SET_BITS_LOW;
|
||||
cmd[index++] = active_cable->dbus_data | MPSSE_MASK;
|
||||
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK;
|
||||
}
|
||||
libftdi_buffer_write(cmd, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
void swdptap_bit_out(bool val)
|
||||
{
|
||||
int index = ticks + 1;
|
||||
uint8_t cmd[4];
|
||||
unsigned int parity = 0;
|
||||
|
||||
cmd[0] = active_cable->bitbang_tms_in_port_cmd;
|
||||
cmd[1] = MPSSE_TMS_SHIFT;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0;
|
||||
swdptap_turnaround(1);
|
||||
while (index--) {
|
||||
libftdi_buffer_write(cmd, 4);
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
if (do_mpsse) {
|
||||
uint8_t cmd[3] = {MPSSE_TDO_SHIFT, 0, (val)? 1:0};
|
||||
libftdi_buffer_write(cmd, sizeof(cmd));
|
||||
} else {
|
||||
uint8_t cmd[3];
|
||||
cmd[0] = MPSSE_TMS_SHIFT;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = (val)? 1 : 0;
|
||||
libftdi_buffer_write(cmd, sizeof(cmd));
|
||||
}
|
||||
uint8_t data[33];
|
||||
unsigned int ret = 0;
|
||||
libftdi_buffer_read(data, ticks + 1);
|
||||
if (data[ticks] & active_cable->bitbang_tms_in_pin)
|
||||
parity ^= 1;
|
||||
while (ticks--) {
|
||||
if (data[ticks] & active_cable->bitbang_tms_in_pin) {
|
||||
}
|
||||
|
||||
bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
{
|
||||
assert(ticks == 32);
|
||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||
unsigned int parity = 0;
|
||||
unsigned int result = 0;
|
||||
if (do_mpsse) {
|
||||
uint8_t DO[5];
|
||||
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks + 1);
|
||||
result = DO[0] + (DO[1] << 8) + (DO[2] << 16) + (DO[3] << 24);
|
||||
parity = __builtin_parity(result & ((1LL << ticks) - 1)) & 1;
|
||||
parity ^= DO[4] & 1;
|
||||
} else {
|
||||
int index = ticks + 1;
|
||||
uint8_t cmd[4];
|
||||
|
||||
cmd[0] = active_cable->bb_swdio_in_port_cmd;
|
||||
cmd[1] = MPSSE_TMS_SHIFT;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0;
|
||||
while (index--) {
|
||||
libftdi_buffer_write(cmd, sizeof(cmd));
|
||||
}
|
||||
uint8_t data[33];
|
||||
libftdi_buffer_read(data, ticks + 1);
|
||||
if (data[ticks] & active_cable->bb_swdio_in_pin)
|
||||
parity ^= 1;
|
||||
ret |= (1 << ticks);
|
||||
index = ticks;
|
||||
while (index--) {
|
||||
if (data[index] & active_cable->bb_swdio_in_pin) {
|
||||
parity ^= 1;
|
||||
result |= (1 << index);
|
||||
}
|
||||
}
|
||||
}
|
||||
*res = ret;
|
||||
*res = result;
|
||||
return parity;
|
||||
}
|
||||
|
||||
static uint32_t swdptap_seq_in(int ticks)
|
||||
{
|
||||
int index = ticks;
|
||||
uint8_t cmd[4];
|
||||
if (!ticks)
|
||||
return 0;
|
||||
uint32_t result = 0;
|
||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||
if (do_mpsse) {
|
||||
uint8_t DO[4];
|
||||
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks);
|
||||
for (int i = 0; i < (ticks >> 3) + (ticks & 7)? 1: 0; i++) {
|
||||
result |= DO[i] << (8 * i);
|
||||
}
|
||||
} else {
|
||||
int index = ticks;
|
||||
uint8_t cmd[4];
|
||||
|
||||
cmd[0] = active_cable->bitbang_tms_in_port_cmd;
|
||||
cmd[1] = MPSSE_TMS_SHIFT;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0;
|
||||
cmd[0] = active_cable->bb_swdio_in_port_cmd;
|
||||
cmd[1] = MPSSE_TMS_SHIFT;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0;
|
||||
|
||||
swdptap_turnaround(1);
|
||||
while (index--) {
|
||||
libftdi_buffer_write(cmd, 4);
|
||||
while (index--) {
|
||||
libftdi_buffer_write(cmd, sizeof(cmd));
|
||||
}
|
||||
uint8_t data[32];
|
||||
libftdi_buffer_read(data, ticks);
|
||||
index = ticks;
|
||||
while (index--) {
|
||||
if (data[index] & active_cable->bb_swdio_in_pin)
|
||||
result |= (1 << index);
|
||||
}
|
||||
}
|
||||
uint8_t data[32];
|
||||
uint32_t ret = 0;
|
||||
libftdi_buffer_read(data, ticks);
|
||||
while (ticks--) {
|
||||
if (data[ticks] & active_cable->bitbang_tms_in_pin)
|
||||
ret |= (1 << ticks);
|
||||
}
|
||||
return ret;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t cmd[15];
|
||||
unsigned int index = 0;
|
||||
swdptap_turnaround(0);
|
||||
while (ticks) {
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
if (ticks >= 7) {
|
||||
cmd[index++] = 6;
|
||||
cmd[index++] = MS & 0x7f;
|
||||
MS >>= 7;
|
||||
ticks -= 7;
|
||||
} else {
|
||||
cmd[index++] = ticks - 1;
|
||||
cmd[index++] = MS & 0x7f;
|
||||
ticks = 0;
|
||||
if (!ticks)
|
||||
return;
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
if (do_mpsse) {
|
||||
uint8_t DI[4];
|
||||
DI[0] = (MS >> 0) & 0xff;
|
||||
DI[1] = (MS >> 8) & 0xff;
|
||||
DI[2] = (MS >> 16) & 0xff;
|
||||
DI[3] = (MS >> 24) & 0xff;
|
||||
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks);
|
||||
} else {
|
||||
uint8_t cmd[16];
|
||||
unsigned int index = 0;
|
||||
while (ticks) {
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
if (ticks >= 7) {
|
||||
cmd[index++] = 6;
|
||||
cmd[index++] = MS & 0x7f;
|
||||
MS >>= 7;
|
||||
ticks -= 7;
|
||||
} else {
|
||||
cmd[index++] = ticks - 1;
|
||||
cmd[index++] = MS & 0x7f;
|
||||
ticks = 0;
|
||||
}
|
||||
}
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t parity = 0;
|
||||
int steps = ticks;
|
||||
uint8_t cmd[18];
|
||||
int parity = __builtin_parity(MS & ((1LL << ticks) - 1)) & 1;
|
||||
unsigned int index = 0;
|
||||
uint32_t data = MS;
|
||||
swdptap_turnaround(0);
|
||||
while (steps) {
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
if (steps >= 7) {
|
||||
cmd[index++] = 6;
|
||||
cmd[index++] = data & 0x7f;
|
||||
data >>= 7;
|
||||
steps -= 7;
|
||||
} else {
|
||||
cmd[index++] = steps - 1;
|
||||
cmd[index++] = data & 0x7f;
|
||||
steps = 0;
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
if (do_mpsse) {
|
||||
uint8_t DI[8];
|
||||
DI[0] = (MS >> 0) & 0xff;
|
||||
DI[1] = (MS >> 8) & 0xff;
|
||||
DI[2] = (MS >> 16) & 0xff;
|
||||
DI[3] = (MS >> 24) & 0xff;
|
||||
DI[4] = parity;
|
||||
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks + 1);
|
||||
} else {
|
||||
uint8_t cmd[32];
|
||||
int steps = ticks;
|
||||
while (steps) {
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
if (steps >= 7) {
|
||||
cmd[index++] = 6;
|
||||
cmd[index++] = MS & 0x7f;
|
||||
MS >>= 7;
|
||||
steps -= 7;
|
||||
} else {
|
||||
cmd[index++] = steps - 1;
|
||||
cmd[index++] = MS & 0x7f;
|
||||
steps = 0;
|
||||
}
|
||||
}
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = parity;
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
while (ticks--) {
|
||||
parity ^= MS;
|
||||
MS >>= 1;
|
||||
}
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = parity;
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
|
@ -37,9 +37,6 @@
|
||||
#include "jlink.h"
|
||||
#include "cmsis_dap.h"
|
||||
|
||||
#define VENDOR_ID_BMP 0x1d50
|
||||
#define PRODUCT_ID_BMP 0x6018
|
||||
|
||||
#define VENDOR_ID_STLINK 0x0483
|
||||
#define PRODUCT_ID_STLINK_MASK 0xffe0
|
||||
#define PRODUCT_ID_STLINK_GROUP 0x3740
|
||||
@ -101,6 +98,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
||||
char product[128];
|
||||
bmp_type_t type = BMP_TYPE_NONE;
|
||||
bool access_problems = false;
|
||||
char *active_cable = NULL;
|
||||
bool ftdi_unknown = false;
|
||||
rescan:
|
||||
found_debuggers = 0;
|
||||
for (int i = 0; devs[i]; i++) {
|
||||
@ -165,6 +164,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
||||
if ((desc.idVendor == VENDOR_ID_BMP) &&
|
||||
(desc.idProduct == PRODUCT_ID_BMP)) {
|
||||
type = BMP_TYPE_BMP;
|
||||
} else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
|
||||
type = BMP_TYPE_CMSIS_DAP;
|
||||
} else if (desc.idVendor == VENDOR_ID_STLINK) {
|
||||
if ((desc.idProduct == PRODUCT_ID_STLINKV2) ||
|
||||
(desc.idProduct == PRODUCT_ID_STLINKV21) ||
|
||||
@ -177,16 +178,45 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
||||
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
|
||||
continue;
|
||||
}
|
||||
} else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
|
||||
type = BMP_TYPE_CMSIS_DAP;
|
||||
} else if (desc.idVendor == VENDOR_ID_SEGGER) {
|
||||
type = BMP_TYPE_JLINK;
|
||||
} else{
|
||||
continue;
|
||||
} else {
|
||||
cable_desc_t *cable = &cable_desc[0];
|
||||
for (; cable->name; cable++) {
|
||||
bool found = false;
|
||||
if ((cable->vendor != desc.idVendor) || (cable->product != desc.idProduct))
|
||||
continue; /* VID/PID do not match*/
|
||||
if (cl_opts->opt_cable) {
|
||||
if (strcmp(cable->name, cl_opts->opt_cable))
|
||||
continue; /* cable names do not match*/
|
||||
else
|
||||
found = true;
|
||||
}
|
||||
if (cable->description) {
|
||||
if (strcmp(cable->description, product))
|
||||
continue; /* discriptions do not match*/
|
||||
else
|
||||
found = true;
|
||||
} else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
|
||||
if ((cable->vendor == 0x0403) && /* FTDI*/
|
||||
((cable->product == 0x6010) || /* FT2232C/D/H*/
|
||||
(cable->product == 0x6011) || /* FT4232H Quad HS USB-UART/FIFO IC */
|
||||
(cable->product == 0x6014))) { /* FT232H Single HS USB-UART/FIFO IC */
|
||||
ftdi_unknown = true;
|
||||
continue; /* Cable name is needed */
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
active_cable = cable->name;
|
||||
type = BMP_TYPE_LIBFTDI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cable->name)
|
||||
continue;
|
||||
}
|
||||
found_debuggers ++;
|
||||
if (report) {
|
||||
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers,
|
||||
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
|
||||
serial,
|
||||
manufacturer,product);
|
||||
}
|
||||
@ -197,11 +227,19 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
||||
strncpy(info->product, product, sizeof(info->product));
|
||||
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
|
||||
if (cl_opts->opt_position &&
|
||||
(cl_opts->opt_position == found_debuggers)) {
|
||||
(cl_opts->opt_position == (found_debuggers + 1))) {
|
||||
found_debuggers = 1;
|
||||
break;
|
||||
} else {
|
||||
found_debuggers++;
|
||||
}
|
||||
}
|
||||
if ((found_debuggers == 0) && ftdi_unknown)
|
||||
DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c <cable>\" !\n");
|
||||
if ((found_debuggers == 1) && !cl_opts->opt_cable && (type == BMP_TYPE_LIBFTDI))
|
||||
cl_opts->opt_cable = active_cable;
|
||||
if (!found_debuggers && cl_opts->opt_list_only)
|
||||
DEBUG_WARN("No usable debugger found\n");
|
||||
if ((found_debuggers > 1) ||
|
||||
((found_debuggers == 1) && (cl_opts->opt_list_only))) {
|
||||
if (!report) {
|
||||
@ -242,12 +280,16 @@ void platform_init(int argc, char **argv)
|
||||
if (cl_opts.opt_device) {
|
||||
info.bmp_type = BMP_TYPE_BMP;
|
||||
} else if (cl_opts.opt_cable) {
|
||||
/* check for libftdi devices*/
|
||||
res = ftdi_bmp_init(&cl_opts, &info);
|
||||
if (res)
|
||||
exit(-1);
|
||||
else
|
||||
info.bmp_type = BMP_TYPE_LIBFTDI;
|
||||
if ((!strcmp(cl_opts.opt_cable, "list")) ||
|
||||
(!strcmp(cl_opts.opt_cable, "l"))) {
|
||||
cable_desc_t *cable = &cable_desc[0];
|
||||
DEBUG_WARN("Available cables:\n");
|
||||
for (; cable->name; cable++) {
|
||||
DEBUG_WARN("\t%s\n", cable->name);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
info.bmp_type = BMP_TYPE_LIBFTDI;
|
||||
} else if (find_debuggers(&cl_opts, &info)) {
|
||||
exit(-1);
|
||||
}
|
||||
@ -269,6 +311,8 @@ void platform_init(int argc, char **argv)
|
||||
exit(-1);
|
||||
break;
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
if (ftdi_bmp_init(&cl_opts, &info))
|
||||
exit(-1);
|
||||
break;
|
||||
case BMP_TYPE_JLINK:
|
||||
if (jlink_init(&info))
|
||||
@ -490,33 +534,51 @@ static void ap_decode_access(uint16_t addr, uint8_t RnW)
|
||||
fprintf(stderr, "Read ");
|
||||
else
|
||||
fprintf(stderr, "Write ");
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
if (RnW)
|
||||
fprintf(stderr, "DP_DPIDR :");
|
||||
else
|
||||
fprintf(stderr, "DP_ABORT :");
|
||||
break;
|
||||
case 0x004: fprintf(stderr, "CTRL/STAT:");
|
||||
break;
|
||||
case 0x008:
|
||||
if (RnW)
|
||||
fprintf(stderr, "RESEND :");
|
||||
else
|
||||
fprintf(stderr, "DP_SELECT:");
|
||||
break;
|
||||
case 0x00c: fprintf(stderr, "DP_RDBUFF:");
|
||||
break;
|
||||
case 0x100: fprintf(stderr, "AP_CSW :");
|
||||
break;
|
||||
case 0x104: fprintf(stderr, "AP_TAR :");
|
||||
break;
|
||||
case 0x10c: fprintf(stderr, "AP_DRW :");
|
||||
break;
|
||||
case 0x1f8: fprintf(stderr, "AP_BASE :");
|
||||
break;
|
||||
case 0x1fc: fprintf(stderr, "AP_IDR :");
|
||||
break;
|
||||
if (addr < 0x100) {
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
if (RnW)
|
||||
fprintf(stderr, "DP_DPIDR :");
|
||||
else
|
||||
fprintf(stderr, "DP_ABORT :");
|
||||
break;
|
||||
case 0x04: fprintf(stderr, "CTRL/STAT:");
|
||||
break;
|
||||
case 0x08:
|
||||
if (RnW)
|
||||
fprintf(stderr, "RESEND :");
|
||||
else
|
||||
fprintf(stderr, "DP_SELECT:");
|
||||
break;
|
||||
case 0x0c: fprintf(stderr, "DP_RDBUFF:");
|
||||
break;
|
||||
default: fprintf(stderr, "Unknown %02x :", addr);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "AP 0x%02x ", addr >> 8);
|
||||
switch (addr & 0xff) {
|
||||
case 0x00: fprintf(stderr, "CSW :");
|
||||
break;
|
||||
case 0x04: fprintf(stderr, "TAR :");
|
||||
break;
|
||||
case 0x0c: fprintf(stderr, "DRW :");
|
||||
break;
|
||||
case 0x10: fprintf(stderr, "DB0 :");
|
||||
break;
|
||||
case 0x14: fprintf(stderr, "DB1 :");
|
||||
break;
|
||||
case 0x18: fprintf(stderr, "DB2 :");
|
||||
break;
|
||||
case 0x1c: fprintf(stderr, "DB3 :");
|
||||
break;
|
||||
case 0xf8: fprintf(stderr, "BASE :");
|
||||
break;
|
||||
case 0xf4: fprintf(stderr, "CFG :");
|
||||
break;
|
||||
case 0xfc: fprintf(stderr, "IDR :");
|
||||
break;
|
||||
default: fprintf(stderr, "RSVD%02x:", addr & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,9 @@ void platform_buffer_flush(void);
|
||||
#define SET_IDLE_STATE(x)
|
||||
#define SET_RUN_STATE(x)
|
||||
|
||||
#define VENDOR_ID_BMP 0x1d50
|
||||
#define PRODUCT_ID_BMP 0x6018
|
||||
|
||||
typedef enum bmp_type_s {
|
||||
BMP_TYPE_NONE = 0,
|
||||
BMP_TYPE_BMP,
|
||||
|
@ -311,6 +311,7 @@ static int stlink_usb_error_check(uint8_t *data, bool verbose)
|
||||
case STLINK_SWD_AP_STICKY_ERROR:
|
||||
if (verbose)
|
||||
DEBUG_WARN("STLINK_SWD_AP_STICKY_ERROR\n");
|
||||
Stlink.ap_error = true;
|
||||
return STLINK_ERROR_FAIL;
|
||||
case STLINK_SWD_AP_STICKYORUN_ERROR:
|
||||
if (verbose)
|
||||
@ -686,11 +687,10 @@ static int stlink_enter_debug_jtag(bmp_info_t *info)
|
||||
|
||||
static uint32_t stlink_read_coreid(void)
|
||||
{
|
||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||
STLINK_DEBUG_READCOREID};
|
||||
uint8_t data[4];
|
||||
send_recv(info.usb_link, cmd, 16, data, 4);
|
||||
uint32_t id = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;
|
||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READ_IDCODES};
|
||||
uint8_t data[12];
|
||||
send_recv(info.usb_link, cmd, 16, data, 12);
|
||||
uint32_t id = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24;
|
||||
DEBUG_INFO("Read Core ID: 0x%08" PRIx32 "\n", id);
|
||||
return id;
|
||||
}
|
||||
@ -897,7 +897,8 @@ static void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
* Approach taken:
|
||||
* Fill the memory with some fixed pattern so hopefully
|
||||
* the caller notices the error*/
|
||||
DEBUG_WARN("stlink_readmem failed\n");
|
||||
DEBUG_WARN("stlink_readmem from %" PRIx32 " to %" PRIx32 ", len %"
|
||||
PRIx32 "failed\n", src, dest, (uint32_t) len);
|
||||
memset(dest, 0xff, len);
|
||||
}
|
||||
DEBUG_PROBE("stlink_readmem from %" PRIx32 " to %" PRIx32 ", len %" PRIx32
|
||||
@ -1027,10 +1028,6 @@ static uint32_t stlink_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1];
|
||||
int jtag_dev_count;
|
||||
jtag_proc_t jtag_proc;
|
||||
|
||||
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens)
|
||||
{
|
||||
uint32_t idcodes[JTAG_MAX_DEVS+1];
|
||||
@ -1094,7 +1091,7 @@ int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
||||
STLINK_DEBUG_ENTER_SWD_NO_RESET};
|
||||
uint8_t data[2];
|
||||
DEBUG_INFO("Enter SWD\n");
|
||||
send_recv(info->usb_link, cmd, 16, data, 2);
|
||||
stlink_send_recv_retry(cmd, 16, data, 2);
|
||||
if (stlink_usb_error_check(data, true))
|
||||
return -1;
|
||||
dp->idcode = stlink_read_coreid();
|
||||
|
@ -129,12 +129,15 @@ static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
|
||||
DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) "
|
||||
"serial number \"serial\"\n");
|
||||
DEBUG_WARN("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n");
|
||||
DEBUG_WARN("\t\t Use \"list\" to list available cables\n");
|
||||
DEBUG_WARN("Run mode related options:\n");
|
||||
DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n");
|
||||
DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n");
|
||||
DEBUG_WARN("\t-C\t\t: Connect under reset\n");
|
||||
DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n"
|
||||
"\t\t\t connected devices\n");
|
||||
DEBUG_WARN("\t-e\t\t: Assume \"resistor SWD connection\" on FTDI: TDI\n"
|
||||
"\t\t\t connected to TMS, TDO to TDI with eventual resistor\n");
|
||||
DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n");
|
||||
DEBUG_WARN("\t-V\t\t: Verify flash against binary file\n");
|
||||
DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n");
|
||||
@ -154,7 +157,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
||||
int c;
|
||||
opt->opt_target_dev = 1;
|
||||
opt->opt_flash_size = 16 * 1024 *1024;
|
||||
while((c = getopt(argc, argv, "Ehv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
|
||||
while((c = getopt(argc, argv, "eEhv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
if (optarg)
|
||||
@ -177,6 +180,9 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
||||
case 'C':
|
||||
opt->opt_connect_under_reset = true;
|
||||
break;
|
||||
case 'e':
|
||||
opt->external_resistor_swd = true;
|
||||
break;
|
||||
case 'd':
|
||||
if (optarg)
|
||||
opt->opt_device = optarg;
|
||||
|
@ -42,6 +42,7 @@ typedef struct BMP_CL_OPTIONS_s {
|
||||
bool opt_tpwr;
|
||||
bool opt_list_only;
|
||||
bool opt_connect_under_reset;
|
||||
bool external_resistor_swd;
|
||||
char *opt_flash_file;
|
||||
char *opt_device;
|
||||
char *opt_serial;
|
||||
|
1026
src/platforms/pc/hid.c
Executable file
1026
src/platforms/pc/hid.c
Executable file
File diff suppressed because it is too large
Load Diff
445
src/platforms/pc/hidapi.h
Normal file
445
src/platforms/pc/hidapi.h
Normal file
@ -0,0 +1,445 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
Alan Ott
|
||||
Signal 11 Software
|
||||
|
||||
8/22/2009
|
||||
|
||||
Copyright 2009, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
/** @file
|
||||
* @defgroup API hidapi API
|
||||
*/
|
||||
|
||||
#ifndef HIDAPI_H__
|
||||
#define HIDAPI_H__
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define HID_API_EXPORT __declspec(dllexport)
|
||||
#define HID_API_CALL
|
||||
#else
|
||||
#define HID_API_EXPORT /**< API export macro */
|
||||
#define HID_API_CALL /**< API call macro */
|
||||
#endif
|
||||
|
||||
#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
struct hid_device_;
|
||||
typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
|
||||
|
||||
/** hidapi info structure */
|
||||
struct hid_device_info {
|
||||
/** Platform-specific device path */
|
||||
char *path;
|
||||
/** Device Vendor ID */
|
||||
unsigned short vendor_id;
|
||||
/** Device Product ID */
|
||||
unsigned short product_id;
|
||||
/** Serial Number */
|
||||
wchar_t *serial_number;
|
||||
/** Device Release Number in binary-coded decimal,
|
||||
also known as Device Version Number */
|
||||
unsigned short release_number;
|
||||
/** Manufacturer String */
|
||||
wchar_t *manufacturer_string;
|
||||
/** Product string */
|
||||
wchar_t *product_string;
|
||||
/** Usage Page for this Device/Interface
|
||||
(Windows/Mac only). */
|
||||
unsigned short usage_page;
|
||||
/** Usage for this Device/Interface
|
||||
(Windows/Mac only).*/
|
||||
unsigned short usage;
|
||||
/** The USB interface which this logical device
|
||||
represents.
|
||||
|
||||
* Valid on both Linux implementations in all cases.
|
||||
* Valid on the Windows implementation only if the device
|
||||
contains more than one interface.
|
||||
* Valid on the Mac implementation if and only if the device
|
||||
is a USB HID device. */
|
||||
int interface_number;
|
||||
|
||||
/** Pointer to the next device */
|
||||
struct hid_device_info *next;
|
||||
};
|
||||
|
||||
|
||||
/** @brief Initialize the HIDAPI library.
|
||||
|
||||
This function initializes the HIDAPI library. Calling it is not
|
||||
strictly necessary, as it will be called automatically by
|
||||
hid_enumerate() and any of the hid_open_*() functions if it is
|
||||
needed. This function should be called at the beginning of
|
||||
execution however, if there is a chance of HIDAPI handles
|
||||
being opened by different threads simultaneously.
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_init(void);
|
||||
|
||||
/** @brief Finalize the HIDAPI library.
|
||||
|
||||
This function frees all of the static data associated with
|
||||
HIDAPI. It should be called at the end of execution to avoid
|
||||
memory leaks.
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_exit(void);
|
||||
|
||||
/** @brief Enumerate the HID Devices.
|
||||
|
||||
This function returns a linked list of all the HID devices
|
||||
attached to the system which match vendor_id and product_id.
|
||||
If @p vendor_id is set to 0 then any vendor matches.
|
||||
If @p product_id is set to 0 then any product matches.
|
||||
If @p vendor_id and @p product_id are both set to 0, then
|
||||
all HID devices will be returned.
|
||||
|
||||
@ingroup API
|
||||
@param vendor_id The Vendor ID (VID) of the types of device
|
||||
to open.
|
||||
@param product_id The Product ID (PID) of the types of
|
||||
device to open.
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a linked list of type
|
||||
struct #hid_device_info, containing information about the HID devices
|
||||
attached to the system, or NULL in the case of failure. Free
|
||||
this linked list by calling hid_free_enumeration().
|
||||
*/
|
||||
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
|
||||
|
||||
/** @brief Free an enumeration Linked List
|
||||
|
||||
This function frees a linked list created by hid_enumerate().
|
||||
|
||||
@ingroup API
|
||||
@param devs Pointer to a list of struct_device returned from
|
||||
hid_enumerate().
|
||||
*/
|
||||
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
|
||||
|
||||
/** @brief Open a HID device using a Vendor ID (VID), Product ID
|
||||
(PID) and optionally a serial number.
|
||||
|
||||
If @p serial_number is NULL, the first device with the
|
||||
specified VID and PID is opened.
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param vendor_id The Vendor ID (VID) of the device to open.
|
||||
@param product_id The Product ID (PID) of the device to open.
|
||||
@param serial_number The Serial Number of the device to open
|
||||
(Optionally NULL).
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a #hid_device object on
|
||||
success or NULL on failure.
|
||||
*/
|
||||
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
|
||||
|
||||
/** @brief Open a HID device by its path name.
|
||||
|
||||
The path name be determined by calling hid_enumerate(), or a
|
||||
platform-specific path name can be used (eg: /dev/hidraw0 on
|
||||
Linux).
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param path The path name of the device to open
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a #hid_device object on
|
||||
success or NULL on failure.
|
||||
*/
|
||||
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
|
||||
|
||||
/** @brief Write an Output report to a HID device.
|
||||
|
||||
The first byte of @p data[] must contain the Report ID. For
|
||||
devices which only support a single report, this must be set
|
||||
to 0x0. The remaining bytes contain the report data. Since
|
||||
the Report ID is mandatory, calls to hid_write() will always
|
||||
contain one more byte than the report contains. For example,
|
||||
if a hid report is 16 bytes long, 17 bytes must be passed to
|
||||
hid_write(), the Report ID (or 0x0, for devices with a
|
||||
single report), followed by the report data (16 bytes). In
|
||||
this example, the length passed in would be 17.
|
||||
|
||||
hid_write() will send the data on the first OUT endpoint, if
|
||||
one exists. If it does not, it will send the data through
|
||||
the Control Endpoint (Endpoint 0).
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data The data to send, including the report number as
|
||||
the first byte.
|
||||
@param length The length in bytes of the data to send.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes written and
|
||||
-1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Read an Input report from a HID device with timeout.
|
||||
|
||||
Input reports are returned
|
||||
to the host through the INTERRUPT IN endpoint. The first byte will
|
||||
contain the Report number if the device uses numbered reports.
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into.
|
||||
@param length The number of bytes to read. For devices with
|
||||
multiple reports, make sure to read an extra byte for
|
||||
the report number.
|
||||
@param milliseconds timeout in milliseconds or -1 for blocking wait.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes read and
|
||||
-1 on error. If no packet was available to be read within
|
||||
the timeout period, this function returns 0.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
|
||||
|
||||
/** @brief Read an Input report from a HID device.
|
||||
|
||||
Input reports are returned
|
||||
to the host through the INTERRUPT IN endpoint. The first byte will
|
||||
contain the Report number if the device uses numbered reports.
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into.
|
||||
@param length The number of bytes to read. For devices with
|
||||
multiple reports, make sure to read an extra byte for
|
||||
the report number.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes read and
|
||||
-1 on error. If no packet was available to be read and
|
||||
the handle is in non-blocking mode, this function returns 0.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Set the device handle to be non-blocking.
|
||||
|
||||
In non-blocking mode calls to hid_read() will return
|
||||
immediately with a value of 0 if there is no data to be
|
||||
read. In blocking mode, hid_read() will wait (block) until
|
||||
there is data to read before returning.
|
||||
|
||||
Nonblocking can be turned on and off at any time.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param nonblock enable or not the nonblocking reads
|
||||
- 1 to enable nonblocking
|
||||
- 0 to disable nonblocking.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
|
||||
|
||||
/** @brief Send a Feature report to the device.
|
||||
|
||||
Feature reports are sent over the Control endpoint as a
|
||||
Set_Report transfer. The first byte of @p data[] must
|
||||
contain the Report ID. For devices which only support a
|
||||
single report, this must be set to 0x0. The remaining bytes
|
||||
contain the report data. Since the Report ID is mandatory,
|
||||
calls to hid_send_feature_report() will always contain one
|
||||
more byte than the report contains. For example, if a hid
|
||||
report is 16 bytes long, 17 bytes must be passed to
|
||||
hid_send_feature_report(): the Report ID (or 0x0, for
|
||||
devices which do not use numbered reports), followed by the
|
||||
report data (16 bytes). In this example, the length passed
|
||||
in would be 17.
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data The data to send, including the report number as
|
||||
the first byte.
|
||||
@param length The length in bytes of the data to send, including
|
||||
the report number.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes written and
|
||||
-1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Get a feature report from a HID device.
|
||||
|
||||
Set the first byte of @p data[] to the Report ID of the
|
||||
report to be read. Make sure to allow space for this
|
||||
extra byte in @p data[]. Upon return, the first byte will
|
||||
still contain the Report ID, and the report data will
|
||||
start in data[1].
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into, including
|
||||
the Report ID. Set the first byte of @p data[] to the
|
||||
Report ID of the report to be read, or set it to zero
|
||||
if your device does not use numbered reports.
|
||||
@param length The number of bytes to read, including an
|
||||
extra byte for the report ID. The buffer can be longer
|
||||
than the actual report.
|
||||
|
||||
@returns
|
||||
This function returns the number of bytes read plus
|
||||
one for the report ID (which is still in the first
|
||||
byte), or -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Get a input report from a HID device.
|
||||
|
||||
Set the first byte of @p data[] to the Report ID of the
|
||||
report to be read. Make sure to allow space for this
|
||||
extra byte in @p data[]. Upon return, the first byte will
|
||||
still contain the Report ID, and the report data will
|
||||
start in data[1].
|
||||
|
||||
@ingroup API
|
||||
@param device A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into, including
|
||||
the Report ID. Set the first byte of @p data[] to the
|
||||
Report ID of the report to be read, or set it to zero
|
||||
if your device does not use numbered reports.
|
||||
@param length The number of bytes to read, including an
|
||||
extra byte for the report ID. The buffer can be longer
|
||||
than the actual report.
|
||||
|
||||
@returns
|
||||
This function returns the number of bytes read plus
|
||||
one for the report ID (which is still in the first
|
||||
byte), or -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Close a HID device.
|
||||
|
||||
This function sets the return value of hid_error().
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
*/
|
||||
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev);
|
||||
|
||||
/** @brief Get The Manufacturer String from a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get The Product String from a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get The Serial Number String from a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get a string from a HID device, based on its string index.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string_index The index of the string to get.
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get a string describing the last error which occurred.
|
||||
|
||||
Whether a function sets the last error is noted in its
|
||||
documentation. These functions will reset the last error
|
||||
to NULL before their execution.
|
||||
|
||||
Strings returned from hid_error() must not be freed by the user!
|
||||
|
||||
This function is thread-safe, and error messages are thread-local.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open(),
|
||||
or NULL to get the last non-device-specific error
|
||||
(e.g. for errors in hid_open() itself).
|
||||
|
||||
@returns
|
||||
This function returns a string containing the last error
|
||||
which occurred or NULL if none has occurred.
|
||||
*/
|
||||
HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -67,6 +67,33 @@ static int set_interface_attribs(void)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
|
||||
{
|
||||
char name[4096];
|
||||
if (!cl_opts->opt_device) {
|
||||
/* Try to find some BMP if0*/
|
||||
if (!serial) {
|
||||
DEBUG_WARN("No serial device found\n");
|
||||
return -1;
|
||||
} else {
|
||||
sprintf(name, "/dev/tty.usbmodem%s1", serial);
|
||||
}
|
||||
} else {
|
||||
strncpy(name, cl_opts->opt_device, sizeof(name) - 1);
|
||||
}
|
||||
fd = open(name, O_RDWR | O_SYNC | O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
DEBUG_WARN("Couldn't open serial port %s\n", name);
|
||||
return -1;
|
||||
}
|
||||
/* BMP only offers an USB-Serial connection with no real serial
|
||||
* line in between. No need for baudrate or parity.!
|
||||
*/
|
||||
return set_interface_attribs();
|
||||
}
|
||||
#else
|
||||
#define BMP_IDSTRING "usb-Black_Sphere_Technologies_Black_Magic_Probe"
|
||||
#define DEVICE_BY_ID "/dev/serial/by-id/"
|
||||
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
|
||||
@ -130,6 +157,7 @@ int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
|
||||
*/
|
||||
return set_interface_attribs();
|
||||
}
|
||||
#endif
|
||||
|
||||
void serial_close(void)
|
||||
{
|
||||
|
@ -23,22 +23,64 @@
|
||||
#include "remote.h"
|
||||
#include "cl_utils.h"
|
||||
|
||||
HANDLE hComm;
|
||||
static HANDLE hComm;
|
||||
|
||||
static char *find_bmp_by_serial(const char *serial)
|
||||
{
|
||||
char regpath[258];
|
||||
/* First find the containers of the BMP comports */
|
||||
sprintf(regpath,
|
||||
"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%04X&PID_%04X\\%s",
|
||||
VENDOR_ID_BMP, PRODUCT_ID_BMP, serial);
|
||||
HKEY hkeySection;
|
||||
LSTATUS res;
|
||||
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &hkeySection);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
BYTE prefix[128];
|
||||
DWORD maxlen = sizeof(prefix);
|
||||
res = RegQueryValueEx(hkeySection, "ParentIdPrefix", NULL, NULL, prefix,
|
||||
&maxlen);
|
||||
RegCloseKey(hkeySection);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
printf("prefix %s\n", prefix);
|
||||
sprintf(regpath,
|
||||
"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%04X&PID_%04X&MI_00\\%s"
|
||||
"&0000\\Device Parameters",
|
||||
VENDOR_ID_BMP, PRODUCT_ID_BMP, prefix);
|
||||
printf("%s\n", regpath);
|
||||
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &hkeySection);
|
||||
if (res != ERROR_SUCCESS) {
|
||||
printf("Failuere\n");
|
||||
return NULL;
|
||||
}
|
||||
BYTE port[128];
|
||||
maxlen = sizeof(port);
|
||||
res = RegQueryValueEx(hkeySection, "PortName", NULL, NULL, port, &maxlen);
|
||||
RegCloseKey(hkeySection);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
printf("Portname %s\n", port);
|
||||
return strdup((char*)port);
|
||||
}
|
||||
|
||||
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char * serial)
|
||||
{
|
||||
(void) serial; /* FIXME: Does Windows allow open with USB serial no? */
|
||||
char device[256];
|
||||
if (!cl_opts->opt_device)
|
||||
cl_opts->opt_device = find_bmp_by_serial(serial);
|
||||
if (!cl_opts->opt_device) {
|
||||
DEBUG_WARN("Specify the serial device to use!\n");
|
||||
DEBUG_WARN("Unexpected problems finding the device!\n");
|
||||
return -1;
|
||||
}
|
||||
char device[256];
|
||||
if (strstr(device, "\\\\.\\")) {
|
||||
strncpy(device, cl_opts->opt_device, sizeof(cl_opts->opt_device) - 1);
|
||||
if (strstr(cl_opts->opt_device, "\\\\.\\")) {
|
||||
strncpy(device, cl_opts->opt_device, sizeof(device) - 1);
|
||||
} else {
|
||||
strcpy(device, "\\\\.\\");
|
||||
strncat(device, cl_opts->opt_device,
|
||||
sizeof(cl_opts->opt_device) - strlen(cl_opts->opt_device) - 1);
|
||||
sizeof(device) - strlen(device) - 1);
|
||||
}
|
||||
hComm = CreateFile(device, //port name
|
||||
GENERIC_READ | GENERIC_WRITE, //Read/Write
|
||||
@ -59,6 +101,7 @@ int serial_open(BMP_CL_OPTIONS_t *cl_opts, char * serial)
|
||||
return -1;
|
||||
}
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
|
||||
if (!SetCommState(hComm, &dcbSerialParams)) {
|
||||
DEBUG_WARN("SetCommState failed %ld\n", GetLastError());
|
||||
return -1;
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include <libopencm3/usb/usbd.h>
|
||||
#include <libopencm3/stm32/adc.h>
|
||||
|
||||
uint8_t running_status;
|
||||
|
||||
uint16_t led_idle_run;
|
||||
uint16_t srst_pin;
|
||||
static uint32_t rev;
|
||||
|
@ -309,6 +309,9 @@ void remotePacketProcessHL(uint8_t i, char *packet)
|
||||
remote_ap.apsel = remotehston(2, packet);
|
||||
remote_ap.dp = &remote_dp;
|
||||
switch (index) {
|
||||
case REMOTE_HL_CHECK:
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
break;
|
||||
case REMOTE_DP_READ:
|
||||
packet += 2;
|
||||
uint16_t addr16 = remotehston(4, packet);
|
||||
|
@ -84,6 +84,7 @@
|
||||
#define REMOTE_RESP_NOTSUP 'N'
|
||||
|
||||
/* High level protocol elements */
|
||||
#define REMOTE_HL_CHECK 'C'
|
||||
#define REMOTE_HL_PACKET 'H'
|
||||
#define REMOTE_DP_READ 'd'
|
||||
#define REMOTE_LOW_ACCESS 'L'
|
||||
@ -142,6 +143,7 @@
|
||||
#define HEX_U32(x) '%', '0', '8', 'x'
|
||||
#define CHR(x) '%', 'c'
|
||||
|
||||
#define REMOTE_HL_CHECK_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_HL_CHECK, REMOTE_EOM, 0 }
|
||||
#define REMOTE_MEM_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_MEM_READ, \
|
||||
HEX_U32(address), HEX_U32(count), REMOTE_EOM, 0 }
|
||||
#define REMOTE_DP_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_DP_READ, \
|
||||
|
@ -106,6 +106,13 @@ static const char * const cidc_debug_strings[] =
|
||||
#define PIDR_PN_MASK 0x000000FFFULL /* Part number bits. */
|
||||
#define PIDR_ARM_BITS 0x4000BB000ULL /* These make up the ARM JEP-106 code. */
|
||||
|
||||
#define DEVTYPE_OFFSET 0xFCC /* CoreSight Device Type Register */
|
||||
#define DEVARCH_OFFSET 0xFBC /* CoreSight Device Architecture Register */
|
||||
|
||||
#define DEVTYPE_MASK 0x000000FF
|
||||
#define DEVARCH_PRESENT (1u << 20)
|
||||
#define DEVARCH_ARCHID_MASK 0x0000FFFF
|
||||
|
||||
enum arm_arch {
|
||||
aa_nosupport,
|
||||
aa_cortexm,
|
||||
@ -152,9 +159,20 @@ enum arm_arch {
|
||||
*
|
||||
* We left out some of the Part numbers included in OpenOCD, we only include
|
||||
* the ones that have ARM as the designer.
|
||||
*
|
||||
* To properly identify ADIv6 CoreSight components, two additional fields,
|
||||
* DEVTYPE and ARCHID are read.
|
||||
* The dev_type and arch_id values in the table below were found in the
|
||||
* corresponding logic in pyOCD:
|
||||
* https://github.com/mbedmicro/pyOCD/blob/master/pyocd/coresight/component_ids.py
|
||||
*
|
||||
* Additional reference on the DEVTYPE and DEVARCH registers can be found in the
|
||||
* ARM CoreSight Architecture Specification v3.0, sections B2.3.4 and B2.3.8.
|
||||
*/
|
||||
static const struct {
|
||||
uint16_t part_number;
|
||||
uint8_t dev_type;
|
||||
uint16_t arch_id;
|
||||
enum arm_arch arch;
|
||||
enum cid_class cidc;
|
||||
#ifdef ENABLE_DEBUG
|
||||
@ -162,59 +180,73 @@ static const struct {
|
||||
const char *full;
|
||||
#endif
|
||||
} pidr_pn_bits[] = {
|
||||
{0x000, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M3 SCS", "(System Control Space)")},
|
||||
{0x001, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ITM", "(Instrumentation Trace Module)")},
|
||||
{0x002, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 DWT", "(Data Watchpoint and Trace)")},
|
||||
{0x003, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 FBP", "(Flash Patch and Breakpoint)")},
|
||||
{0x008, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M0 SCS", "(System Control Space)")},
|
||||
{0x00a, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 DWT", "(Data Watchpoint and Trace)")},
|
||||
{0x00b, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 BPU", "(Breakpoint Unit)")},
|
||||
{0x00c, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M4 SCS", "(System Control Space)")},
|
||||
{0x00d, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
|
||||
{0x00e, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 FBP", "(Flash Patch and Breakpoint)")},
|
||||
{0x101, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("System TSGEN", "(Time Stamp Generator)")},
|
||||
{0x490, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 GIC", "(Generic Interrupt Controller)")},
|
||||
{0x4c7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 PPB", "(Private Peripheral Bus ROM Table)")},
|
||||
{0x906, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CTI", "(Cross Trigger)")},
|
||||
{0x907, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETB", "(Trace Buffer)")},
|
||||
{0x908, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CSTF", "(Trace Funnel)")},
|
||||
{0x910, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM9", "(Embedded Trace)")},
|
||||
{0x912, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x913, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ITM", "(Instrumentation Trace Macrocell)")},
|
||||
{0x914, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight SWO", "(Single Wire Output)")},
|
||||
{0x917, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight HTM", "(AHB Trace Macrocell)")},
|
||||
{0x920, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
|
||||
{0x921, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 ETM", "(Embedded Trace)")},
|
||||
{0x922, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 CTI", "(Cross Trigger)")},
|
||||
{0x923, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x924, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ETM", "(Embedded Trace)")},
|
||||
{0x925, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 ETM", "(Embedded Trace)")},
|
||||
{0x930, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 ETM", "(Embedded Trace)")},
|
||||
{0x932, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight MTB-M0+", "(Simple Execution Trace)")},
|
||||
{0x941, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU-Lite", "(Trace Port Interface Unit)")},
|
||||
{0x950, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A9 component)")},
|
||||
{0x955, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A5 component)")},
|
||||
{0x956, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 ETM", "(Embedded Trace)")},
|
||||
{0x95f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PTM", "(Program Trace Macrocell)")},
|
||||
{0x961, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TMC", "(Trace Memory Controller)")},
|
||||
{0x962, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
|
||||
{0x963, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
|
||||
{0x975, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 ETM", "(Embedded Trace)")},
|
||||
{0x9a0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight PMU", "(Performance Monitoring Unit)")},
|
||||
{0x9a1, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x9a9, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x9a5, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A5 ETM", "(Embedded Trace)")},
|
||||
{0x9a7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 PMU", "(Performance Monitor Unit)")},
|
||||
{0x9af, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PMU", "(Performance Monitor Unit)")},
|
||||
{0xc05, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A5 Debug", "(Debug Unit)")},
|
||||
{0xc07, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A7 Debug", "(Debug Unit)")},
|
||||
{0xc08, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A8 Debug", "(Debug Unit)")},
|
||||
{0xc09, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A9 Debug", "(Debug Unit)")},
|
||||
{0xc0f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 Debug", "(Debug Unit)")}, /* support? */
|
||||
{0xc14, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 Debug", "(Debug Unit)")}, /* support? */
|
||||
{0xcd0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Atmel DSU", "(Device Service Unit)")},
|
||||
{0xd21, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M33", "()")}, /* support? */
|
||||
{0xfff, aa_end, cidc_unknown, PIDR_PN_BIT_STRINGS("end", "end")}
|
||||
{0x000, 0x00, 0, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M3 SCS", "(System Control Space)")},
|
||||
{0x001, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ITM", "(Instrumentation Trace Module)")},
|
||||
{0x002, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 DWT", "(Data Watchpoint and Trace)")},
|
||||
{0x003, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 FBP", "(Flash Patch and Breakpoint)")},
|
||||
{0x008, 0x00, 0, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M0 SCS", "(System Control Space)")},
|
||||
{0x00a, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 DWT", "(Data Watchpoint and Trace)")},
|
||||
{0x00b, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 BPU", "(Breakpoint Unit)")},
|
||||
{0x00c, 0x00, 0, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M4 SCS", "(System Control Space)")},
|
||||
{0x00d, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
|
||||
{0x00e, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 FBP", "(Flash Patch and Breakpoint)")},
|
||||
{0x101, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("System TSGEN", "(Time Stamp Generator)")},
|
||||
{0x490, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 GIC", "(Generic Interrupt Controller)")},
|
||||
{0x4c7, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 PPB", "(Private Peripheral Bus ROM Table)")},
|
||||
{0x906, 0x14, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CTI", "(Cross Trigger)")},
|
||||
{0x907, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETB", "(Trace Buffer)")},
|
||||
{0x908, 0x12, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CSTF", "(Trace Funnel)")},
|
||||
{0x910, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM9", "(Embedded Trace)")},
|
||||
{0x912, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x913, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ITM", "(Instrumentation Trace Macrocell)")},
|
||||
{0x914, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight SWO", "(Single Wire Output)")},
|
||||
{0x917, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight HTM", "(AHB Trace Macrocell)")},
|
||||
{0x920, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
|
||||
{0x921, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 ETM", "(Embedded Trace)")},
|
||||
{0x922, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 CTI", "(Cross Trigger)")},
|
||||
{0x923, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x924, 0x13, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ETM", "(Embedded Trace)")},
|
||||
{0x925, 0x13, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 ETM", "(Embedded Trace)")},
|
||||
{0x930, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 ETM", "(Embedded Trace)")},
|
||||
{0x932, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight MTB-M0+", "(Simple Execution Trace)")},
|
||||
{0x941, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU-Lite", "(Trace Port Interface Unit)")},
|
||||
{0x950, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A9 component)")},
|
||||
{0x955, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A5 component)")},
|
||||
{0x956, 0x13, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 ETM", "(Embedded Trace)")},
|
||||
{0x95f, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PTM", "(Program Trace Macrocell)")},
|
||||
{0x961, 0x32, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TMC", "(Trace Memory Controller)")},
|
||||
{0x962, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
|
||||
{0x963, 0x63, 0x0a63, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
|
||||
{0x975, 0x13, 0x4a13, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 ETM", "(Embedded Trace)")},
|
||||
{0x9a0, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight PMU", "(Performance Monitoring Unit)")},
|
||||
{0x9a1, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x9a9, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 TPIU", "(Trace Port Interface Unit)")},
|
||||
{0x9a5, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A5 ETM", "(Embedded Trace)")},
|
||||
{0x9a7, 0x16, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 PMU", "(Performance Monitor Unit)")},
|
||||
{0x9af, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PMU", "(Performance Monitor Unit)")},
|
||||
{0xc05, 0x00, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A5 Debug", "(Debug Unit)")},
|
||||
{0xc07, 0x15, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A7 Debug", "(Debug Unit)")},
|
||||
{0xc08, 0x00, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A8 Debug", "(Debug Unit)")},
|
||||
{0xc09, 0x00, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A9 Debug", "(Debug Unit)")},
|
||||
{0xc0f, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 Debug", "(Debug Unit)")}, /* support? */
|
||||
{0xc14, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 Debug", "(Debug Unit)")}, /* support? */
|
||||
{0xcd0, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Atmel DSU", "(Device Service Unit)")},
|
||||
{0xd20, 0x00, 0x2a04, aa_cortexm, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(System Control Space)")},
|
||||
{0xd20, 0x11, 0, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Trace Port Interface Unit)")},
|
||||
{0xd20, 0x13, 0, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Embedded Trace)")},
|
||||
{0xd20, 0x31, 0x0a31, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Micro Trace Buffer)")},
|
||||
{0xd20, 0x00, 0x1a02, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Data Watchpoint and Trace)")},
|
||||
{0xd20, 0x00, 0x1a03, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Breakpoint Unit)")},
|
||||
{0xd20, 0x14, 0x1a14, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Cross Trigger)")},
|
||||
{0xd21, 0x00, 0x2a04, aa_cortexm, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(System Control Space)")},
|
||||
{0xd21, 0x31, 0x0a31, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Micro Trace Buffer)")},
|
||||
{0xd21, 0x43, 0x1a01, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Instrumentation Trace Macrocell)")},
|
||||
{0xd21, 0x00, 0x1a02, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Data Watchpoint and Trace)")},
|
||||
{0xd21, 0x00, 0x1a03, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Breakpoint Unit)")},
|
||||
{0xd21, 0x14, 0x1a14, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Cross Trigger)")},
|
||||
{0xd21, 0x13, 0x4a13, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Embedded Trace)")},
|
||||
{0xd21, 0x11, 0, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Trace Port Interface Unit)")},
|
||||
{0xfff, 0x00, 0, aa_end, cidc_unknown, PIDR_PN_BIT_STRINGS("end", "end")}
|
||||
};
|
||||
|
||||
extern bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base);
|
||||
@ -347,6 +379,19 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ADIv6: For CoreSight components, read DEVTYPE and ARCHID */
|
||||
uint16_t arch_id = 0;
|
||||
uint8_t dev_type = 0;
|
||||
if (cid_class == cidc_dc) {
|
||||
dev_type = adiv5_mem_read32(ap, addr + DEVTYPE_OFFSET) & DEVTYPE_MASK;
|
||||
|
||||
uint32_t devarch = adiv5_mem_read32(ap, addr + DEVARCH_OFFSET);
|
||||
|
||||
if (devarch & DEVARCH_PRESENT) {
|
||||
arch_id = devarch & DEVARCH_ARCHID_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract part number from the part id register. */
|
||||
uint16_t part_number = pidr & PIDR_PN_MASK;
|
||||
/* Find the part number in our part list and run the appropriate probe
|
||||
@ -354,13 +399,15 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; pidr_pn_bits[i].arch != aa_end; i++) {
|
||||
if (pidr_pn_bits[i].part_number == part_number) {
|
||||
if ((pidr_pn_bits[i].part_number == part_number)
|
||||
&& (pidr_pn_bits[i].dev_type == dev_type)
|
||||
&& (pidr_pn_bits[i].arch_id == arch_id)) {
|
||||
DEBUG_INFO("%s%d 0x%" PRIx32 ": %s - %s %s (PIDR = 0x%02" PRIx32
|
||||
"%08" PRIx32 ")",
|
||||
"%08" PRIx32 " DEVTYPE = 0x%02" PRIx8 " ARCHID = 0x%04" PRIx16 ")",
|
||||
indent + 1, num_entry, addr,
|
||||
cidc_debug_strings[cid_class],
|
||||
pidr_pn_bits[i].type, pidr_pn_bits[i].full,
|
||||
(uint32_t)(pidr >> 32), (uint32_t)pidr);
|
||||
(uint32_t)(pidr >> 32), (uint32_t)pidr, dev_type, arch_id);
|
||||
/* Perform sanity check, if we know what to expect as
|
||||
* component ID class.
|
||||
*/
|
||||
@ -390,9 +437,9 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
||||
}
|
||||
if (pidr_pn_bits[i].arch == aa_end) {
|
||||
DEBUG_WARN("%s0x%" PRIx32 ": %s - Unknown (PIDR = 0x%02" PRIx32
|
||||
"%08" PRIx32 ")\n",
|
||||
"%08" PRIx32 " DEVTYPE = 0x%02" PRIx8 " ARCHID = 0x%04" PRIx16 ")\n",
|
||||
indent, addr, cidc_debug_strings[cid_class],
|
||||
(uint32_t)(pidr >> 32), (uint32_t)pidr);
|
||||
(uint32_t)(pidr >> 32), (uint32_t)pidr, dev_type, arch_id);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
@ -45,11 +45,16 @@ int adiv5_swdp_scan(void)
|
||||
}
|
||||
|
||||
#if PC_HOSTED == 1
|
||||
if (platform_swdptap_init())
|
||||
if (platform_swdptap_init()) {
|
||||
free(dp);
|
||||
exit(-1);
|
||||
}
|
||||
#else
|
||||
if (swdptap_init())
|
||||
#endif
|
||||
if (swdptap_init()) {
|
||||
free(dp);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Switch from JTAG to SWD mode */
|
||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 16);
|
||||
@ -78,7 +83,8 @@ int adiv5_swdp_scan(void)
|
||||
|
||||
firmware_swdp_error(dp);
|
||||
adiv5_dp_init(dp);
|
||||
|
||||
if (!target_list)
|
||||
free(dp);
|
||||
return target_list?1:0;
|
||||
}
|
||||
|
||||
|
@ -269,16 +269,17 @@ static bool cortexm_forced_halt(target *t)
|
||||
platform_srst_set_val(false);
|
||||
uint32_t dhcsr = 0;
|
||||
uint32_t start_time = platform_time_ms();
|
||||
const uint32_t dhcsr_halted_bits = CORTEXM_DHCSR_S_HALT | CORTEXM_DHCSR_S_REGRDY |
|
||||
CORTEXM_DHCSR_C_HALT | CORTEXM_DHCSR_C_DEBUGEN;
|
||||
/* Try hard to halt the target. STM32F7 in WFI
|
||||
needs multiple writes!*/
|
||||
while (platform_time_ms() < start_time + cortexm_wait_timeout) {
|
||||
dhcsr = target_mem_read32(t, CORTEXM_DHCSR);
|
||||
if (dhcsr == (CORTEXM_DHCSR_S_HALT | CORTEXM_DHCSR_S_REGRDY |
|
||||
CORTEXM_DHCSR_C_HALT | CORTEXM_DHCSR_C_DEBUGEN))
|
||||
if ((dhcsr & dhcsr_halted_bits) == dhcsr_halted_bits)
|
||||
break;
|
||||
target_halt_request(t);
|
||||
}
|
||||
if (dhcsr != 0x00030003)
|
||||
if ((dhcsr & dhcsr_halted_bits) != dhcsr_halted_bits)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@ -293,7 +294,6 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
|
||||
}
|
||||
|
||||
adiv5_ap_ref(ap);
|
||||
uint32_t identity = ap->idr & 0xff;
|
||||
struct cortexm_priv *priv = calloc(1, sizeof(*priv));
|
||||
if (!priv) { /* calloc failed: heap exhaustion */
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
@ -309,18 +309,42 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
|
||||
t->mem_write = cortexm_mem_write;
|
||||
|
||||
t->driver = cortexm_driver_str;
|
||||
switch (identity) {
|
||||
case 0x11: /* M3/M4 */
|
||||
t->core = "M3/M4";
|
||||
|
||||
/* The CPUID register is defined in the ARMv7-M and ARMv8-M
|
||||
* architecture manuals. The PARTNO field is implementation defined,
|
||||
* that is, the actual values are found in the Technical Reference Manual
|
||||
* for each Cortex-M core.
|
||||
*/
|
||||
uint32_t cpuid = target_mem_read32(t, CORTEXM_CPUID);
|
||||
uint16_t partno = (cpuid >> 4) & 0xfff;
|
||||
|
||||
switch (partno) {
|
||||
case 0xd21:
|
||||
t->core = "M33";
|
||||
break;
|
||||
case 0x21: /* M0 */
|
||||
t->core = "M0";
|
||||
|
||||
case 0xd20:
|
||||
t->core = "M23";
|
||||
break;
|
||||
case 0x31: /* M0+ */
|
||||
|
||||
case 0xc23:
|
||||
t->core = "M3";
|
||||
break;
|
||||
|
||||
case 0xc24:
|
||||
t->core = "M4";
|
||||
break;
|
||||
|
||||
case 0xc27:
|
||||
t->core = "M7";
|
||||
break;
|
||||
|
||||
case 0xc60:
|
||||
t->core = "M0+";
|
||||
break;
|
||||
case 0x01: /* M7 */
|
||||
t->core = "M7";
|
||||
|
||||
case 0xc20:
|
||||
t->core = "M0";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ extern long cortexm_wait_timeout;
|
||||
|
||||
#define CORTEXM_SCS_BASE (CORTEXM_PPB_BASE + 0xE000)
|
||||
|
||||
#define CORTEXM_CPUID (CORTEXM_SCS_BASE + 0xD00)
|
||||
#define CORTEXM_AIRCR (CORTEXM_SCS_BASE + 0xD0C)
|
||||
#define CORTEXM_CFSR (CORTEXM_SCS_BASE + 0xD28)
|
||||
#define CORTEXM_HFSR (CORTEXM_SCS_BASE + 0xD2C)
|
||||
|
@ -29,7 +29,8 @@
|
||||
#define MIN_RAM_SIZE 1024
|
||||
#define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */
|
||||
|
||||
#define IAP_ENTRYPOINT 0x1fff1ff1
|
||||
#define IAP_ENTRY_MOST 0x1fff1ff1 /* all except LPC84x */
|
||||
#define IAP_ENTRY_84x 0x0f001ff1
|
||||
#define IAP_RAM_BASE 0x10000000
|
||||
|
||||
#define LPC11XX_DEVICE_ID 0x400483F4
|
||||
@ -55,13 +56,13 @@ const struct command_s lpc11xx_cmd_list[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize)
|
||||
void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize, uint32_t iap_entry)
|
||||
{
|
||||
struct lpc_flash *lf = lpc_add_flash(t, addr, len);
|
||||
lf->f.blocksize = erasesize;
|
||||
lf->f.buf_size = IAP_PGM_CHUNKSIZE;
|
||||
lf->f.write = lpc_flash_write_magic_vect;
|
||||
lf->iap_entry = IAP_ENTRYPOINT;
|
||||
lf->iap_entry = iap_entry;
|
||||
lf->iap_ram = IAP_RAM_BASE;
|
||||
lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES;
|
||||
}
|
||||
@ -108,7 +109,7 @@ lpc11xx_probe(target *t)
|
||||
case 0x2980002B: /* lpc11u24x/401 */
|
||||
t->driver = "LPC11xx";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST);
|
||||
target_add_commands(t, lpc11xx_cmd_list, "LPC11xx");
|
||||
return true;
|
||||
|
||||
@ -116,23 +117,23 @@ lpc11xx_probe(target *t)
|
||||
case 0x1A24902B:
|
||||
t->driver = "LPC1112";
|
||||
target_add_ram(t, 0x10000000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000, IAP_ENTRY_MOST);
|
||||
return true;
|
||||
case 0x1000002b: // FX LPC11U6 32 kB SRAM/256 kB flash (max)
|
||||
t->driver = "LPC11U6";
|
||||
target_add_ram(t, 0x10000000, 0x8000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x40000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x40000, 0x1000, IAP_ENTRY_MOST);
|
||||
return true;
|
||||
case 0x3000002B:
|
||||
case 0x3D00002B:
|
||||
t->driver = "LPC1343";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000, IAP_ENTRY_MOST);
|
||||
return true;
|
||||
case 0x00008A04: /* LPC8N04 (see UM11074 Rev.1.3 section 4.5.19) */
|
||||
t->driver = "LPC8N04";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
|
||||
target_add_commands(t, lpc11xx_cmd_list, "LPC8N04");
|
||||
return true;
|
||||
}
|
||||
@ -148,7 +149,7 @@ lpc11xx_probe(target *t)
|
||||
case 0x00008122: /* LPC812M101JDH20 / LPC812M101JTB16 */
|
||||
t->driver = "LPC81x";
|
||||
target_add_ram(t, 0x10000000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST);
|
||||
target_add_commands(t, lpc11xx_cmd_list, "LPC81x");
|
||||
return true;
|
||||
case 0x00008221: /* LPC822M101JHI33 */
|
||||
@ -157,7 +158,7 @@ lpc11xx_probe(target *t)
|
||||
case 0x00008242: /* LPC824M201JDH20 */
|
||||
t->driver = "LPC82x";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
|
||||
target_add_commands(t, lpc11xx_cmd_list, "LPC82x");
|
||||
return true;
|
||||
case 0x00008441:
|
||||
@ -166,7 +167,7 @@ lpc11xx_probe(target *t)
|
||||
case 0x00008444:
|
||||
t->driver = "LPC844";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x);
|
||||
return true;
|
||||
case 0x00008451:
|
||||
case 0x00008452:
|
||||
@ -174,7 +175,7 @@ lpc11xx_probe(target *t)
|
||||
case 0x00008454:
|
||||
t->driver = "LPC845";
|
||||
target_add_ram(t, 0x10000000, 0x4000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x);
|
||||
return true;
|
||||
case 0x0003D440: /* LPC11U34/311 */
|
||||
case 0x0001cc40: /* LPC11U34/421 */
|
||||
@ -186,13 +187,13 @@ lpc11xx_probe(target *t)
|
||||
case 0x00007C40: /* LPC11U37FBD64/501 */
|
||||
t->driver = "LPC11U3x";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST);
|
||||
return true;
|
||||
case 0x00040070: /* LPC1114/333 */
|
||||
case 0x00050080: /* lpc1115XL */
|
||||
t->driver = "LPC1100XL";
|
||||
target_add_ram(t, 0x10000000, 0x2000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
|
||||
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST);
|
||||
return true;
|
||||
}
|
||||
if (idcode) {
|
||||
|
@ -65,6 +65,9 @@ static int stm32f1_flash_write(struct target_flash *f,
|
||||
#define FLASH_OBR (FPEC_BASE+0x1C)
|
||||
#define FLASH_WRPR (FPEC_BASE+0x20)
|
||||
|
||||
#define FLASH_BANK2_OFFSET 0x40
|
||||
#define FLASH_BANK_SPLIT 0x08080000
|
||||
|
||||
#define FLASH_CR_OBL_LAUNCH (1<<13)
|
||||
#define FLASH_CR_OPTWRE (1 << 9)
|
||||
#define FLASH_CR_STRT (1 << 6)
|
||||
@ -124,7 +127,7 @@ bool stm32f1_probe(target *t)
|
||||
case 0x420: /* Value Line, Low-/Medium density */
|
||||
target_add_ram(t, 0x20000000, 0x5000);
|
||||
stm32f1_add_flash(t, 0x8000000, 0x20000, 0x400);
|
||||
target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD");
|
||||
target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD");
|
||||
/* Test for non-genuine parts with Core rev 2*/
|
||||
ADIv5_AP_t *ap = cortexm_ap(t);
|
||||
if ((ap->idr >> 28) > 1) {
|
||||
@ -139,11 +142,19 @@ bool stm32f1_probe(target *t)
|
||||
case 0x414: /* High density */
|
||||
case 0x418: /* Connectivity Line */
|
||||
case 0x428: /* Value Line, High Density */
|
||||
t->driver = "STM32F1 high density";
|
||||
t->driver = "STM32F1 VL density";
|
||||
target_add_ram(t, 0x20000000, 0x10000);
|
||||
stm32f1_add_flash(t, 0x8000000, 0x80000, 0x800);
|
||||
target_add_commands(t, stm32f1_cmd_list, "STM32 HD/CL");
|
||||
target_add_commands(t, stm32f1_cmd_list, "STM32 HF/CL/VL-HD");
|
||||
return true;
|
||||
case 0x430: /* XL-density */
|
||||
t->driver = "STM32F1 XL density";
|
||||
target_add_ram(t, 0x20000000, 0x18000);
|
||||
stm32f1_add_flash(t, 0x8000000, 0x80000, 0x800);
|
||||
stm32f1_add_flash(t, 0x8080000, 0x80000, 0x800);
|
||||
target_add_commands(t, stm32f1_cmd_list, "STM32 XL/VL-XL");
|
||||
return true;
|
||||
|
||||
case 0x438: /* STM32F303x6/8 and STM32F328 */
|
||||
case 0x422: /* STM32F30x */
|
||||
case 0x446: /* STM32F303xD/E and STM32F398xE */
|
||||
@ -192,29 +203,37 @@ bool stm32f1_probe(target *t)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void stm32f1_flash_unlock(target *t)
|
||||
static void stm32f1_flash_unlock(target *t, uint32_t bank_offset)
|
||||
{
|
||||
target_mem_write32(t, FLASH_KEYR, KEY1);
|
||||
target_mem_write32(t, FLASH_KEYR, KEY2);
|
||||
target_mem_write32(t, FLASH_KEYR + bank_offset, KEY1);
|
||||
target_mem_write32(t, FLASH_KEYR + bank_offset, KEY2);
|
||||
}
|
||||
|
||||
static int stm32f1_flash_erase(struct target_flash *f,
|
||||
target_addr addr, size_t len)
|
||||
{
|
||||
target *t = f->t;
|
||||
target_addr end = addr + len - 1;
|
||||
target_addr start = addr;
|
||||
|
||||
stm32f1_flash_unlock(t);
|
||||
|
||||
if ((t->idcode == 0x430) && (end >= FLASH_BANK_SPLIT))
|
||||
stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET);
|
||||
if (addr < FLASH_BANK_SPLIT)
|
||||
stm32f1_flash_unlock(t, 0);
|
||||
while(len) {
|
||||
uint32_t bank_offset = 0;
|
||||
if (addr >= FLASH_BANK_SPLIT)
|
||||
bank_offset = FLASH_BANK2_OFFSET;
|
||||
/* Flash page erase instruction */
|
||||
target_mem_write32(t, FLASH_CR, FLASH_CR_PER);
|
||||
target_mem_write32(t, FLASH_CR + bank_offset, FLASH_CR_PER);
|
||||
/* write address to FMA */
|
||||
target_mem_write32(t, FLASH_AR, addr);
|
||||
target_mem_write32(t, FLASH_AR + bank_offset, addr);
|
||||
/* Flash page erase start instruction */
|
||||
target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER);
|
||||
target_mem_write32(t, FLASH_CR + bank_offset,
|
||||
FLASH_CR_STRT | FLASH_CR_PER);
|
||||
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
|
||||
while (target_mem_read32(t, FLASH_SR + bank_offset) & FLASH_SR_BSY)
|
||||
if(target_check_error(t)) {
|
||||
DEBUG_WARN("stm32f1 flash erase: comm error\n");
|
||||
return -1;
|
||||
@ -227,12 +246,20 @@ static int stm32f1_flash_erase(struct target_flash *f,
|
||||
}
|
||||
|
||||
/* Check for error */
|
||||
uint32_t sr = target_mem_read32(t, FLASH_SR);
|
||||
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) {
|
||||
DEBUG_INFO("stm32f1 flash erase error 0x%" PRIx32 "\n", sr);
|
||||
return -1;
|
||||
if (start < FLASH_BANK_SPLIT) {
|
||||
uint32_t sr = target_mem_read32(t, FLASH_SR);
|
||||
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) {
|
||||
DEBUG_INFO("stm32f1 flash erase error 0x%" PRIx32 "\n", sr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ((t->idcode == 0x430) && (end >= FLASH_BANK_SPLIT)) {
|
||||
uint32_t sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
|
||||
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) {
|
||||
DEBUG_INFO("stm32f1 bank 2 flash erase error 0x%" PRIx32 "\n", sr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -241,21 +268,49 @@ static int stm32f1_flash_write(struct target_flash *f,
|
||||
{
|
||||
target *t = f->t;
|
||||
uint32_t sr;
|
||||
target_mem_write32(t, FLASH_CR, FLASH_CR_PG);
|
||||
cortexm_mem_write_sized(t, dest, src, len, ALIGN_HALFWORD);
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
/* Wait for completion or an error */
|
||||
do {
|
||||
sr = target_mem_read32(t, FLASH_SR);
|
||||
if(target_check_error(t)) {
|
||||
DEBUG_WARN("stm32f1 flash write: comm error\n");
|
||||
size_t length = 0;
|
||||
if (dest < FLASH_BANK_SPLIT) {
|
||||
if ((dest + len - 1) >= FLASH_BANK_SPLIT)
|
||||
length = FLASH_BANK_SPLIT - dest;
|
||||
else
|
||||
length = len;
|
||||
target_mem_write32(t, FLASH_CR, FLASH_CR_PG);
|
||||
cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
/* Wait for completion or an error */
|
||||
do {
|
||||
sr = target_mem_read32(t, FLASH_SR);
|
||||
if(target_check_error(t)) {
|
||||
DEBUG_WARN("stm32f1 flash write: comm error\n");
|
||||
return -1;
|
||||
}
|
||||
} while (sr & FLASH_SR_BSY);
|
||||
|
||||
if (sr & SR_ERROR_MASK) {
|
||||
DEBUG_WARN("stm32f1 flash write error 0x%" PRIx32 "\n", sr);
|
||||
return -1;
|
||||
}
|
||||
} while (sr & FLASH_SR_BSY);
|
||||
dest += length;
|
||||
src += length;
|
||||
}
|
||||
length = len - length;
|
||||
if ((t->idcode == 0x430) && length) { /* Write on bank 2 */
|
||||
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_PG);
|
||||
cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
/* Wait for completion or an error */
|
||||
do {
|
||||
sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
|
||||
if(target_check_error(t)) {
|
||||
DEBUG_WARN("stm32f1 flash bank2 write: comm error\n");
|
||||
return -1;
|
||||
}
|
||||
} while (sr & FLASH_SR_BSY);
|
||||
|
||||
if (sr & SR_ERROR_MASK) {
|
||||
DEBUG_WARN("stm32f1 flash write error 0x%" PRIx32 "\n", sr);
|
||||
return -1;
|
||||
if (sr & SR_ERROR_MASK) {
|
||||
DEBUG_WARN("stm32f1 flash bank2 write error 0x%" PRIx32 "\n", sr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -264,7 +319,7 @@ static bool stm32f1_cmd_erase_mass(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
stm32f1_flash_unlock(t);
|
||||
stm32f1_flash_unlock(t, 0);
|
||||
|
||||
/* Flash mass erase start instruction */
|
||||
target_mem_write32(t, FLASH_CR, FLASH_CR_MER);
|
||||
@ -279,7 +334,23 @@ static bool stm32f1_cmd_erase_mass(target *t, int argc, const char **argv)
|
||||
uint16_t sr = target_mem_read32(t, FLASH_SR);
|
||||
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
|
||||
return false;
|
||||
if (t->idcode == 0x430) {
|
||||
stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET);
|
||||
|
||||
/* Flash mass erase start instruction on bank 2*/
|
||||
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_MER);
|
||||
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET,
|
||||
FLASH_CR_STRT | FLASH_CR_MER);
|
||||
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
while (target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET) & FLASH_SR_BSY)
|
||||
if(target_check_error(t))
|
||||
return false;
|
||||
/* Check for error */
|
||||
uint16_t sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
|
||||
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -359,7 +430,7 @@ static bool stm32f1_cmd_option(target *t, int argc, const char **argv)
|
||||
default: flash_obp_rdp_key = FLASH_OBP_RDP_KEY;
|
||||
}
|
||||
rdprt = target_mem_read32(t, FLASH_OBR) & FLASH_OBR_RDPRT;
|
||||
stm32f1_flash_unlock(t);
|
||||
stm32f1_flash_unlock(t, 0);
|
||||
target_mem_write32(t, FLASH_OPTKEYR, KEY1);
|
||||
target_mem_write32(t, FLASH_OPTKEYR, KEY2);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user