Merge pull request #347 from UweBonnes/ftdi

libftdi platform improvements
This commit is contained in:
Gareth McMullin 2018-05-31 10:16:34 +12:00 committed by GitHub
commit 80f003ff4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 346 additions and 176 deletions

View File

@ -21,8 +21,6 @@
/* Low level JTAG implementation using FT2232 with libftdi. /* Low level JTAG implementation using FT2232 with libftdi.
* *
* Issues: * Issues:
* This code is old, rotten and unsupported.
* Magic numbers everywhere.
* Should share interface with swdptap.c or at least clean up... * Should share interface with swdptap.c or at least clean up...
*/ */
@ -35,23 +33,39 @@
#include <ftdi.h> #include <ftdi.h>
#include "general.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" #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) int jtagtap_init(void)
{ {
assert(ftdic != NULL); 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 */ /* Go to JTAG mode for SWJ-DP */
for (int i = 0; i <= 50; i++) for (int i = 0; i <= 50; i++)
@ -67,133 +81,94 @@ void jtagtap_reset(void)
jtagtap_soft_reset(); jtagtap_soft_reset();
} }
#ifndef PROVIDE_GENERIC_TAP_TMS_SEQ
void void
jtagtap_tms_seq(uint32_t MS, int ticks) 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) { while(ticks >= 0) {
//jtagtap_next(MS & 1, 1);
tmp[1] = ticks<7?ticks-1:6; tmp[1] = ticks<7?ticks-1:6;
tmp[2] = 0x80 | (MS & 0x7F); tmp[2] = 0x80 | (MS & 0x7F);
// assert(ftdi_write_data(ftdic, tmp, 3) == 3);
platform_buffer_write(tmp, 3); platform_buffer_write(tmp, 3);
MS >>= 7; ticks -= 7; 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 void
jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
{ {
uint8_t *tmp; int rsize, rticks;
int index = 0, rsize;
int rticks;
if(!ticks) return; if(!ticks) return;
if (!DI && !DO) return;
// printf("ticks: %d\n", ticks); // printf("ticks: %d\n", ticks);
if(final_tms) ticks--; if(final_tms) ticks--;
rticks = ticks & 7; rticks = ticks & 7;
ticks >>= 3; 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; rsize = ticks;
if(ticks) { if(ticks) {
tmp[index++] = 0x39; data[0] = cmd;
tmp[index++] = ticks - 1; data[1] = ticks - 1;
tmp[index++] = 0; data[2] = 0;
while(ticks--) tmp[index++] = *DI++; platform_buffer_write(data, 3);
if (DI)
platform_buffer_write(DI, ticks);
} }
if(rticks) { if(rticks) {
int index = 0;
rsize++; rsize++;
tmp[index++] = 0x3B; data[index++] = cmd | MPSSE_BITMODE;
tmp[index++] = rticks - 1; data[index++] = rticks - 1;
tmp[index++] = *DI; if (DI)
data[index++] = DI[ticks];
platform_buffer_write(data, index);
} }
if(final_tms) { if(final_tms) {
int index = 0;
rsize++; rsize++;
tmp[index++] = 0x6B; data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
tmp[index++] = 0; data[index++] = 0;
tmp[index++] = (*DI)>>rticks?0x81:0x01; if (DI)
data[index++] = (*DI)>>rticks?0x81:0x01;
platform_buffer_write(data, index);
} }
// assert(ftdi_write_data(ftdic, tmp, index) == index); if (DO) {
platform_buffer_write(tmp, index); int index = 0;
// index = 0; uint8_t *tmp = alloca(ticks);
// while((index += ftdi_read_data(ftdic, tmp + index, rsize-index)) != rsize); platform_buffer_read(tmp, rsize);
platform_buffer_read(tmp, rsize); if(final_tms) rsize--;
/*for(index = 0; index < rsize; index++)
printf("%02X ", tmp[index]);
printf("\n");*/
index = 0;
if(final_tms) rsize--;
while(rsize--) { while(rsize--) {
/*if(rsize) printf("%02X ", tmp[index]);*/ /*if(rsize) printf("%02X ", tmp[index]);*/
*DO++ = 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 jtagtap_next(uint8_t dTMS, uint8_t dTDI)
{ {
uint8_t ret; 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); 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_write(tmp, 3);
platform_buffer_read(&ret, 1); platform_buffer_read(&ret, 1);

View File

@ -20,6 +20,7 @@
#include "general.h" #include "general.h"
#include "gdb_if.h" #include "gdb_if.h"
#include "version.h" #include "version.h"
#include "platform.h"
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
@ -31,27 +32,25 @@ struct ftdi_context *ftdic;
static uint8_t outbuf[BUF_SIZE]; static uint8_t outbuf[BUF_SIZE];
static uint16_t bufptr = 0; static uint16_t bufptr = 0;
static struct cable_desc_s { cable_desc_t *active_cable;
int vendor;
int product; cable_desc_t cable_desc[] = {
int interface;
uint8_t dbus_data;
uint8_t dbus_ddr;
uint8_t cbus_data;
uint8_t cbus_ddr;
char *description;
char * name;
} cable_desc[] = {
{ {
/* Direct connection from FTDI to Jtag/Swd.*/
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .dbus_data = 0x08,
.dbus_ddr = 0x1B, .dbus_ddr = 0x1B,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS,
.description = "FLOSS-JTAG", .description = "FLOSS-JTAG",
.name = "flossjtag" .name = "flossjtag"
}, },
{ {
/* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable!
* SWD not possible. */
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6010, .product = 0x6010,
.interface = INTERFACE_A, .interface = INTERFACE_A,
@ -60,6 +59,33 @@ static struct cable_desc_s {
.description = "FTDIJTAG", .description = "FTDIJTAG",
.name = "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, .vendor = 0x15b1,
.product = 0x0003, .product = 0x0003,
@ -69,6 +95,9 @@ static struct cable_desc_s {
.name = "olimex" .name = "olimex"
}, },
{ {
/* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable!
* => SWD not possible. */
.vendor = 0x0403, .vendor = 0x0403,
.product = 0xbdc8, .product = 0xbdc8,
.interface = INTERFACE_A, .interface = INTERFACE_A,
@ -77,6 +106,11 @@ static struct cable_desc_s {
.name = "turtelizer" .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, .vendor = 0x0403,
.product = 0xbdc8, .product = 0xbdc8,
.interface = INTERFACE_A, .interface = INTERFACE_A,
@ -85,14 +119,18 @@ static struct cable_desc_s {
.name = "jtaghs1" .name = "jtaghs1"
}, },
{ {
/* Direct connection from FTDI to Jtag/Swd assumed.*/
.vendor = 0x0403, .vendor = 0x0403,
.product = 0xbdc8, .product = 0xbdc8,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0xA8, .dbus_data = 0xA8,
.dbus_ddr = 0xAB, .dbus_ddr = 0xAB,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS,
.name = "ftdi" .name = "ftdi"
}, },
{ {
/* Product name not unique! Assume SWD not possible.*/
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6014, .product = 0x6014,
.interface = INTERFACE_A, .interface = INTERFACE_A,
@ -103,22 +141,32 @@ static struct cable_desc_s {
.name = "digilent" .name = "digilent"
}, },
{ {
/* Direct connection from FTDI to Jtag/Swd assumed.*/
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6014, .product = 0x6014,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .dbus_data = 0x08,
.dbus_ddr = 0x0B, .dbus_ddr = 0x0B,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS,
.name = "ft232h" .name = "ft232h"
}, },
{ {
/* Direct connection from FTDI to Jtag/Swd assumed.*/
.vendor = 0x0403, .vendor = 0x0403,
.product = 0x6011, .product = 0x6011,
.interface = INTERFACE_A, .interface = INTERFACE_A,
.dbus_data = 0x08, .dbus_data = 0x08,
.dbus_ddr = 0x0B, .dbus_ddr = 0x0B,
.bitbang_tms_in_port_cmd = GET_BITS_LOW,
.bitbang_tms_in_pin = MPSSE_TMS,
.name = "ft4232h" .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, .vendor = 0x15ba,
.product = 0x002b, .product = 0x002b,
.interface = INTERFACE_A, .interface = INTERFACE_A,
@ -137,9 +185,6 @@ void platform_init(int argc, char **argv)
unsigned index = 0; unsigned index = 0;
char *serial = NULL; char *serial = NULL;
char * cablename = "ftdi"; 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) { while((c = getopt(argc, argv, "c:s:")) != -1) {
switch(c) { switch(c) {
case 'c': case 'c':
@ -161,14 +206,7 @@ void platform_init(int argc, char **argv)
exit(-1); exit(-1);
} }
if (cable_desc[index].dbus_data) active_cable = &cable_desc[index];
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;
printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n"); printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n");
printf("Copyright (C) 2015 Black Sphere Technologies Ltd.\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)); ftdi_get_error_string(ftdic));
abort(); 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", fprintf(stderr, "ftdi_set_interface: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); abort();
} }
if((err = ftdi_usb_open_desc( if((err = ftdi_usb_open_desc(
ftdic, cable_desc[index].vendor, cable_desc[index].product, ftdic, active_cable->vendor, active_cable->product,
cable_desc[index].description, serial)) != 0) { active_cable->description, serial)) != 0) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n", fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); abort();
@ -208,24 +246,11 @@ void platform_init(int argc, char **argv)
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); 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) { if((err = ftdi_write_data_set_chunksize(ftdic, BUF_SIZE)) != 0) {
fprintf(stderr, "ftdi_write_data_set_chunksize: %d: %s\n", fprintf(stderr, "ftdi_write_data_set_chunksize: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); 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); 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 platform_buffer_read(uint8_t *data, int size)
{ {
int index = 0; int index = 0;
outbuf[bufptr++] = SEND_IMMEDIATE;
platform_buffer_flush(); platform_buffer_flush();
while((index += ftdi_read_data(ftdic, data + index, size-index)) != size); while((index += ftdi_read_data(ftdic, data + index, size-index)) != size);
return size; return size;

View File

@ -48,10 +48,33 @@ void platform_buffer_flush(void);
int platform_buffer_write(const uint8_t *data, int size); int platform_buffer_write(const uint8_t *data, int size);
int platform_buffer_read(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) static inline int platform_hwversion(void)
{ {
return 0; return 0;
} }
#define MPSSE_TDI 2
#define MPSSE_TDO 4
#define MPSSE_TMS 8
#endif #endif

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the Black Magic Debug project. * 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> * Written by Gareth McMullin <gareth@blacksphere.co.nz>
* *
* This program is free software: you can redistribute it and/or modify * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Quick hack for bit-banging SW-DP interface over FT2232. /* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled.
* Intended as proof of concept, not for production. * Speed is sensible.
*/ */
#include <stdio.h> #include <stdio.h>
@ -31,65 +31,206 @@
static uint8_t olddir = 0; 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 swdptap_init(void)
{ {
int err; if (!active_cable->bitbang_tms_in_pin) {
DEBUG("SWD not possible or missing item in cable description.\n");
assert(ftdic != NULL); return -1;
}
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG)) != 0) { int err = ftdi_usb_purge_buffers(ftdic);
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n", if (err != 0) {
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); abort();
} }
/* Reset MPSSE controller. */
assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2); err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
olddir = 0; 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; return 0;
} }
static void swdptap_turnaround(uint8_t dir) static void swdptap_turnaround(uint8_t dir)
{ {
platform_buffer_flush();
if (dir == olddir) if (dir == olddir)
return; return;
olddir = dir; olddir = dir;
uint8_t cmd[6];
int index = 0;
if(dir) /* SWDIO goes to input */ if(dir) { /* SWDIO goes to input */
assert(ftdi_set_bitmode(ftdic, 0xA3, BITMODE_BITBANG) == 0); 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 */ /* One clock cycle */
ftdi_write_data(ftdic, (void *)"\xAB\xA8", 2); cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0;
if(!dir) /* SWDIO goes to output */ cmd[index++] = 0;
assert(ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG) == 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) bool swdptap_bit_in(void)
{ {
uint8_t ret;
swdptap_turnaround(1); swdptap_turnaround(1);
uint8_t cmd[4];
int index = 0;
ftdi_read_pins(ftdic, &ret); cmd[index++] = active_cable->bitbang_tms_in_port_cmd;
ret &= 0x08; cmd[index++] = MPSSE_TMS_SHIFT;
ftdi_write_data(ftdic, (void *)"\xA1\xA0", 2); cmd[index++] = 0;
cmd[index++] = 0;
return ret; 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) void swdptap_bit_out(bool val)
{ {
uint8_t buf[3] = "\xA0\xA1\xA0";
swdptap_turnaround(0); swdptap_turnaround(0);
uint8_t cmd[3];
if (val) { cmd[0] = MPSSE_TMS_SHIFT;
for(int i = 0; i < 3; i++) cmd[1] = 0;
buf[i] |= 0x08; cmd[2] = (val)? 1 : 0;
} platform_buffer_write(cmd, 3);
platform_buffer_write(buf, 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);
}

View File

@ -49,7 +49,8 @@ int adiv5_swdp_scan(void)
target_list_free(); target_list_free();
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
swdptap_init(); if (swdptap_init())
return -1;
/* Switch from JTAG to SWD mode */ /* Switch from JTAG to SWD mode */
swdptap_seq_out(0xFFFF, 16); swdptap_seq_out(0xFFFF, 16);

View File

@ -294,6 +294,10 @@ void target_detach(target *t)
{ {
t->detach(t); t->detach(t);
t->attached = false; t->attached = false;
#if defined(LIBFTDI)
# include "platform.h"
platform_buffer_flush();
#endif
} }
bool target_check_error(target *t) { return t->check_error(t); } bool target_check_error(target *t) { return t->check_error(t); }