libftdi/swdptap: Provide SWD using generic MPSSE if hardware allows.

This commit is contained in:
Uwe Bonnes 2018-06-01 13:53:27 +02:00 committed by UweBonnes
parent 40ba261982
commit 05534e9b49
4 changed files with 435 additions and 203 deletions

View File

@ -40,21 +40,39 @@ cable_desc_t *active_cable;
cable_desc_t cable_desc[] = { 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, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .dbus_data = PIN6 | MPSSE_CS | MPSSE_DO | MPSSE_DI,
.dbus_ddr = 0x1B, .dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS, .bitbang_tms_in_pin = MPSSE_CS,
.assert_srst.data_low = ~0x40, .assert_srst.data_low = ~PIN6,
.assert_srst.ddr_low = 0x40, .assert_srst.ddr_low = PIN6,
.deassert_srst.data_low = 0x40, .deassert_srst.data_low = PIN6,
.deassert_srst.ddr_low = ~0x40, .deassert_srst.ddr_low = ~PIN6,
.description = "FLOSS-JTAG", .description = "FLOSS-JTAG",
.name = "flossjtag" .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.*/
.vendor = 0x0403,
.product = 0x6014,/*FT232H*/
.interface = INTERFACE_A,
.dbus_data = MPSSE_DO | MPSSE_DI | MPSSE_CS,
.dbus_ddr = MPSSE_SK,
.swd_read.set_data_low = MPSSE_DO,
.swd_write.set_data_low = MPSSE_DO,
.name = "ft232h_resistor_swd"
},
{ {
/* Buffered connection from FTDI to Jtag/Swd. /* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable! * TCK and TMS not independant switchable!
@ -66,27 +84,27 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .dbus_data = PIN4 | MPSSE_CS | MPSSE_DI | MPSSE_DO,
.dbus_ddr = 0x1B, .dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.cbus_data = 0x1c, .cbus_data = PIN4 | PIN3 | PIN2,
.cbus_ddr = 0x1f, .cbus_ddr = PIN4 | PIN3 |PIN2 | PIN1 | PIN0,
.assert_srst.data_high = ~0x08, .assert_srst.data_high = ~PIN3,
.deassert_srst.data_high = 0x08, .deassert_srst.data_high = PIN3,
.srst_get_port_cmd = GET_BITS_LOW, .srst_get_port_cmd = GET_BITS_LOW,
.srst_get_pin = 0x40, .srst_get_pin = ~PIN6,
.description = "FTDIJTAG", .description = "FTDIJTAG",
.name = "ftdijtag" .name = "ftdijtag"
}, },
{ {
/* UART/SWO on Interface A /* UART/SWO on Interface A
* JTAG and control on INTERFACE_B * JTAG and control on INTERFACE_B
* Bit 5 high selects SWD-READ (TMS routed to TDO) * Bit 5 high selects SWD-WRITE (TMS routed to TDO)
* Bit 6 high selects JTAG vs SWD (TMS routed to TDI/TDO) * Bit 6 high selects JTAG vs SWD (TMS routed to TDI/TDO)
* BCBUS 1 (Output) N_SRST * BCBUS 1 (Output) N_SRST
* BCBUS 2 (Input) V_ISO available * BCBUS 2 (Input) V_ISO available
* *
* For bitbanged SWD, set Bit 5 low and select SWD read with * 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 * TDO is routed to Interface 0 RXD as SWO or with Uart
* Connector pin 10 pulled to ground will connect Interface 0 RXD * Connector pin 10 pulled to ground will connect Interface 0 RXD
@ -95,17 +113,19 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_B, .interface = INTERFACE_B,
.dbus_data = 0x6A, .dbus_data = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_DI,
.dbus_ddr = 0x6B, .dbus_ddr = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_SK,
.cbus_data = 0x02, .cbus_data = PIN1 | PIN2,
.cbus_ddr = 0x02,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TDO, /* keep bit 5 low*/ .bitbang_tms_in_pin = MPSSE_DI, /* keep bit 5 low*/
.bitbang_swd_dbus_read_data = 0x02, .bitbang_swd_dbus_read_data = MPSSE_DO,
.assert_srst.data_high = ~PIN1, .assert_srst.data_high = ~PIN1,
.assert_srst.ddr_high = PIN1, .assert_srst.ddr_high = PIN1,
.deassert_srst.data_high = PIN1, .deassert_srst.data_high = PIN1,
.deassert_srst.ddr_high = ~PIN1, .deassert_srst.ddr_high = ~PIN1,
.swd_read.clr_data_low = PIN5 | PIN6,
.swd_write.set_data_low = PIN5,
.swd_write.clr_data_low = PIN6,
.name = "ftdiswd" .name = "ftdiswd"
}, },
{ {
@ -152,7 +172,7 @@ cable_desc_t cable_desc[] = {
.dbus_data = 0xA8, .dbus_data = 0xA8,
.dbus_ddr = 0xAB, .dbus_ddr = 0xAB,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS, .bitbang_tms_in_pin = MPSSE_CS,
.name = "ftdi" .name = "ftdi"
}, },
{ {
@ -174,7 +194,7 @@ cable_desc_t cable_desc[] = {
.dbus_data = 0x08, .dbus_data = 0x08,
.dbus_ddr = 0x0B, .dbus_ddr = 0x0B,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS, .bitbang_tms_in_pin = MPSSE_CS,
.name = "ft232h" .name = "ft232h"
}, },
{ {
@ -185,7 +205,7 @@ cable_desc_t cable_desc[] = {
.dbus_data = 0x08, .dbus_data = 0x08,
.dbus_ddr = 0x0B, .dbus_ddr = 0x0B,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS, .bitbang_tms_in_pin = MPSSE_CS,
.name = "ft4232h" .name = "ft4232h"
}, },
{ {
@ -380,6 +400,73 @@ int libftdi_buffer_read(uint8_t *data, int size)
return size; 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[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) 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) const char *libftdi_target_voltage(void)
{ {
return "not supported"; return "not supported";

View File

@ -32,16 +32,40 @@ typedef struct data_desc_s {
int16_t ddr_high; int16_t ddr_high;
}data_desc_t; }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 { typedef struct cable_desc_s {
int vendor; int vendor;
int product; int product;
int interface; int interface;
/* Needed level on DBUS output pins to drive the JTAG signals and for
* other functionality like SRST, TRST. etc.*/
uint8_t dbus_data; uint8_t dbus_data;
/* Write '1' for DBUS pins needed as output in JTAG mode and for
* other functionality like SRST, TRST. etc..*/
uint8_t dbus_ddr; uint8_t dbus_ddr;
/* Needed level on CBUS output pins to drive the JTAG signals and for
* other functionality like SRST, TRST. etc.
* Often not needed at all.*/
uint8_t cbus_data; uint8_t cbus_data;
/* Write '1' for CBUS pins needed as output in JTAG mode and for
* other functionality like SRST, TRST. etc.
* Often not needed at all.*/
uint8_t cbus_ddr; uint8_t cbus_ddr;
/* MPSSE command to read TMS/SWDIO Port in bitbanging SWD.
* In many cases this is the TMS port of the FTDI and
* so "GET_BITS_LOW" */
uint8_t bitbang_tms_in_port_cmd; uint8_t bitbang_tms_in_port_cmd;
/* Pin mask where TMS/SWDIO can be read in bitbanging SWD.
* In many cases this is the TMS port of the FTDI
* and so "MPSSE_TMS".*/
uint8_t bitbang_tms_in_pin; uint8_t bitbang_tms_in_pin;
/* Dbus data to allow bitbanging SWD read.*/
uint8_t bitbang_swd_dbus_read_data; uint8_t bitbang_swd_dbus_read_data;
uint8_t bitbang_swd_direct; uint8_t bitbang_swd_direct;
/* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST. /* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST.
@ -57,7 +81,23 @@ typedef struct cable_desc_s {
/* PIN to read back as SRST. if 0 port from assert_srst is ised. /* 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*/ * Use PINX if active high, use Complement (~PINX) if active low*/
uint8_t srst_get_pin; uint8_t srst_get_pin;
/* dbus 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 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 swd_read;
/* dbus data for pure MPSSE SWD write.*/
pin_settings_t swd_write;
/* USB readable description of the device.*/
char *description; char *description;
/* Command line argument to -c option to select this device.*/
char * name; char * name;
}cable_desc_t; }cable_desc_t;
@ -72,14 +112,16 @@ void libftdi_buffer_flush(void);
int libftdi_buffer_write(const uint8_t *data, int size); int libftdi_buffer_write(const uint8_t *data, int size);
int libftdi_buffer_read(uint8_t *data, int size); int libftdi_buffer_read(uint8_t *data, int size);
const char *libftdi_target_voltage(void); 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);
#define MPSSE_TCK 1 #define MPSSE_SK 1
#define PIN0 1 #define PIN0 1
#define MPSSE_TDI 2 #define MPSSE_DO 2
#define PIN1 2 #define PIN1 2
#define MPSSE_TDO 4 #define MPSSE_DI 4
#define PIN2 4 #define PIN2 4
#define MPSSE_TMS 8 #define MPSSE_CS 8
#define PIN3 8 #define PIN3 8
#define PIN4 0x10 #define PIN4 0x10
#define PIN5 0x20 #define PIN5 0x20

View File

@ -38,14 +38,17 @@ extern struct ftdi_context *ftdic;
static void jtagtap_reset(void); static void jtagtap_reset(void);
static void jtagtap_tms_seq(uint32_t MS, int ticks); 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( static void jtagtap_tdi_seq(
const uint8_t final_tms, const uint8_t *DI, int ticks); const uint8_t final_tms, const uint8_t *DI, int ticks);
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI); static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) int libftdi_jtagtap_init(jtag_proc_t *jtag_proc)
{ {
if ((active_cable->swd_read.set_data_low == MPSSE_DO) &&
(active_cable->swd_write.set_data_low == MPSSE_DO)) {
printf("Jtag not possible with resistor SWD!\n");
return -1;
}
assert(ftdic != NULL); assert(ftdic != NULL);
/* select new buffer flush function if libftdi 1.5 */ /* select new buffer flush function if libftdi 1.5 */
#ifdef _Ftdi_Pragma #ifdef _Ftdi_Pragma
@ -84,7 +87,7 @@ int libftdi_jtagtap_init(jtag_proc_t *jtag_proc)
jtag_proc->jtagtap_reset = jtagtap_reset; jtag_proc->jtagtap_reset = jtagtap_reset;
jtag_proc->jtagtap_next =jtagtap_next; jtag_proc->jtagtap_next =jtagtap_next;
jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq; 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; jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
return 0; return 0;
@ -108,75 +111,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(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( static void jtagtap_tdi_seq(
const uint8_t final_tms, const uint8_t *DI, int ticks) 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) static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)

View File

@ -28,12 +28,76 @@
#include "general.h" #include "general.h"
#include "ftdi_bmp.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) static enum swdio_status olddir;
#define MPSSE_TD_MASK (MPSSE_TDI | MPSSE_TDO) static bool do_mpsse;
#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 |\ #define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
MPSSE_BITMODE | MPSSE_WRITE_NEG) 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;
if (do_mpsse) {
if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ {
active_cable->dbus_data |= active_cable->swd_read.set_data_low;
active_cable->dbus_data &= ~active_cable->swd_read.clr_data_low;
active_cable->cbus_data |= active_cable->swd_read.set_data_high;
active_cable->cbus_data &= ~active_cable->swd_read.clr_data_high;
uint8_t cmd_read[6] = {
SET_BITS_LOW, active_cable->dbus_data,
active_cable->dbus_ddr & ~MPSSE_DO,
SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr};
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_cable->dbus_data |= active_cable->swd_write.set_data_low;
active_cable->dbus_data &= ~active_cable->swd_write.clr_data_low;
active_cable->cbus_data |= active_cable->swd_write.set_data_high;
active_cable->cbus_data &= ~active_cable->swd_write.clr_data_high;
uint8_t cmd_write[6] = {
SET_BITS_LOW, active_cable->dbus_data,
active_cable->dbus_ddr | MPSSE_DO,
SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr};
libftdi_buffer_write(cmd_write, 6);
}
} else {
uint8_t cmd[6];
int index = 0;
if(dir == SWDIO_STATUS_FLOAT) { /* 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;
}
/* One clock cycle */
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0;
cmd[index++] = 0;
if (dir == SWDIO_STATUS_DRIVE) {
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);
}
}
static bool swdptap_seq_in_parity(uint32_t *res, int ticks); static bool swdptap_seq_in_parity(uint32_t *res, int ticks);
static uint32_t swdptap_seq_in(int ticks); static uint32_t swdptap_seq_in(int ticks);
@ -46,6 +110,25 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
DEBUG_WARN("SWD not possible or missing item in cable description.\n"); DEBUG_WARN("SWD not possible or missing item in cable description.\n");
return -1; return -1;
} }
bool swd_read =
active_cable->swd_read.set_data_low ||
active_cable->swd_read.clr_data_low ||
active_cable->swd_read.set_data_high ||
active_cable->swd_read.clr_data_high;
bool swd_write =
active_cable->swd_write.set_data_low ||
active_cable->swd_write.clr_data_low ||
active_cable->swd_write.set_data_high ||
active_cable->swd_write.clr_data_high;
do_mpsse = swd_read && swd_write;
if (!do_mpsse) {
if (!(active_cable->bitbang_tms_in_port_cmd &&
active_cable->bitbang_tms_in_pin &&
active_cable->bitbang_swd_dbus_read_data)) {
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
return -1;
}
}
/* select new buffer flush function if libftdi 1.5 */ /* select new buffer flush function if libftdi 1.5 */
#ifdef _Ftdi_Pragma #ifdef _Ftdi_Pragma
int err = ftdi_tcioflush(ftdic); int err = ftdi_tcioflush(ftdic);
@ -73,11 +156,24 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
} }
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0, uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
SET_BITS_HIGH, 0,0}; SET_BITS_HIGH, 0,0};
if (do_mpsse) {
DEBUG_INFO("Using genuine MPSSE for SWD.\n");
ftdi_init[4]= active_cable->dbus_data;
active_cable->dbus_ddr &= ~MPSSE_CS; /* Do not touch SWDIO.*/
ftdi_init[5]= active_cable->dbus_ddr;
} else {
DEBUG_INFO("Using bitbang MPSSE for SWD.\n");
ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK; ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK;
ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK; ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK;
}
ftdi_init[7]= active_cable->cbus_data; ftdi_init[7]= active_cable->cbus_data;
ftdi_init[8]= active_cable->cbus_ddr; ftdi_init[8]= active_cable->cbus_ddr;
libftdi_buffer_write(ftdi_init, 9); libftdi_buffer_write(ftdi_init, sizeof(ftdi_init));
if (do_mpsse) {
olddir = SWDIO_STATUS_FLOAT;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
} else
olddir = SWDIO_STATUS_DRIVE;
libftdi_buffer_flush(); libftdi_buffer_flush();
swd_proc->swdptap_seq_in = swdptap_seq_in; swd_proc->swdptap_seq_in = swdptap_seq_in;
@ -88,66 +184,101 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
return 0; return 0;
} }
static void swdptap_turnaround(uint8_t dir) bool swdptap_bit_in(void)
{ {
if (dir == olddir) swdptap_turnaround(SWDIO_STATUS_FLOAT);
return; uint8_t cmd[4];
olddir = dir;
uint8_t cmd[6];
int index = 0; int index = 0;
bool result = false;
if(dir) { /* SWDIO goes to input */ if (do_mpsse) {
cmd[index++] = SET_BITS_LOW; uint8_t cmd[2] = {MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE, 0};
if (active_cable->bitbang_swd_dbus_read_data) libftdi_buffer_write(cmd, sizeof(cmd));
cmd[index] = active_cable->bitbang_swd_dbus_read_data; uint8_t data[1];
else libftdi_buffer_read(data, sizeof(data));
cmd[index] = active_cable->dbus_data; result = (data[0] & 0x80);
index++; } else {
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK; cmd[index++] = active_cable->bitbang_tms_in_port_cmd;
}
/* One clock cycle */
cmd[index++] = MPSSE_TMS_SHIFT; cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0; cmd[index++] = 0;
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); libftdi_buffer_write(cmd, index);
uint8_t data[1];
libftdi_buffer_read(data, sizeof(data));
result = (data[0] &= active_cable->bitbang_tms_in_pin);
}
return result;
} }
static bool swdptap_seq_in_parity(uint32_t *res, int ticks) void swdptap_bit_out(bool val)
{ {
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));
}
}
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);
for (int i = 0; i < 32; i++) {
parity ^= (result >> i) & 1;
}
parity ^= DO[4] & 1;
} else {
int index = ticks + 1; int index = ticks + 1;
uint8_t cmd[4]; uint8_t cmd[4];
unsigned int parity = 0;
cmd[0] = active_cable->bitbang_tms_in_port_cmd; cmd[0] = active_cable->bitbang_tms_in_port_cmd;
cmd[1] = MPSSE_TMS_SHIFT; cmd[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0; cmd[2] = 0;
cmd[3] = 0; cmd[3] = 0;
swdptap_turnaround(1);
while (index--) { while (index--) {
libftdi_buffer_write(cmd, 4); libftdi_buffer_write(cmd, sizeof(cmd));
} }
uint8_t data[33]; uint8_t data[33];
unsigned int ret = 0;
libftdi_buffer_read(data, ticks + 1); libftdi_buffer_read(data, ticks + 1);
if (data[ticks] & active_cable->bitbang_tms_in_pin) if (data[ticks] & active_cable->bitbang_tms_in_pin)
parity ^= 1; parity ^= 1;
while (ticks--) { index = ticks;
if (data[ticks] & active_cable->bitbang_tms_in_pin) { while (index--) {
if (data[index] & active_cable->bitbang_tms_in_pin) {
parity ^= 1; parity ^= 1;
ret |= (1 << ticks); result |= (1 << index);
} }
} }
*res = ret; }
*res = result;
return parity; return parity;
} }
static uint32_t swdptap_seq_in(int ticks) static uint32_t swdptap_seq_in(int ticks)
{ {
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; int index = ticks;
uint8_t cmd[4]; uint8_t cmd[4];
@ -156,25 +287,36 @@ static uint32_t swdptap_seq_in(int ticks)
cmd[2] = 0; cmd[2] = 0;
cmd[3] = 0; cmd[3] = 0;
swdptap_turnaround(1);
while (index--) { while (index--) {
libftdi_buffer_write(cmd, 4); libftdi_buffer_write(cmd, sizeof(cmd));
} }
uint8_t data[32]; uint8_t data[32];
uint32_t ret = 0;
libftdi_buffer_read(data, ticks); libftdi_buffer_read(data, ticks);
while (ticks--) { index = ticks;
if (data[ticks] & active_cable->bitbang_tms_in_pin) while (index--) {
ret |= (1 << ticks); if (data[index] & active_cable->bitbang_tms_in_pin)
result |= (1 << index);
} }
return ret; }
return result;
} }
static void swdptap_seq_out(uint32_t MS, int ticks) static void swdptap_seq_out(uint32_t MS, int ticks)
{ {
if (!ticks)
return;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
if (do_mpsse) {
uint8_t DI[4];
swdptap_turnaround(0);
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[15]; uint8_t cmd[15];
unsigned int index = 0; unsigned int index = 0;
swdptap_turnaround(0);
while (ticks) { while (ticks) {
cmd[index++] = MPSSE_TMS_SHIFT; cmd[index++] = MPSSE_TMS_SHIFT;
if (ticks >= 7) { if (ticks >= 7) {
@ -189,16 +331,30 @@ static void swdptap_seq_out(uint32_t MS, int ticks)
} }
} }
libftdi_buffer_write(cmd, index); libftdi_buffer_write(cmd, index);
}
} }
static void swdptap_seq_out_parity(uint32_t MS, int ticks) static void swdptap_seq_out_parity(uint32_t MS, int ticks)
{ {
uint8_t parity = 0; unsigned int parity = 0;
int steps = ticks;
uint8_t cmd[18]; uint8_t cmd[18];
unsigned int index = 0; unsigned int index = 0;
uint32_t data = MS;
swdptap_turnaround(0); swdptap_turnaround(0);
if (do_mpsse) {
uint8_t DI[5];
DI[0] = (MS >> 0) & 0xff;
DI[1] = (MS >> 8) & 0xff;
DI[2] = (MS >> 16) & 0xff;
DI[3] = (MS >> 24) & 0xff;
while(MS) {
parity ^= (MS & 1);
MS >>= 1;
}
DI[4] = parity;
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks + 1);
} else {
int steps = ticks;
unsigned int data = MS;
while (steps) { while (steps) {
cmd[index++] = MPSSE_TMS_SHIFT; cmd[index++] = MPSSE_TMS_SHIFT;
if (steps >= 7) { if (steps >= 7) {
@ -220,4 +376,13 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
cmd[index++] = 0; cmd[index++] = 0;
cmd[index++] = parity; cmd[index++] = parity;
libftdi_buffer_write(cmd, index); 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);
} }