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; static uint16_t bufptr = 0;
cable_desc_t *active_cable; cable_desc_t *active_cable;
data_desc_t active_state;
cable_desc_t cable_desc[] = { cable_desc_t cable_desc[] = {
{ {
@ -45,10 +46,9 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = PIN6 | MPSSE_CS | MPSSE_DO | MPSSE_DI, .init.data_low = PIN6, /* PULL nRST high*/
.dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK, .bb_swdio_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bb_swdio_in_pin = MPSSE_CS,
.bitbang_tms_in_pin = MPSSE_CS,
.assert_srst.data_low = ~PIN6, .assert_srst.data_low = ~PIN6,
.assert_srst.ddr_low = PIN6, .assert_srst.ddr_low = PIN6,
.deassert_srst.data_low = PIN6, .deassert_srst.data_low = PIN6,
@ -67,41 +67,40 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6014,/*FT232H*/ .product = 0x6014,/*FT232H*/
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = MPSSE_DO | MPSSE_DI | MPSSE_CS, .mpsse_swd_read.set_data_low = MPSSE_DO,
.dbus_ddr = MPSSE_SK, .mpsse_swd_write.set_data_low = MPSSE_DO,
.swd_read.set_data_low = MPSSE_DO,
.swd_write.set_data_low = MPSSE_DO,
.name = "ft232h_resistor_swd" .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!
* SWD not possible. * SWD not possible.
* DBUS PIN6 : SRST readback. * PIN4 low enables buffers
* CBUS PIN1 : Drive SRST * PIN5 Low indicates VRef applied
* CBUS PIN4 : not tristate SRST * PIN6 reads back SRST
* CBUS PIN1 Sets SRST
* CBUS PIN2 low drives SRST
*/ */
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = PIN4 | MPSSE_CS | MPSSE_DI | MPSSE_DO, .init.data_low = PIN4,
.dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK, .init.data_high = PIN4 | PIN3 | PIN2,
.cbus_data = PIN4 | PIN3 | PIN2, .init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
.cbus_ddr = PIN4 | PIN3 |PIN2 | PIN1 | PIN0, .assert_srst.data_high = ~PIN2,
.assert_srst.data_high = ~PIN3, .deassert_srst.data_high = PIN2,
.deassert_srst.data_high = PIN3,
.srst_get_port_cmd = GET_BITS_LOW, .srst_get_port_cmd = GET_BITS_LOW,
.srst_get_pin = ~PIN6, .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-WRITE (TMS routed to TDO) * Bit 5 high selects SWD-WRITE (TMS routed to MPSSE_DI)
* Bit 6 high selects JTAG vs SWD (TMS routed to TDI/TDO) * Bit 6 high selects JTAG vs SWD (TMS routed to MPSSE_CS)
* BCBUS 1 (Output) N_SRST * 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 * For bitbanged SWD, set Bit 5 low and select SWD read with
* Bit 6 low. Read Connector TMS as MPSSE_DI. * Bit 6 low. Read Connector TMS as MPSSE_DI.
@ -113,42 +112,46 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_B, .interface = INTERFACE_B,
.dbus_data = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_DI, .init.data_low = PIN6 | PIN5,
.dbus_ddr = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_SK, .init.ddr_low = PIN6 | PIN5,
.cbus_data = PIN1 | PIN2, .init.data_high = PIN1 | PIN2,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .assert_srst.data_high = ~PIN1,
.bitbang_tms_in_pin = MPSSE_DI, /* keep bit 5 low*/ .assert_srst.ddr_high = PIN1,
.bitbang_swd_dbus_read_data = MPSSE_DO, .deassert_srst.data_high = PIN1,
.assert_srst.data_high = ~PIN1, .deassert_srst.ddr_high = ~PIN1,
.assert_srst.ddr_high = PIN1, .mpsse_swd_read.clr_data_low = PIN5 | PIN6,
.deassert_srst.data_high = PIN1, .mpsse_swd_write.set_data_low = PIN5,
.deassert_srst.ddr_high = ~PIN1, .mpsse_swd_write.clr_data_low = PIN6,
.swd_read.clr_data_low = PIN5 | PIN6, .jtag.set_data_low = PIN6,
.swd_write.set_data_low = PIN5,
.swd_write.clr_data_low = PIN6,
.name = "ftdiswd" .name = "ftdiswd"
}, },
{ {
.vendor = 0x15b1, .vendor = 0x15b1,
.product = 0x0003, .product = 0x0003,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .init.ddr_low = PIN5,
.dbus_ddr = 0x1B,
.name = "olimex" .name = "olimex"
}, },
{ {
/* 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!
* => 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, .vendor = 0x0403,
.product = 0xbdc8, .product = 0xbdc8,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, /* Drive low to activate JTAGOE and deassert TRST/RST.*/
.dbus_ddr = 0x1B, .init.data_low = PIN6,
.assert_srst.data_low = 0x40, .init.ddr_low = PIN6 | PIN5 | PIN4,
.deassert_srst.data_low = ~0x40, .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_port_cmd = GET_BITS_HIGH,
.srst_get_pin = 0x01, .srst_get_pin = PIN0,
.name = "turtelizer" .name = "turtelizer"
}, },
{ {
@ -160,8 +163,6 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0xbdc8, .product = 0xbdc8,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.name = "jtaghs1" .name = "jtaghs1"
}, },
{ {
@ -169,10 +170,10 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0xbdc8, .product = 0xbdc8,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0xA8, .init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
.dbus_ddr = 0xAB, .init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bb_swdio_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_CS, .bb_swdio_in_pin = MPSSE_CS,
.name = "ftdi" .name = "ftdi"
}, },
{ {
@ -180,10 +181,10 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6014, .product = 0x6014,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x88, .init.data_low = PIN7,
.dbus_ddr = 0x8B, .init.ddr_low = PIN7,
.cbus_data = 0x20, .init.data_high = PIN5,
.cbus_ddr = 0x3f, .init.ddr_high = PIN5 | PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
.name = "digilent" .name = "digilent"
}, },
{ {
@ -191,10 +192,10 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6014, .product = 0x6014,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
.dbus_ddr = 0x0B, .init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.bitbang_tms_in_port_cmd = GET_BITS_LOW, .bb_swdio_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_CS, .bb_swdio_in_pin = MPSSE_CS,
.name = "ft232h" .name = "ft232h"
}, },
{ {
@ -202,24 +203,21 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6011, .product = 0x6011,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .bb_swdio_in_port_cmd = GET_BITS_LOW,
.dbus_ddr = 0x0B, .bb_swdio_in_pin = MPSSE_CS,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_CS,
.name = "ft4232h" .name = "ft4232h"
}, },
{ {
/* http://www.olimex.com/dev/pdf/ARM-USB-OCD.pdf. /* 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! * => TCK and TMS not independant switchable!
* => SWD not possible. */ * => SWD not possible. */
.vendor = 0x15ba, .vendor = 0x15ba,
.product = 0x002b, .product = 0x002b,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .init.ddr_low = PIN4,
.dbus_ddr = 0x1B, .init.data_high = PIN3 | PIN1 | PIN0,
.cbus_data = 0x00, .init.ddr_high = PIN4 | PIN3 | PIN1 | PIN0,
.cbus_ddr = 0x08,
.name = "arm-usb-ocd-h" .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]; active_cable = &cable_desc[index];
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
DEBUG_WARN("Black Magic Probe for FTDI/MPSSE\n"); DEBUG_WARN("Black Magic Probe for FTDI/MPSSE\n");
if(ftdic) { 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)); err, ftdi_get_error_string(ftdic));
goto error_2; 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; return 0;
error_2: error_2:
ftdi_usb_close(ftdic); ftdi_usb_close(ftdic);
error_1: error_1:
@ -294,29 +328,29 @@ static void libftdi_set_data(data_desc_t* data)
int index = 0; int index = 0;
if ((data->data_low) || (data->ddr_low)) { if ((data->data_low) || (data->ddr_low)) {
if (data->data_low > 0) if (data->data_low > 0)
active_cable->dbus_data |= (data->data_low & 0xff); active_state.data_low |= (data->data_low & 0xff);
else else
active_cable->dbus_data &= (data->data_low & 0xff); active_state.data_low &= (data->data_low & 0xff);
if (data->ddr_low > 0) if (data->ddr_low > 0)
active_cable->dbus_ddr |= (data->ddr_low & 0xff); active_state.ddr_low |= (data->ddr_low & 0xff);
else else
active_cable->dbus_ddr &= (data->ddr_low & 0xff); active_state.ddr_low &= (data->ddr_low & 0xff);
cmd[index++] = SET_BITS_LOW; cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_cable->dbus_data; cmd[index++] = active_state.data_low;
cmd[index++] = active_cable->dbus_ddr; cmd[index++] = active_state.ddr_low;
} }
if ((data->data_high) || (data->ddr_high)) { if ((data->data_high) || (data->ddr_high)) {
if (data->data_high > 0) if (data->data_high > 0)
active_cable->cbus_data |= (data->data_high & 0xff); active_state.data_high |= (data->data_high & 0xff);
else else
active_cable->cbus_data &= (data->data_high & 0xff); active_state.data_high &= (data->data_high & 0xff);
if (data->ddr_high > 0) if (data->ddr_high > 0)
active_cable->cbus_ddr |= (data->ddr_high & 0xff); active_state.ddr_high |= (data->ddr_high & 0xff);
else else
active_cable->cbus_ddr &= (data->ddr_high & 0xff); active_state.ddr_high &= (data->ddr_high & 0xff);
cmd[index++] = SET_BITS_HIGH; cmd[index++] = SET_BITS_HIGH;
cmd[index++] = active_cable->cbus_data; cmd[index++] = active_state.data_high;
cmd[index++] = active_cable->cbus_ddr; cmd[index++] = active_state.ddr_high;
} }
if (index) { if (index) {
libftdi_buffer_write(cmd, index); libftdi_buffer_write(cmd, index);

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2011 Black Sphere Technologies Ltd. * Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz> * 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 * 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 * 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 vendor;
int product; int product;
int interface; int interface;
/* Needed level on DBUS output pins to drive the JTAG signals and for /* Initial (C|D)(Bus|Ddr) values for additional pins.
* other functionality like SRST, TRST. etc.*/ * MPSSE_CS|DI|DO|SK are initialized accordig to mode.*/
uint8_t dbus_data; data_desc_t init;
/* Write '1' for DBUS pins needed as output in JTAG mode and for /* MPSSE command to read TMS/SWDIO in bitbanging SWD.
* other functionality like SRST, TRST. etc..*/ * In many cases this is the TMS port, so then use "GET_PIN_LOW".*/
uint8_t dbus_ddr; uint8_t bb_swdio_in_port_cmd;
/* Needed level on CBUS output pins to drive the JTAG signals and for /* bus bit to read TMS/SWDIO in bitbanging SWD.
* other functionality like SRST, TRST. etc. * In many cases this is the TMS port, so then use "MPSSE_CS".*/
* Often not needed at all.*/ uint8_t bb_swdio_in_pin;
uint8_t cbus_data; /* Bus data to allow bitbanging switched SWD read.
/* Write '1' for CBUS pins needed as output in JTAG mode and for * TMS is routed to bb_swdio_in_port/pin.*/
* other functionality like SRST, TRST. etc. pin_settings_t bb_swd_read;
* Often not needed at all.*/ /* Bus data to allow bitbanging switched SWD write.
uint8_t cbus_ddr; * TMS is routed to MPSSE_CS.*/
/* MPSSE command to read TMS/SWDIO Port in bitbanging SWD. pin_settings_t bb_swd_write;
* 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;
/* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST. /* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST.
* E.g. with CBUS Pin 1 low, * E.g. with CBUS Pin 1 low,
* give data_high = ~PIN1, ddr_high = PIN1 */ * give data_high = ~PIN1, ddr_high = PIN1 */
data_desc_t assert_srst; 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, * E.g. with CBUS Pin 1 floating with internal pull up,
* give data_high = PIN1, ddr_high = ~PIN1 */ * give data_high = PIN1, ddr_high = ~PIN1 */
data_desc_t deassert_srst; 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. /* 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. /* Bbus data for pure MPSSE SWD read.
* Use together with swd_write if by some bits on DBUS, * Use together with swd_write if by some bits on DBUS,
* SWDIO can be routed to TDI and TDO. * 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 * bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
* are provided, pure MPSSE SWD is choosen. * are provided, pure MPSSE SWD is choosen.
* If neither a complete set of swd_read|write or * 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. * are provided, SWD can not be done.
* swd_read.set_data_low == swd_write.set_data_low == MPSSE_DO * swd_read.set_data_low == swd_write.set_data_low == MPSSE_DO
* indicated resistor SWD and inhibits Jtag.*/ * indicated resistor SWD and inhibits Jtag.*/
pin_settings_t swd_read; pin_settings_t mpsse_swd_read;
/* dbus data for pure MPSSE SWD write.*/ /* 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.*/ /* USB readable description of the device.*/
char *description; char *description;
/* Command line argument to -c option to select this device.*/ /* 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 cable_desc_t *active_cable;
extern struct ftdi_context *ftdic; 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); 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. /* Low level JTAG implementation using FT2232 with libftdi.
* *
* Issues:
* Should share interface with swdptap.c or at least clean up...
*/ */
#include <stdio.h> #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) int libftdi_jtagtap_init(jtag_proc_t *jtag_proc)
{ {
if ((active_cable->swd_read.set_data_low == MPSSE_DO) && if ((active_cable->mpsse_swd_read.set_data_low == MPSSE_DO) &&
(active_cable->swd_write.set_data_low == MPSSE_DO)) { (active_cable->mpsse_swd_write.set_data_low == MPSSE_DO)) {
printf("Jtag not possible with resistor SWD!\n"); printf("Jtag not possible with resistor SWD!\n");
return -1; 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_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 = libftdi_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;
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; return 0;
} }
@ -128,7 +111,5 @@ static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
ret &= 0x80; ret &= 0x80;
// DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %02X\n", dTMS, dTDI, ret);
return ret; return ret;
} }

View File

@ -35,6 +35,7 @@ enum swdio_status{
static enum swdio_status olddir; static enum swdio_status olddir;
static bool do_mpsse; static bool do_mpsse;
static bool direct_bb_swd;
#define MPSSE_MASK (MPSSE_DO | MPSSE_DI | MPSSE_CS) #define MPSSE_MASK (MPSSE_DO | MPSSE_DI | MPSSE_CS)
#define MPSSE_TD_MASK (MPSSE_DO | MPSSE_DI) #define MPSSE_TD_MASK (MPSSE_DO | MPSSE_DI)
@ -42,7 +43,6 @@ static bool do_mpsse;
MPSSE_BITMODE | MPSSE_WRITE_NEG) MPSSE_BITMODE | MPSSE_WRITE_NEG)
#define MPSSE_TDO_SHIFT (MPSSE_DO_WRITE | MPSSE_LSB |\ #define MPSSE_TDO_SHIFT (MPSSE_DO_WRITE | MPSSE_LSB |\
MPSSE_BITMODE | MPSSE_WRITE_NEG) MPSSE_BITMODE | MPSSE_WRITE_NEG)
static void swdptap_turnaround(enum swdio_status dir) static void swdptap_turnaround(enum swdio_status dir)
{ {
if (dir == olddir) if (dir == olddir)
@ -50,50 +50,72 @@ static void swdptap_turnaround(enum swdio_status dir)
olddir = dir; olddir = dir;
if (do_mpsse) { if (do_mpsse) {
if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ { if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ {
active_cable->dbus_data |= active_cable->swd_read.set_data_low; active_state.data_low |= active_cable->mpsse_swd_read.set_data_low | MPSSE_DO;
active_cable->dbus_data &= ~active_cable->swd_read.clr_data_low; active_state.data_low &= ~active_cable->mpsse_swd_read.clr_data_low;
active_cable->cbus_data |= active_cable->swd_read.set_data_high; active_state.ddr_low &= ~MPSSE_DO;
active_cable->cbus_data &= ~active_cable->swd_read.clr_data_high; 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] = { uint8_t cmd_read[6] = {
SET_BITS_LOW, active_cable->dbus_data, SET_BITS_LOW, active_state.data_low,
active_cable->dbus_ddr & ~MPSSE_DO, active_state.ddr_low,
SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr}; SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
libftdi_buffer_write(cmd_read, 6); libftdi_buffer_write(cmd_read, 6);
} }
uint8_t cmd[] = {MPSSE_TDO_SHIFT, 0, 0}; /* One clock cycle */ uint8_t cmd[] = {MPSSE_TDO_SHIFT, 0, 0}; /* One clock cycle */
libftdi_buffer_write(cmd, sizeof(cmd)); libftdi_buffer_write(cmd, sizeof(cmd));
if (dir == SWDIO_STATUS_DRIVE) /* SWDIO goes to output */ { if (dir == SWDIO_STATUS_DRIVE) /* SWDIO goes to output */ {
active_cable->dbus_data |= active_cable->swd_write.set_data_low; active_state.data_low |= active_cable->mpsse_swd_write.set_data_low | MPSSE_DO;
active_cable->dbus_data &= ~active_cable->swd_write.clr_data_low; active_state.data_low &= ~active_cable->mpsse_swd_write.clr_data_low;
active_cable->cbus_data |= active_cable->swd_write.set_data_high; active_state.ddr_low |= MPSSE_DO;
active_cable->cbus_data &= ~active_cable->swd_write.clr_data_high; 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] = { uint8_t cmd_write[6] = {
SET_BITS_LOW, active_cable->dbus_data, SET_BITS_LOW, active_state.data_low,
active_cable->dbus_ddr | MPSSE_DO, active_state.ddr_low,
SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr}; SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
libftdi_buffer_write(cmd_write, 6); libftdi_buffer_write(cmd_write, 6);
} }
} else { } else {
uint8_t cmd[6]; uint8_t cmd[9];
int index = 0; int index = 0;
if(dir == SWDIO_STATUS_FLOAT) { /* SWDIO goes to input */ 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++] = SET_BITS_LOW;
if (active_cable->bitbang_swd_dbus_read_data) cmd[index++] = active_state.data_low;
cmd[index] = active_cable->bitbang_swd_dbus_read_data; cmd[index++] = active_state.ddr_low;
else cmd[index++] = SET_BITS_HIGH;
cmd[index] = active_cable->dbus_data; cmd[index++] = active_state.data_high;
index++; cmd[index++] = active_state.ddr_high;
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK;
} }
/* One clock cycle */ /* 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 == SWDIO_STATUS_DRIVE) { 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++] = SET_BITS_LOW;
cmd[index++] = active_cable->dbus_data | MPSSE_MASK; cmd[index++] = active_state.data_low;
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK; 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); 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) 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 = bool swd_read =
active_cable->swd_read.set_data_low || active_cable->mpsse_swd_read.set_data_low ||
active_cable->swd_read.clr_data_low || active_cable->mpsse_swd_read.clr_data_low ||
active_cable->swd_read.set_data_high || active_cable->mpsse_swd_read.set_data_high ||
active_cable->swd_read.clr_data_high; active_cable->mpsse_swd_read.clr_data_high;
bool swd_write = bool swd_write =
active_cable->swd_write.set_data_low || active_cable->mpsse_swd_write.set_data_low ||
active_cable->swd_write.clr_data_low || active_cable->mpsse_swd_write.clr_data_low ||
active_cable->swd_write.set_data_high || active_cable->mpsse_swd_write.set_data_high ||
active_cable->swd_write.clr_data_high; active_cable->mpsse_swd_write.clr_data_high;
do_mpsse = swd_read && swd_write; do_mpsse = swd_read && swd_write;
if (!do_mpsse) { if (!do_mpsse) {
if (!(active_cable->bitbang_tms_in_port_cmd && bool bb_swd_read =
active_cable->bitbang_tms_in_pin && active_cable->bb_swd_read.set_data_low ||
active_cable->bitbang_swd_dbus_read_data)) { active_cable->bb_swd_read.clr_data_low ||
DEBUG_WARN("SWD not possible or missing item in cable description.\n"); active_cable->bb_swd_read.set_data_high ||
return -1; 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 */ active_state.data_low |= MPSSE_CS | MPSSE_DI | MPSSE_DO;
#ifdef _Ftdi_Pragma active_state.data_low &= MPSSE_SK;
int err = ftdi_tcioflush(ftdic); active_state.ddr_low |= MPSSE_SK;
#else active_state.ddr_low &= ~(MPSSE_CS | MPSSE_DI | MPSSE_DO);
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};
if (do_mpsse) { if (do_mpsse) {
DEBUG_INFO("Using genuine MPSSE for SWD.\n"); DEBUG_INFO("Using genuine MPSSE for SWD.\n");
ftdi_init[4]= active_cable->dbus_data; active_state.data_low |= active_cable->mpsse_swd_read.set_data_low;
active_cable->dbus_ddr &= ~MPSSE_CS; /* Do not touch SWDIO.*/ active_state.data_low &= ~(active_cable->mpsse_swd_read.clr_data_low);
ftdi_init[5]= active_cable->dbus_ddr; 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 { } else {
DEBUG_INFO("Using bitbang MPSSE for SWD.\n"); DEBUG_INFO("Using switched bitbang for SWD.\n");
ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK; active_state.data_low |= active_cable->bb_swd_read.set_data_low;
ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK; 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; uint8_t cmd_write[6] = {
ftdi_init[8]= active_cable->cbus_ddr; SET_BITS_LOW, active_state.data_low,
libftdi_buffer_write(ftdi_init, sizeof(ftdi_init)); active_state.ddr_low,
if (do_mpsse) { SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
olddir = SWDIO_STATUS_FLOAT; libftdi_buffer_write(cmd_write, 6);
swdptap_turnaround(SWDIO_STATUS_DRIVE);
} else
olddir = SWDIO_STATUS_DRIVE;
libftdi_buffer_flush(); libftdi_buffer_flush();
olddir = SWDIO_STATUS_FLOAT;
swd_proc->swdptap_seq_in = swdptap_seq_in; swd_proc->swdptap_seq_in = swdptap_seq_in;
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity; 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)); libftdi_buffer_read(data, sizeof(data));
result = (data[0] & 0x80); result = (data[0] & 0x80);
} else { } 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++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0; cmd[index++] = 0;
cmd[index++] = 0; cmd[index++] = 0;
libftdi_buffer_write(cmd, index); libftdi_buffer_write(cmd, index);
uint8_t data[1]; uint8_t data[1];
libftdi_buffer_read(data, sizeof(data)); 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; return result;
} }
@ -243,7 +261,7 @@ bool swdptap_seq_in_parity(uint32_t *res, int ticks)
int index = ticks + 1; int index = ticks + 1;
uint8_t cmd[4]; 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[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0; cmd[2] = 0;
cmd[3] = 0; cmd[3] = 0;
@ -252,11 +270,11 @@ bool swdptap_seq_in_parity(uint32_t *res, int ticks)
} }
uint8_t data[33]; uint8_t data[33];
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->bb_swdio_in_pin)
parity ^= 1; parity ^= 1;
index = ticks; index = ticks;
while (index--) { while (index--) {
if (data[index] & active_cable->bitbang_tms_in_pin) { if (data[index] & active_cable->bb_swdio_in_pin) {
parity ^= 1; parity ^= 1;
result |= (1 << index); result |= (1 << index);
} }
@ -282,7 +300,7 @@ static uint32_t swdptap_seq_in(int ticks)
int index = ticks; int index = ticks;
uint8_t cmd[4]; 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[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0; cmd[2] = 0;
cmd[3] = 0; cmd[3] = 0;
@ -294,7 +312,7 @@ static uint32_t swdptap_seq_in(int ticks)
libftdi_buffer_read(data, ticks); libftdi_buffer_read(data, ticks);
index = ticks; index = ticks;
while (index--) { while (index--) {
if (data[index] & active_cable->bitbang_tms_in_pin) if (data[index] & active_cable->bb_swdio_in_pin)
result |= (1 << index); result |= (1 << index);
} }
} }