libftdi: Reinitialize pins when switching JTAG/SWD.

This commit is contained in:
Uwe Bonnes 2019-09-05 15:46:04 +02:00 committed by UweBonnes
parent 05534e9b49
commit eabf45357d
4 changed files with 264 additions and 237 deletions

View File

@ -37,6 +37,7 @@ 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[] = {
{
@ -45,10 +46,9 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_A,
.dbus_data = PIN6 | MPSSE_CS | MPSSE_DO | MPSSE_DI,
.dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_CS,
.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,
@ -67,41 +67,40 @@ cable_desc_t cable_desc[] = {
.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,
.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.
* DBUS PIN6 : SRST readback.
* CBUS PIN1 : Drive SRST
* CBUS PIN4 : not tristate SRST
* 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 = PIN4 | MPSSE_CS | MPSSE_DI | MPSSE_DO,
.dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.cbus_data = PIN4 | PIN3 | PIN2,
.cbus_ddr = PIN4 | PIN3 |PIN2 | PIN1 | PIN0,
.assert_srst.data_high = ~PIN3,
.deassert_srst.data_high = PIN3,
.init.data_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,
.srst_get_pin = PIN6,
.description = "FTDIJTAG",
.name = "ftdijtag"
},
{
/* UART/SWO on Interface A
* JTAG and control on INTERFACE_B
* Bit 5 high selects SWD-WRITE (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 MPSSE_DI.
@ -113,42 +112,46 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_B,
.dbus_data = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_DI,
.dbus_ddr = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_SK,
.cbus_data = PIN1 | PIN2,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_DI, /* keep bit 5 low*/
.bitbang_swd_dbus_read_data = MPSSE_DO,
.assert_srst.data_high = ~PIN1,
.assert_srst.ddr_high = PIN1,
.deassert_srst.data_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,
.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,
.name = "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,
.assert_srst.data_low = 0x40,
.deassert_srst.data_low = ~0x40,
/* Drive low to activate JTAGOE and deassert TRST/RST.*/
.init.data_low = PIN6,
.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 = 0x01,
.srst_get_pin = PIN0,
.name = "turtelizer"
},
{
@ -160,8 +163,6 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.name = "jtaghs1"
},
{
@ -169,10 +170,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_CS,
.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"
},
{
@ -180,10 +181,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"
},
{
@ -191,10 +192,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_CS,
.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"
},
{
@ -202,24 +203,21 @@ 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_CS,
.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"
},
};
@ -239,6 +237,7 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
}
active_cable = &cable_desc[index];
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
DEBUG_WARN("Black Magic Probe for FTDI/MPSSE\n");
if(ftdic) {
@ -280,7 +279,42 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
err, ftdi_get_error_string(ftdic));
goto error_2;
}
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[9];
ftdi_init[0]= TCK_DIVISOR;
/* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
ftdi_init[1]= 1;
ftdi_init[2]= 0;
ftdi_init[3]= SET_BITS_LOW;
ftdi_init[4]= active_state.data_low;
ftdi_init[5]= active_state.ddr_low;
ftdi_init[6]= SET_BITS_HIGH;
ftdi_init[7]= active_state.data_high;
ftdi_init[8]= active_state.ddr_high;
libftdi_buffer_write(ftdi_init, 9);
libftdi_buffer_flush();
return 0;
error_2:
ftdi_usb_close(ftdic);
error_1:
@ -294,29 +328,29 @@ static void libftdi_set_data(data_desc_t* data)
int index = 0;
if ((data->data_low) || (data->ddr_low)) {
if (data->data_low > 0)
active_cable->dbus_data |= (data->data_low & 0xff);
active_state.data_low |= (data->data_low & 0xff);
else
active_cable->dbus_data &= (data->data_low & 0xff);
active_state.data_low &= (data->data_low & 0xff);
if (data->ddr_low > 0)
active_cable->dbus_ddr |= (data->ddr_low & 0xff);
active_state.ddr_low |= (data->ddr_low & 0xff);
else
active_cable->dbus_ddr &= (data->ddr_low & 0xff);
active_state.ddr_low &= (data->ddr_low & 0xff);
cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_cable->dbus_data;
cmd[index++] = active_cable->dbus_ddr;
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_cable->cbus_data |= (data->data_high & 0xff);
active_state.data_high |= (data->data_high & 0xff);
else
active_cable->cbus_data &= (data->data_high & 0xff);
active_state.data_high &= (data->data_high & 0xff);
if (data->ddr_high > 0)
active_cable->cbus_ddr |= (data->ddr_high & 0xff);
active_state.ddr_high |= (data->ddr_high & 0xff);
else
active_cable->cbus_ddr &= (data->ddr_high & 0xff);
active_state.ddr_high &= (data->ddr_high & 0xff);
cmd[index++] = SET_BITS_HIGH;
cmd[index++] = active_cable->cbus_data;
cmd[index++] = active_cable->cbus_ddr;
cmd[index++] = active_state.data_high;
cmd[index++] = active_state.ddr_high;
}
if (index) {
libftdi_buffer_write(cmd, index);

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
@ -43,36 +44,26 @@ typedef struct cable_desc_s {
int vendor;
int product;
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;
/* Write '1' for DBUS pins needed as output in JTAG mode and for
* other functionality like SRST, TRST. etc..*/
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;
/* 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;
/* 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;
/* 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;
/* Dbus data to allow bitbanging SWD read.*/
uint8_t bitbang_swd_dbus_read_data;
uint8_t bitbang_swd_direct;
/* 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;
/* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to release 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;
@ -81,10 +72,10 @@ typedef struct cable_desc_s {
/* 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;
/* dbus data for pure MPSSE SWD read.
/* 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 swd_read|write and
* 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
@ -92,9 +83,11 @@ typedef struct cable_desc_s {
* 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;
pin_settings_t mpsse_swd_read;
/* dbus data for pure MPSSE SWD write.*/
pin_settings_t swd_write;
pin_settings_t mpsse_swd_write;
/* dbus data for jtag.*/
pin_settings_t jtag;
/* USB readable description of the device.*/
char *description;
/* Command line argument to -c option to select this device.*/
@ -103,6 +96,7 @@ typedef struct cable_desc_s {
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);

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>
@ -44,52 +42,37 @@ static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
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)) {
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;
}
assert(ftdic != NULL);
/* select new buffer flush function if libftdi 1.5 */
#ifdef _Ftdi_Pragma
int err = ftdi_tcioflush(ftdic);
#else
int err = ftdi_usb_purge_buffers(ftdic);
#endif
if (err != 0) {
DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
}
/* 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 = 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);
DEBUG_PROBE("%02x %02x %02x %02x\n", active_state.data_low ,
active_state.ddr_low, active_state.data_high,
active_state.ddr_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);
/* 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;
}
@ -128,7 +111,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

@ -35,6 +35,7 @@ enum swdio_status{
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)
@ -42,7 +43,6 @@ static bool do_mpsse;
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)
@ -50,50 +50,72 @@ static void swdptap_turnaround(enum swdio_status dir)
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;
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_cable->dbus_data,
active_cable->dbus_ddr & ~MPSSE_DO,
SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr};
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_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;
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_cable->dbus_data,
active_cable->dbus_ddr | MPSSE_DO,
SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr};
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[6];
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;
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;
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_cable->dbus_data | MPSSE_MASK;
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK;
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);
}
@ -106,75 +128,71 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks);
int libftdi_swdptap_init(swd_proc_t *swd_proc)
{
if (!active_cable->bitbang_tms_in_pin) {
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
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;
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->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;
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;
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;
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 == SET_BITS_LOW &&
active_cable->bb_swdio_in_pin == MPSSE_CS;
if (!bb_swd_read && !bb_swd_write) {
if (bb_direct_possible)
direct_bb_swd = true;
else {
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
return -1;
}
}
}
/* select new buffer flush function if libftdi 1.5 */
#ifdef _Ftdi_Pragma
int err = ftdi_tcioflush(ftdic);
#else
int err = ftdi_usb_purge_buffers(ftdic);
#endif
if (err != 0) {
DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
err, ftdi_get_error_string(ftdic));
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, 0x01, 0x00, SET_BITS_LOW, 0,0,
SET_BITS_HIGH, 0,0};
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");
ftdi_init[4]= active_cable->dbus_data;
active_cable->dbus_ddr &= ~MPSSE_CS; /* Do not touch SWDIO.*/
ftdi_init[5]= active_cable->dbus_ddr;
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 for SWD.\n");
} else {
DEBUG_INFO("Using bitbang MPSSE for SWD.\n");
ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK;
ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK;
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;
}
ftdi_init[7]= active_cable->cbus_data;
ftdi_init[8]= active_cable->cbus_ddr;
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;
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;
@ -198,14 +216,14 @@ bool swdptap_bit_in(void)
libftdi_buffer_read(data, sizeof(data));
result = (data[0] & 0x80);
} else {
cmd[index++] = active_cable->bitbang_tms_in_port_cmd;
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->bitbang_tms_in_pin);
result = (data[0] &= active_cable->bb_swdio_in_pin);
}
return result;
}
@ -243,7 +261,7 @@ bool swdptap_seq_in_parity(uint32_t *res, int ticks)
int index = ticks + 1;
uint8_t cmd[4];
cmd[0] = active_cable->bitbang_tms_in_port_cmd;
cmd[0] = active_cable->bb_swdio_in_port_cmd;
cmd[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0;
cmd[3] = 0;
@ -252,11 +270,11 @@ bool swdptap_seq_in_parity(uint32_t *res, int ticks)
}
uint8_t data[33];
libftdi_buffer_read(data, ticks + 1);
if (data[ticks] & active_cable->bitbang_tms_in_pin)
if (data[ticks] & active_cable->bb_swdio_in_pin)
parity ^= 1;
index = ticks;
while (index--) {
if (data[index] & active_cable->bitbang_tms_in_pin) {
if (data[index] & active_cable->bb_swdio_in_pin) {
parity ^= 1;
result |= (1 << index);
}
@ -282,7 +300,7 @@ static uint32_t swdptap_seq_in(int ticks)
int index = ticks;
uint8_t cmd[4];
cmd[0] = active_cable->bitbang_tms_in_port_cmd;
cmd[0] = active_cable->bb_swdio_in_port_cmd;
cmd[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0;
cmd[3] = 0;
@ -294,7 +312,7 @@ static uint32_t swdptap_seq_in(int ticks)
libftdi_buffer_read(data, ticks);
index = ticks;
while (index--) {
if (data[index] & active_cable->bitbang_tms_in_pin)
if (data[index] & active_cable->bb_swdio_in_pin)
result |= (1 << index);
}
}