Merge commit '8289862b55e2a0dc658c3c7e2f6ab9878d0527fa' into sam-update

# Conflicts:
#	README.md
#	src/platforms/common/cdcacm.c
This commit is contained in:
Jason Kotzin 2022-08-10 17:40:24 -07:00
commit 93cf62d944
36 changed files with 3001 additions and 596 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

445
src/platforms/pc/hidapi.h Normal file
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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