From 992ccf91a99c05f69b92de0e9e76507900d18071 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Tue, 29 May 2018 19:33:43 +0200 Subject: [PATCH] libftdi/swdptap.c: Use MPSSE Mode for bitbanging SWD. --- src/platforms/libftdi/platform.h | 4 ++ src/platforms/libftdi/swdptap.c | 101 +++++++++++++++++++------------ 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/platforms/libftdi/platform.h b/src/platforms/libftdi/platform.h index 7b4f4b9..562f58f 100644 --- a/src/platforms/libftdi/platform.h +++ b/src/platforms/libftdi/platform.h @@ -67,5 +67,9 @@ static inline int platform_hwversion(void) return 0; } +#define MPSSE_TDI 2 +#define MPSSE_TDO 4 +#define MPSSE_TMS 8 + #endif diff --git a/src/platforms/libftdi/swdptap.c b/src/platforms/libftdi/swdptap.c index 24b2ce3..de8270e 100644 --- a/src/platforms/libftdi/swdptap.c +++ b/src/platforms/libftdi/swdptap.c @@ -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 * * This program is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -/* 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. + * Slow, but usable. */ #include @@ -31,72 +31,97 @@ 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) + +#define MPSSE_TMS_IN_PORT GET_BITS_LOW +#define MPSSE_TMS_IN_PIN MPSSE_TMS + int swdptap_init(void) { - int err; - - 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. */ - if((err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET)) != 0) { + 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)); - abort(); + return -1;; } - - if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG)) != 0) { + /* 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)); - abort(); + return -1;; } - - assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2); - olddir = 0; + 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; + cmd[index++] = active_cable->dbus_data | MPSSE_MASK; + 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++] = MPSSE_TMS_IN_PORT; + 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] &= MPSSE_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); }