Merge pull request #347 from UweBonnes/ftdi
libftdi platform improvements
This commit is contained in:
commit
80f003ff4b
|
@ -21,8 +21,6 @@
|
|||
/* Low level JTAG implementation using FT2232 with libftdi.
|
||||
*
|
||||
* Issues:
|
||||
* This code is old, rotten and unsupported.
|
||||
* Magic numbers everywhere.
|
||||
* Should share interface with swdptap.c or at least clean up...
|
||||
*/
|
||||
|
||||
|
@ -35,23 +33,39 @@
|
|||
#include <ftdi.h>
|
||||
|
||||
#include "general.h"
|
||||
|
||||
#define PROVIDE_GENERIC_TAP_SEQ
|
||||
//#define PROVIDE_GENERIC_TAP_TMS_SEQ
|
||||
//#define PROVIDE_GENERIC_TAP_TDI_TDO_SEQ
|
||||
//#define PROVIDE_GENERIC_TAP_TDI_SEQ
|
||||
#include "jtagtap.h"
|
||||
|
||||
#define ALL_ZERO 0xA0
|
||||
#define TCK 0x01
|
||||
#define TDI 0x02
|
||||
#define TDO 0x04
|
||||
#define TMS 0x08
|
||||
#define nSRST 0x20
|
||||
|
||||
int jtagtap_init(void)
|
||||
{
|
||||
assert(ftdic != NULL);
|
||||
int err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "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) {
|
||||
fprintf(stderr, "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) {
|
||||
fprintf(stderr, "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;
|
||||
platform_buffer_write(ftdi_init, 9);
|
||||
platform_buffer_flush();
|
||||
|
||||
/* Go to JTAG mode for SWJ-DP */
|
||||
for (int i = 0; i <= 50; i++)
|
||||
|
@ -67,133 +81,94 @@ void jtagtap_reset(void)
|
|||
jtagtap_soft_reset();
|
||||
}
|
||||
|
||||
#ifndef PROVIDE_GENERIC_TAP_TMS_SEQ
|
||||
void
|
||||
jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t tmp[3] = "\x4B";
|
||||
uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0};
|
||||
while(ticks >= 0) {
|
||||
//jtagtap_next(MS & 1, 1);
|
||||
tmp[1] = ticks<7?ticks-1:6;
|
||||
tmp[2] = 0x80 | (MS & 0x7F);
|
||||
|
||||
// assert(ftdi_write_data(ftdic, tmp, 3) == 3);
|
||||
platform_buffer_write(tmp, 3);
|
||||
MS >>= 7; ticks -= 7;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PROVIDE_GENERIC_TAP_TDI_SEQ
|
||||
void
|
||||
jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t *tmp;
|
||||
int index = 0;
|
||||
int rticks;
|
||||
|
||||
if(!ticks) return;
|
||||
|
||||
if(final_tms) ticks--;
|
||||
rticks = ticks & 7;
|
||||
ticks >>= 3;
|
||||
tmp = alloca(ticks + 9);
|
||||
|
||||
if(ticks) {
|
||||
tmp[index++] = 0x19;
|
||||
tmp[index++] = ticks - 1;
|
||||
tmp[index++] = 0;
|
||||
while(ticks--) tmp[index++] = *DI++;
|
||||
}
|
||||
|
||||
if(rticks) {
|
||||
tmp[index++] = 0x1B;
|
||||
tmp[index++] = rticks - 1;
|
||||
tmp[index++] = *DI;
|
||||
}
|
||||
|
||||
if(final_tms) {
|
||||
tmp[index++] = 0x4B;
|
||||
tmp[index++] = 0;
|
||||
tmp[index++] = (*DI)>>rticks?0x81:0x01;
|
||||
}
|
||||
// assert(ftdi_write_data(ftdic, tmp, index) == index);
|
||||
platform_buffer_write(tmp, index);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PROVIDE_GENERIC_TAP_TDI_TDO_SEQ
|
||||
void
|
||||
jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t *tmp;
|
||||
int index = 0, rsize;
|
||||
int rticks;
|
||||
int rsize, rticks;
|
||||
|
||||
if(!ticks) return;
|
||||
if (!DI && !DO) return;
|
||||
|
||||
// printf("ticks: %d\n", ticks);
|
||||
if(final_tms) ticks--;
|
||||
rticks = ticks & 7;
|
||||
ticks >>= 3;
|
||||
tmp = alloca(ticks + 9);
|
||||
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) {
|
||||
tmp[index++] = 0x39;
|
||||
tmp[index++] = ticks - 1;
|
||||
tmp[index++] = 0;
|
||||
while(ticks--) tmp[index++] = *DI++;
|
||||
data[0] = cmd;
|
||||
data[1] = ticks - 1;
|
||||
data[2] = 0;
|
||||
platform_buffer_write(data, 3);
|
||||
if (DI)
|
||||
platform_buffer_write(DI, ticks);
|
||||
}
|
||||
|
||||
if(rticks) {
|
||||
int index = 0;
|
||||
rsize++;
|
||||
tmp[index++] = 0x3B;
|
||||
tmp[index++] = rticks - 1;
|
||||
tmp[index++] = *DI;
|
||||
data[index++] = cmd | MPSSE_BITMODE;
|
||||
data[index++] = rticks - 1;
|
||||
if (DI)
|
||||
data[index++] = DI[ticks];
|
||||
platform_buffer_write(data, index);
|
||||
}
|
||||
|
||||
if(final_tms) {
|
||||
int index = 0;
|
||||
rsize++;
|
||||
tmp[index++] = 0x6B;
|
||||
tmp[index++] = 0;
|
||||
tmp[index++] = (*DI)>>rticks?0x81:0x01;
|
||||
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)>>rticks?0x81:0x01;
|
||||
platform_buffer_write(data, index);
|
||||
}
|
||||
// assert(ftdi_write_data(ftdic, tmp, index) == index);
|
||||
platform_buffer_write(tmp, index);
|
||||
// index = 0;
|
||||
// while((index += ftdi_read_data(ftdic, tmp + index, rsize-index)) != rsize);
|
||||
platform_buffer_read(tmp, rsize);
|
||||
/*for(index = 0; index < rsize; index++)
|
||||
printf("%02X ", tmp[index]);
|
||||
printf("\n");*/
|
||||
index = 0;
|
||||
if(final_tms) rsize--;
|
||||
if (DO) {
|
||||
int index = 0;
|
||||
uint8_t *tmp = alloca(ticks);
|
||||
platform_buffer_read(tmp, rsize);
|
||||
if(final_tms) rsize--;
|
||||
|
||||
while(rsize--) {
|
||||
/*if(rsize) printf("%02X ", tmp[index]);*/
|
||||
*DO++ = tmp[index++];
|
||||
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);*/
|
||||
}
|
||||
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);*/
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
uint8_t ret;
|
||||
uint8_t tmp[3] = "\x6B\x00\x00";
|
||||
uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0};
|
||||
tmp[2] = (dTDI?0x80:0) | (dTMS?0x01:0);
|
||||
// assert(ftdi_write_data(ftdic, tmp, 3) == 3);
|
||||
// while(ftdi_read_data(ftdic, &ret, 1) != 1);
|
||||
platform_buffer_write(tmp, 3);
|
||||
platform_buffer_read(&ret, 1);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "version.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
@ -31,27 +32,25 @@ struct ftdi_context *ftdic;
|
|||
static uint8_t outbuf[BUF_SIZE];
|
||||
static uint16_t bufptr = 0;
|
||||
|
||||
static 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;
|
||||
char *description;
|
||||
char * name;
|
||||
} cable_desc[] = {
|
||||
cable_desc_t *active_cable;
|
||||
|
||||
cable_desc_t cable_desc[] = {
|
||||
{
|
||||
/* Direct connection from FTDI to Jtag/Swd.*/
|
||||
.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,
|
||||
.description = "FLOSS-JTAG",
|
||||
.name = "flossjtag"
|
||||
},
|
||||
{
|
||||
/* Buffered connection from FTDI to Jtag/Swd.
|
||||
* TCK and TMS not independant switchable!
|
||||
* SWD not possible. */
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6010,
|
||||
.interface = INTERFACE_A,
|
||||
|
@ -60,6 +59,33 @@ static struct cable_desc_s {
|
|||
.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)
|
||||
* BCBUS 1 (Output) N_SRST
|
||||
* BCBUS 2 (Input) V_ISO available
|
||||
*
|
||||
* For bitbanged SWD, set Bit 5 low and select SWD read with
|
||||
* Bit 6 low. Read Connector TMS as FTDI TDO.
|
||||
*
|
||||
* TDO is routed to Interface 0 RXD as SWO or with Uart
|
||||
* Connector pin 10 pulled to ground will connect Interface 0 RXD
|
||||
* to UART connector RXD
|
||||
*/
|
||||
.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"
|
||||
},
|
||||
{
|
||||
.vendor = 0x15b1,
|
||||
.product = 0x0003,
|
||||
|
@ -69,6 +95,9 @@ static struct cable_desc_s {
|
|||
.name = "olimex"
|
||||
},
|
||||
{
|
||||
/* Buffered connection from FTDI to Jtag/Swd.
|
||||
* TCK and TMS not independant switchable!
|
||||
* => SWD not possible. */
|
||||
.vendor = 0x0403,
|
||||
.product = 0xbdc8,
|
||||
.interface = INTERFACE_A,
|
||||
|
@ -77,6 +106,11 @@ static struct cable_desc_s {
|
|||
.name = "turtelizer"
|
||||
},
|
||||
{
|
||||
/* https://reference.digilentinc.com/jtag_hs1/jtag_hs1
|
||||
* No schmeatics available.
|
||||
* Buffered from FTDI to Jtag/Swd announced
|
||||
* Independant switch for TMS not known
|
||||
* => SWD not possible. */
|
||||
.vendor = 0x0403,
|
||||
.product = 0xbdc8,
|
||||
.interface = INTERFACE_A,
|
||||
|
@ -85,14 +119,18 @@ static struct cable_desc_s {
|
|||
.name = "jtaghs1"
|
||||
},
|
||||
{
|
||||
/* Direct connection from FTDI to Jtag/Swd assumed.*/
|
||||
.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,
|
||||
.name = "ftdi"
|
||||
},
|
||||
{
|
||||
/* Product name not unique! Assume SWD not possible.*/
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6014,
|
||||
.interface = INTERFACE_A,
|
||||
|
@ -103,22 +141,32 @@ static struct cable_desc_s {
|
|||
.name = "digilent"
|
||||
},
|
||||
{
|
||||
/* Direct connection from FTDI to Jtag/Swd assumed.*/
|
||||
.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,
|
||||
.name = "ft232h"
|
||||
},
|
||||
{
|
||||
/* Direct connection from FTDI to Jtag/Swd assumed.*/
|
||||
.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,
|
||||
.name = "ft4232h"
|
||||
},
|
||||
{
|
||||
/* http://www.olimex.com/dev/pdf/ARM-USB-OCD.pdf.
|
||||
* BDUS 4 global enables JTAG Buffer.
|
||||
* => TCK and TMS not independant switchable!
|
||||
* => SWD not possible. */
|
||||
.vendor = 0x15ba,
|
||||
.product = 0x002b,
|
||||
.interface = INTERFACE_A,
|
||||
|
@ -137,9 +185,6 @@ void platform_init(int argc, char **argv)
|
|||
unsigned index = 0;
|
||||
char *serial = NULL;
|
||||
char * cablename = "ftdi";
|
||||
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
|
||||
SET_BITS_HIGH, 0,0};
|
||||
|
||||
while((c = getopt(argc, argv, "c:s:")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
|
@ -161,14 +206,7 @@ void platform_init(int argc, char **argv)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (cable_desc[index].dbus_data)
|
||||
ftdi_init[4]= cable_desc[index].dbus_data;
|
||||
if (cable_desc[index].dbus_ddr)
|
||||
ftdi_init[5]= cable_desc[index].dbus_ddr;
|
||||
if (cable_desc[index].cbus_data)
|
||||
ftdi_init[7]= cable_desc[index].cbus_data;
|
||||
if(cable_desc[index].cbus_ddr)
|
||||
ftdi_init[8]= cable_desc[index].cbus_ddr;
|
||||
active_cable = &cable_desc[index];
|
||||
|
||||
printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n");
|
||||
printf("Copyright (C) 2015 Black Sphere Technologies Ltd.\n");
|
||||
|
@ -185,14 +223,14 @@ void platform_init(int argc, char **argv)
|
|||
ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
if((err = ftdi_set_interface(ftdic, cable_desc[index].interface)) != 0) {
|
||||
if((err = ftdi_set_interface(ftdic, active_cable->interface)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_interface: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
if((err = ftdi_usb_open_desc(
|
||||
ftdic, cable_desc[index].vendor, cable_desc[index].product,
|
||||
cable_desc[index].description, serial)) != 0) {
|
||||
ftdic, active_cable->vendor, active_cable->product,
|
||||
active_cable->description, serial)) != 0) {
|
||||
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
|
@ -208,24 +246,11 @@ void platform_init(int argc, char **argv)
|
|||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
if((err = ftdi_usb_purge_buffers(ftdic)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_baudrate: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
if((err = ftdi_write_data_set_chunksize(ftdic, BUF_SIZE)) != 0) {
|
||||
fprintf(stderr, "ftdi_write_data_set_chunksize: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
|
||||
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_MPSSE)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
|
||||
assert(ftdi_write_data(ftdic, ftdi_init, 9) == 9);
|
||||
assert(gdb_if_init() == 0);
|
||||
}
|
||||
|
||||
|
@ -255,6 +280,7 @@ int platform_buffer_write(const uint8_t *data, int size)
|
|||
int platform_buffer_read(uint8_t *data, int size)
|
||||
{
|
||||
int index = 0;
|
||||
outbuf[bufptr++] = SEND_IMMEDIATE;
|
||||
platform_buffer_flush();
|
||||
while((index += ftdi_read_data(ftdic, data + index, size-index)) != size);
|
||||
return size;
|
||||
|
|
|
@ -48,10 +48,33 @@ void platform_buffer_flush(void);
|
|||
int platform_buffer_write(const uint8_t *data, int size);
|
||||
int platform_buffer_read(uint8_t *data, int size);
|
||||
|
||||
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.*/
|
||||
char *description;
|
||||
char * name;
|
||||
}cable_desc_t;
|
||||
|
||||
extern cable_desc_t *active_cable;
|
||||
|
||||
static inline int platform_hwversion(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MPSSE_TDI 2
|
||||
#define MPSSE_TDO 4
|
||||
#define MPSSE_TMS 8
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,7 +1,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
|
||||
|
@ -18,8 +18,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Quick hack for bit-banging SW-DP interface over FT2232.
|
||||
* Intended as proof of concept, not for production.
|
||||
/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled.
|
||||
* Speed is sensible.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -31,65 +31,206 @@
|
|||
|
||||
static uint8_t olddir = 0;
|
||||
|
||||
#define MPSSE_MASK (MPSSE_TDI | MPSSE_TDO | MPSSE_TMS)
|
||||
#define MPSSE_TD_MASK (MPSSE_TDI | MPSSE_TDO)
|
||||
#define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
|
||||
MPSSE_BITMODE | MPSSE_WRITE_NEG)
|
||||
|
||||
int swdptap_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
assert(ftdic != NULL);
|
||||
|
||||
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
if (!active_cable->bitbang_tms_in_pin) {
|
||||
DEBUG("SWD not possible or missing item in cable description.\n");
|
||||
return -1;
|
||||
}
|
||||
int err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
|
||||
assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2);
|
||||
olddir = 0;
|
||||
/* 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));
|
||||
return -1;;
|
||||
}
|
||||
/* 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));
|
||||
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;
|
||||
platform_buffer_write(ftdi_init, 9);
|
||||
platform_buffer_flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void swdptap_turnaround(uint8_t dir)
|
||||
{
|
||||
platform_buffer_flush();
|
||||
|
||||
if (dir == olddir)
|
||||
return;
|
||||
olddir = dir;
|
||||
uint8_t cmd[6];
|
||||
int index = 0;
|
||||
|
||||
if(dir) /* SWDIO goes to input */
|
||||
assert(ftdi_set_bitmode(ftdic, 0xA3, BITMODE_BITBANG) == 0);
|
||||
|
||||
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;
|
||||
}
|
||||
/* One clock cycle */
|
||||
ftdi_write_data(ftdic, (void *)"\xAB\xA8", 2);
|
||||
|
||||
if(!dir) /* SWDIO goes to output */
|
||||
assert(ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG) == 0);
|
||||
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;
|
||||
}
|
||||
platform_buffer_write(cmd, index);
|
||||
}
|
||||
|
||||
bool swdptap_bit_in(void)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
swdptap_turnaround(1);
|
||||
uint8_t cmd[4];
|
||||
int index = 0;
|
||||
|
||||
ftdi_read_pins(ftdic, &ret);
|
||||
ret &= 0x08;
|
||||
ftdi_write_data(ftdic, (void *)"\xA1\xA0", 2);
|
||||
|
||||
return ret;
|
||||
cmd[index++] = active_cable->bitbang_tms_in_port_cmd;
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = 0;
|
||||
platform_buffer_write(cmd, index);
|
||||
uint8_t data[1];
|
||||
platform_buffer_read(data, 1);
|
||||
return (data[0] &= active_cable->bitbang_tms_in_pin);
|
||||
}
|
||||
|
||||
void swdptap_bit_out(bool val)
|
||||
{
|
||||
uint8_t buf[3] = "\xA0\xA1\xA0";
|
||||
|
||||
swdptap_turnaround(0);
|
||||
uint8_t cmd[3];
|
||||
|
||||
if (val) {
|
||||
for(int i = 0; i < 3; i++)
|
||||
buf[i] |= 0x08;
|
||||
}
|
||||
platform_buffer_write(buf, 3);
|
||||
cmd[0] = MPSSE_TMS_SHIFT;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = (val)? 1 : 0;
|
||||
platform_buffer_write(cmd, 3);
|
||||
}
|
||||
|
||||
bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
{
|
||||
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--) {
|
||||
platform_buffer_write(cmd, 4);
|
||||
}
|
||||
uint8_t data[33];
|
||||
unsigned int ret = 0;
|
||||
platform_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) {
|
||||
parity ^= 1;
|
||||
ret |= (1 << ticks);
|
||||
}
|
||||
}
|
||||
*res = ret;
|
||||
return parity;
|
||||
}
|
||||
|
||||
uint32_t swdptap_seq_in(int ticks)
|
||||
{
|
||||
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;
|
||||
|
||||
swdptap_turnaround(1);
|
||||
while (index--) {
|
||||
platform_buffer_write(cmd, 4);
|
||||
}
|
||||
uint8_t data[32];
|
||||
uint32_t ret = 0;
|
||||
platform_buffer_read(data, ticks);
|
||||
while (ticks--) {
|
||||
if (data[ticks] & active_cable->bitbang_tms_in_pin)
|
||||
ret |= (1 << ticks);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t cmd[15];
|
||||
uint 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;
|
||||
}
|
||||
}
|
||||
platform_buffer_write(cmd, index);
|
||||
}
|
||||
|
||||
void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t parity = 0;
|
||||
int steps = ticks;
|
||||
uint8_t cmd[18];
|
||||
uint 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;
|
||||
}
|
||||
}
|
||||
while (ticks--) {
|
||||
parity ^= MS;
|
||||
MS >>= 1;
|
||||
}
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = parity;
|
||||
platform_buffer_write(cmd, index);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,8 @@ int adiv5_swdp_scan(void)
|
|||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
|
||||
swdptap_init();
|
||||
if (swdptap_init())
|
||||
return -1;
|
||||
|
||||
/* Switch from JTAG to SWD mode */
|
||||
swdptap_seq_out(0xFFFF, 16);
|
||||
|
|
|
@ -294,6 +294,10 @@ void target_detach(target *t)
|
|||
{
|
||||
t->detach(t);
|
||||
t->attached = false;
|
||||
#if defined(LIBFTDI)
|
||||
# include "platform.h"
|
||||
platform_buffer_flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool target_check_error(target *t) { return t->check_error(t); }
|
||||
|
|
Loading…
Reference in New Issue