jtag/ftdi: switch to command 'adapter serial'
[fw/openocd] / src / jtag / drivers / ftdi.c
index 6406406aa093061223edc3502dc083726cb7d56e..7671cee5d08fdbad14a3e615f60018fb37f3c73f 100644 (file)
@@ -13,9 +13,7 @@
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
-*   along with this program; if not, write to the                         *
-*   Free Software Foundation, Inc.,                                       *
-*   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+*   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/
 
 /**
  *
  * This code uses information contained in the MPSSE specification which was
  * found here:
- * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf
+ * https://www.ftdichip.com/Support/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf
  * Hereafter this is called the "MPSSE Spec".
  *
- * The datasheet for the ftdichip.com's FT2232D part is here:
- * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf
+ * The datasheet for the ftdichip.com's FT2232H part is here:
+ * https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232H.pdf
  *
  * Also note the issue with code 0x4b (clock data to TMS) noted in
  * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html
 #endif
 
 /* project specific includes */
+#include <jtag/adapter.h>
 #include <jtag/interface.h>
 #include <jtag/swd.h>
 #include <transport/transport.h>
 #include <helper/time_support.h>
+#include <helper/log.h>
 
 #if IS_CYGWIN == 1
 #include <windows.h>
 #include "mpsse.h"
 
 #define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
+#define JTAG_MODE_ALT (LSB_FIRST | NEG_EDGE_IN | NEG_EDGE_OUT)
 #define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
 
 static char *ftdi_device_desc;
-static char *ftdi_serial;
 static uint8_t ftdi_channel;
+static uint8_t ftdi_jtag_mode = JTAG_MODE;
 
 static bool swd_mode;
 
@@ -104,8 +105,10 @@ static struct mpsse_ctx *mpsse_ctx;
 struct signal {
        const char *name;
        uint16_t data_mask;
+       uint16_t input_mask;
        uint16_t oe_mask;
        bool invert_data;
+       bool invert_input;
        bool invert_oe;
        struct signal *next;
 };
@@ -128,7 +131,7 @@ static uint16_t direction;
 static uint16_t jtag_output_init;
 static uint16_t jtag_direction_init;
 
-static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
+static int ftdi_swd_switch_seq(enum swd_special_seq seq);
 
 static struct signal *find_signal_by_name(const char *name)
 {
@@ -146,11 +149,11 @@ static struct signal *create_signal(const char *name)
                psig = &(*psig)->next;
 
        *psig = calloc(1, sizeof(**psig));
-       if (*psig == NULL)
+       if (!*psig)
                return NULL;
 
        (*psig)->name = strdup(name);
-       if ((*psig)->name == NULL) {
+       if (!(*psig)->name) {
                free(*psig);
                *psig = NULL;
        }
@@ -210,6 +213,32 @@ static int ftdi_set_signal(const struct signal *s, char value)
        return ERROR_OK;
 }
 
+static int ftdi_get_signal(const struct signal *s, uint16_t *value_out)
+{
+       uint8_t data_low = 0;
+       uint8_t data_high = 0;
+
+       if (s->input_mask == 0) {
+               LOG_ERROR("interface doesn't provide signal '%s'", s->name);
+               return ERROR_FAIL;
+       }
+
+       if (s->input_mask & 0xff)
+               mpsse_read_data_bits_low_byte(mpsse_ctx, &data_low);
+       if (s->input_mask >> 8)
+               mpsse_read_data_bits_high_byte(mpsse_ctx, &data_high);
+
+       mpsse_flush(mpsse_ctx);
+
+       *value_out = (((uint16_t)data_high) << 8) | data_low;
+
+       if (s->invert_input)
+               *value_out = ~(*value_out);
+
+       *value_out &= s->input_mask;
+
+       return ERROR_OK;
+}
 
 /**
  * Function move_to_state
@@ -233,7 +262,7 @@ static void move_to_state(tap_state_t goal_state)
        int tms_count = tap_get_tms_path_len(start_state, goal_state);
        assert(tms_count <= 8);
 
-       DEBUG_JTAG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state));
+       LOG_DEBUG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state));
 
        /* Track state transitions step by step */
        for (int i = 0; i < tms_count; i++)
@@ -244,7 +273,7 @@ static void move_to_state(tap_state_t goal_state)
                0,
                tms_count,
                false,
-               JTAG_MODE);
+               ftdi_jtag_mode);
 }
 
 static int ftdi_speed(int speed)
@@ -257,6 +286,9 @@ static int ftdi_speed(int speed)
                return retval;
        }
 
+       if (!swd_mode && speed >= 10000000 && ftdi_jtag_mode != JTAG_MODE_ALT)
+               LOG_INFO("ftdi: if you experience problems at higher adapter clocks, try "
+                        "the command \"ftdi tdo_sample_edge falling\"");
        return ERROR_OK;
 }
 
@@ -292,7 +324,7 @@ static void ftdi_execute_runtest(struct jtag_command *cmd)
        int i;
        uint8_t zero = 0;
 
-       DEBUG_JTAG_IO("runtest %i cycles, end in %s",
+       LOG_DEBUG_IO("runtest %i cycles, end in %s",
                cmd->cmd.runtest->num_cycles,
                tap_state_name(cmd->cmd.runtest->end_state));
 
@@ -304,7 +336,7 @@ static void ftdi_execute_runtest(struct jtag_command *cmd)
        while (i > 0) {
                /* there are no state transitions in this code, so omit state tracking */
                unsigned this_len = i > 7 ? 7 : i;
-               mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, JTAG_MODE);
+               mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, ftdi_jtag_mode);
                i -= this_len;
        }
 
@@ -313,14 +345,14 @@ static void ftdi_execute_runtest(struct jtag_command *cmd)
        if (tap_get_state() != tap_get_end_state())
                move_to_state(tap_get_end_state());
 
-       DEBUG_JTAG_IO("runtest: %i, end in %s",
+       LOG_DEBUG_IO("runtest: %i, end in %s",
                cmd->cmd.runtest->num_cycles,
                tap_state_name(tap_get_end_state()));
 }
 
 static void ftdi_execute_statemove(struct jtag_command *cmd)
 {
-       DEBUG_JTAG_IO("statemove end in %s",
+       LOG_DEBUG_IO("statemove end in %s",
                tap_state_name(cmd->cmd.statemove->end_state));
 
        ftdi_end_state(cmd->cmd.statemove->end_state);
@@ -336,7 +368,7 @@ static void ftdi_execute_statemove(struct jtag_command *cmd)
  */
 static void ftdi_execute_tms(struct jtag_command *cmd)
 {
-       DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
+       LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
 
        /* TODO: Missing tap state tracking, also missing from ft2232.c! */
        mpsse_clock_tms_cs_out(mpsse_ctx,
@@ -344,7 +376,7 @@ static void ftdi_execute_tms(struct jtag_command *cmd)
                0,
                cmd->cmd.tms->num_bits,
                false,
-               JTAG_MODE);
+               ftdi_jtag_mode);
 }
 
 static void ftdi_execute_pathmove(struct jtag_command *cmd)
@@ -352,7 +384,7 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
        tap_state_t *path = cmd->cmd.pathmove->path;
        int num_states  = cmd->cmd.pathmove->num_states;
 
-       DEBUG_JTAG_IO("pathmove: %i states, current: %s  end: %s", num_states,
+       LOG_DEBUG_IO("pathmove: %i states, current: %s  end: %s", num_states,
                tap_state_name(tap_get_state()),
                tap_state_name(path[num_states-1]));
 
@@ -360,7 +392,7 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
        unsigned bit_count = 0;
        uint8_t tms_byte = 0;
 
-       DEBUG_JTAG_IO("-");
+       LOG_DEBUG_IO("-");
 
        /* this loop verifies that the path is legal and logs each state in the path */
        while (num_states--) {
@@ -391,7 +423,7 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
                                        0,
                                        bit_count,
                                        false,
-                                       JTAG_MODE);
+                                       ftdi_jtag_mode);
                        bit_count = 0;
                }
        }
@@ -400,18 +432,18 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
 
 static void ftdi_execute_scan(struct jtag_command *cmd)
 {
-       DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN",
+       LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN",
                jtag_scan_type(cmd->cmd.scan));
 
        /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */
        while (cmd->cmd.scan->num_fields > 0
                        && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) {
                cmd->cmd.scan->num_fields--;
-               LOG_DEBUG("discarding trailing empty field");
+               LOG_DEBUG_IO("discarding trailing empty field");
        }
 
        if (cmd->cmd.scan->num_fields == 0) {
-               LOG_DEBUG("empty scan, doing nothing");
+               LOG_DEBUG_IO("empty scan, doing nothing");
                return;
        }
 
@@ -430,7 +462,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
 
        for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) {
                scan_size += field->num_bits;
-               DEBUG_JTAG_IO("%s%s field %d/%d %d bits",
+               LOG_DEBUG_IO("%s%s field %d/%d %d bits",
                        field->in_value ? "in" : "",
                        field->out_value ? "out" : "",
                        i,
@@ -446,11 +478,15 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                field->in_value,
                                0,
                                field->num_bits - 1,
-                               JTAG_MODE);
+                               ftdi_jtag_mode);
                        uint8_t last_bit = 0;
                        if (field->out_value)
                                bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1);
-                       uint8_t tms_bits = 0x01;
+
+                       /* If endstate is TAP_IDLE, clock out 1-1-0 (->EXIT1 ->UPDATE ->IDLE)
+                        * Otherwise, clock out 1-0 (->EXIT1 ->PAUSE)
+                        */
+                       uint8_t tms_bits = 0x03;
                        mpsse_clock_tms_cs(mpsse_ctx,
                                        &tms_bits,
                                        0,
@@ -458,15 +494,26 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                        field->num_bits - 1,
                                        1,
                                        last_bit,
-                                       JTAG_MODE);
+                                       ftdi_jtag_mode);
                        tap_set_state(tap_state_transition(tap_get_state(), 1));
-                       mpsse_clock_tms_cs_out(mpsse_ctx,
-                                       &tms_bits,
-                                       1,
-                                       1,
-                                       last_bit,
-                                       JTAG_MODE);
-                       tap_set_state(tap_state_transition(tap_get_state(), 0));
+                       if (tap_get_end_state() == TAP_IDLE) {
+                               mpsse_clock_tms_cs_out(mpsse_ctx,
+                                               &tms_bits,
+                                               1,
+                                               2,
+                                               last_bit,
+                                               ftdi_jtag_mode);
+                               tap_set_state(tap_state_transition(tap_get_state(), 1));
+                               tap_set_state(tap_state_transition(tap_get_state(), 0));
+                       } else {
+                               mpsse_clock_tms_cs_out(mpsse_ctx,
+                                               &tms_bits,
+                                               2,
+                                               1,
+                                               last_bit,
+                                               ftdi_jtag_mode);
+                               tap_set_state(tap_state_transition(tap_get_state(), 0));
+                       }
                } else
                        mpsse_clock_data(mpsse_ctx,
                                field->out_value,
@@ -474,66 +521,62 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                field->in_value,
                                0,
                                field->num_bits,
-                               JTAG_MODE);
+                               ftdi_jtag_mode);
        }
 
        if (tap_get_state() != tap_get_end_state())
                move_to_state(tap_get_end_state());
 
-       DEBUG_JTAG_IO("%s scan, %i bits, end in %s",
+       LOG_DEBUG_IO("%s scan, %i bits, end in %s",
                (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size,
                tap_state_name(tap_get_end_state()));
 }
 
-static void ftdi_execute_reset(struct jtag_command *cmd)
+static int ftdi_reset(int trst, int srst)
 {
-       DEBUG_JTAG_IO("reset trst: %i srst %i",
-               cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-
-       if (cmd->cmd.reset->trst == 1
-           || (cmd->cmd.reset->srst
-               && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
-               tap_set_state(TAP_RESET);
-
-       struct signal *trst = find_signal_by_name("nTRST");
-       if (cmd->cmd.reset->trst == 1) {
-               if (trst)
-                       ftdi_set_signal(trst, '0');
-               else
-                       LOG_ERROR("Can't assert TRST: nTRST signal is not defined");
-       } else if (trst && jtag_get_reset_config() & RESET_HAS_TRST &&
-                       cmd->cmd.reset->trst == 0) {
-               if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
-                       ftdi_set_signal(trst, 'z');
-               else
-                       ftdi_set_signal(trst, '1');
+       struct signal *sig_ntrst = find_signal_by_name("nTRST");
+       struct signal *sig_nsrst = find_signal_by_name("nSRST");
+
+       LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst);
+
+       if (!swd_mode) {
+               if (trst == 1) {
+                       if (sig_ntrst)
+                               ftdi_set_signal(sig_ntrst, '0');
+                       else
+                               LOG_ERROR("Can't assert TRST: nTRST signal is not defined");
+               } else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST &&
+                               trst == 0) {
+                       if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
+                               ftdi_set_signal(sig_ntrst, 'z');
+                       else
+                               ftdi_set_signal(sig_ntrst, '1');
+               }
        }
 
-       struct signal *srst = find_signal_by_name("nSRST");
-       if (cmd->cmd.reset->srst == 1) {
-               if (srst)
-                       ftdi_set_signal(srst, '0');
+       if (srst == 1) {
+               if (sig_nsrst)
+                       ftdi_set_signal(sig_nsrst, '0');
                else
                        LOG_ERROR("Can't assert SRST: nSRST signal is not defined");
-       } else if (srst && jtag_get_reset_config() & RESET_HAS_SRST &&
-                       cmd->cmd.reset->srst == 0) {
+       } else if (sig_nsrst && jtag_get_reset_config() & RESET_HAS_SRST &&
+                       srst == 0) {
                if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
-                       ftdi_set_signal(srst, '1');
+                       ftdi_set_signal(sig_nsrst, '1');
                else
-                       ftdi_set_signal(srst, 'z');
+                       ftdi_set_signal(sig_nsrst, 'z');
        }
 
-       DEBUG_JTAG_IO("trst: %i, srst: %i",
-               cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+       return mpsse_flush(mpsse_ctx);
 }
 
 static void ftdi_execute_sleep(struct jtag_command *cmd)
 {
-       DEBUG_JTAG_IO("sleep %" PRIi32, cmd->cmd.sleep->us);
+       LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us);
 
        mpsse_flush(mpsse_ctx);
        jtag_sleep(cmd->cmd.sleep->us);
-       DEBUG_JTAG_IO("sleep %" PRIi32 " usec while in %s",
+       LOG_DEBUG_IO("sleep %" PRIu32 " usec while in %s",
                cmd->cmd.sleep->us,
                tap_state_name(tap_get_state()));
 }
@@ -553,11 +596,11 @@ static void ftdi_execute_stableclocks(struct jtag_command *cmd)
        while (num_cycles > 0) {
                /* there are no state transitions in this code, so omit state tracking */
                unsigned this_len = num_cycles > 7 ? 7 : num_cycles;
-               mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, JTAG_MODE);
+               mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, ftdi_jtag_mode);
                num_cycles -= this_len;
        }
 
-       DEBUG_JTAG_IO("clocks %i while in %s",
+       LOG_DEBUG_IO("clocks %i while in %s",
                cmd->cmd.stableclocks->num_cycles,
                tap_state_name(tap_get_state()));
 }
@@ -565,9 +608,6 @@ static void ftdi_execute_stableclocks(struct jtag_command *cmd)
 static void ftdi_execute_command(struct jtag_command *cmd)
 {
        switch (cmd->type) {
-               case JTAG_RESET:
-                       ftdi_execute_reset(cmd);
-                       break;
                case JTAG_RUNTEST:
                        ftdi_execute_runtest(cmd);
                        break;
@@ -624,9 +664,14 @@ static int ftdi_initialize(void)
        else
                LOG_DEBUG("ftdi interface using shortest path jtag state transitions");
 
+       if (!ftdi_vid[0] && !ftdi_pid[0]) {
+               LOG_ERROR("Please specify ftdi vid_pid");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
        for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
                mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
-                               ftdi_serial, ftdi_channel);
+                               adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel);
                if (mpsse_ctx)
                        break;
        }
@@ -653,12 +698,7 @@ static int ftdi_initialize(void)
 
        mpsse_loopback_config(mpsse_ctx, false);
 
-       freq = mpsse_set_frequency(mpsse_ctx, jtag_get_speed_khz() * 1000);
-
-       if (swd_mode)
-               ftdi_swd_switch_seq(NULL, JTAG_TO_SWD);
-       else
-               ftdi_swd_switch_seq(NULL, SWD_TO_JTAG);
+       freq = mpsse_set_frequency(mpsse_ctx, adapter_get_speed_khz() * 1000);
 
        return mpsse_flush(mpsse_ctx);
 }
@@ -667,30 +707,28 @@ static int ftdi_quit(void)
 {
        mpsse_close(mpsse_ctx);
 
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(ftdi_handle_device_desc_command)
-{
-       if (CMD_ARGC == 1) {
-               if (ftdi_device_desc)
-                       free(ftdi_device_desc);
-               ftdi_device_desc = strdup(CMD_ARGV[0]);
-       } else {
-               LOG_ERROR("expected exactly one argument to ftdi_device_desc <description>");
+       struct signal *sig = signals;
+       while (sig) {
+               struct signal *next = sig->next;
+               free((void *)sig->name);
+               free(sig);
+               sig = next;
        }
 
+       free(ftdi_device_desc);
+
+       free(swd_cmd_queue);
+
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(ftdi_handle_serial_command)
+COMMAND_HANDLER(ftdi_handle_device_desc_command)
 {
        if (CMD_ARGC == 1) {
-               if (ftdi_serial)
-                       free(ftdi_serial);
-               ftdi_serial = strdup(CMD_ARGV[0]);
+               free(ftdi_device_desc);
+               ftdi_device_desc = strdup(CMD_ARGV[0]);
        } else {
-               return ERROR_COMMAND_SYNTAX_ERROR;
+               LOG_ERROR("expected exactly one argument to ftdi device_desc <description>");
        }
 
        return ERROR_OK;
@@ -724,6 +762,8 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
 
        bool invert_data = false;
        uint16_t data_mask = 0;
+       bool invert_input = false;
+       uint16_t input_mask = 0;
        bool invert_oe = false;
        uint16_t oe_mask = 0;
        for (unsigned i = 1; i < CMD_ARGC; i += 2) {
@@ -733,6 +773,12 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
                } else if (strcmp("-ndata", CMD_ARGV[i]) == 0) {
                        invert_data = true;
                        COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], data_mask);
+               } else if (strcmp("-input", CMD_ARGV[i]) == 0) {
+                       invert_input = false;
+                       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], input_mask);
+               } else if (strcmp("-ninput", CMD_ARGV[i]) == 0) {
+                       invert_input = true;
+                       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], input_mask);
                } else if (strcmp("-oe", CMD_ARGV[i]) == 0) {
                        invert_oe = false;
                        COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask);
@@ -741,15 +787,19 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
                        COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask);
                } else if (!strcmp("-alias", CMD_ARGV[i]) ||
                           !strcmp("-nalias", CMD_ARGV[i])) {
-                       if (!strcmp("-nalias", CMD_ARGV[i]))
+                       if (!strcmp("-nalias", CMD_ARGV[i])) {
                                invert_data = true;
+                               invert_input = true;
+                       }
                        struct signal *sig = find_signal_by_name(CMD_ARGV[i + 1]);
                        if (!sig) {
                                LOG_ERROR("signal %s is not defined", CMD_ARGV[i + 1]);
                                return ERROR_FAIL;
                        }
                        data_mask = sig->data_mask;
+                       input_mask = sig->input_mask;
                        oe_mask = sig->oe_mask;
+                       invert_input ^= sig->invert_input;
                        invert_oe = sig->invert_oe;
                        invert_data ^= sig->invert_data;
                } else {
@@ -769,6 +819,8 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
 
        sig->invert_data = invert_data;
        sig->data_mask = data_mask;
+       sig->invert_input = invert_input;
+       sig->input_mask = input_mask;
        sig->invert_oe = invert_oe;
        sig->oe_mask = oe_mask;
 
@@ -797,6 +849,7 @@ COMMAND_HANDLER(ftdi_handle_set_signal_command)
                        ftdi_set_signal(sig, *CMD_ARGV[1]);
                        break;
                }
+               /* fallthrough */
        default:
                LOG_ERROR("unknown signal level '%s', use 0, 1 or z", CMD_ARGV[1]);
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -805,15 +858,37 @@ COMMAND_HANDLER(ftdi_handle_set_signal_command)
        return mpsse_flush(mpsse_ctx);
 }
 
+COMMAND_HANDLER(ftdi_handle_get_signal_command)
+{
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct signal *sig;
+       uint16_t sig_data = 0;
+       sig = find_signal_by_name(CMD_ARGV[0]);
+       if (!sig) {
+               LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]);
+               return ERROR_FAIL;
+       }
+
+       int ret = ftdi_get_signal(sig, &sig_data);
+       if (ret != ERROR_OK)
+               return ret;
+
+       LOG_USER("Signal %s = %#06x", sig->name, sig_data);
+
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(ftdi_handle_vid_pid_command)
 {
        if (CMD_ARGC > MAX_USB_IDS * 2) {
-               LOG_WARNING("ignoring extra IDs in ftdi_vid_pid "
+               LOG_WARNING("ignoring extra IDs in ftdi vid_pid "
                        "(maximum is %d pairs)", MAX_USB_IDS);
                CMD_ARGC = MAX_USB_IDS * 2;
        }
        if (CMD_ARGC < 2 || (CMD_ARGC & 1)) {
-               LOG_WARNING("incomplete ftdi_vid_pid configuration directive");
+               LOG_WARNING("incomplete ftdi vid_pid configuration directive");
                if (CMD_ARGC < 2)
                        return ERROR_COMMAND_SYNTAX_ERROR;
                /* remove the incomplete trailing id */
@@ -828,37 +903,53 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command)
 
        /*
         * Explicitly terminate, in case there are multiples instances of
-        * ftdi_vid_pid.
+        * ftdi vid_pid.
         */
        ftdi_vid[i >> 1] = ftdi_pid[i >> 1] = 0;
 
        return ERROR_OK;
 }
 
-static const struct command_registration ftdi_command_handlers[] = {
+COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command)
+{
+       struct jim_nvp *n;
+       static const struct jim_nvp nvp_ftdi_jtag_modes[] = {
+               { .name = "rising", .value = JTAG_MODE },
+               { .name = "falling", .value = JTAG_MODE_ALT },
+               { .name = NULL, .value = -1 },
+       };
+
+       if (CMD_ARGC > 0) {
+               n = jim_nvp_name2value_simple(nvp_ftdi_jtag_modes, CMD_ARGV[0]);
+               if (!n->name)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               ftdi_jtag_mode = n->value;
+
+       }
+
+       n = jim_nvp_value2name_simple(nvp_ftdi_jtag_modes, ftdi_jtag_mode);
+       command_print(CMD, "ftdi samples TDO on %s edge of TCK", n->name);
+
+       return ERROR_OK;
+}
+
+static const struct command_registration ftdi_subcommand_handlers[] = {
        {
-               .name = "ftdi_device_desc",
+               .name = "device_desc",
                .handler = &ftdi_handle_device_desc_command,
                .mode = COMMAND_CONFIG,
                .help = "set the USB device description of the FTDI device",
                .usage = "description_string",
        },
        {
-               .name = "ftdi_serial",
-               .handler = &ftdi_handle_serial_command,
-               .mode = COMMAND_CONFIG,
-               .help = "set the serial number of the FTDI device",
-               .usage = "serial_string",
-       },
-       {
-               .name = "ftdi_channel",
+               .name = "channel",
                .handler = &ftdi_handle_channel_command,
                .mode = COMMAND_CONFIG,
                .help = "set the channel of the FTDI device that is used as JTAG",
                .usage = "(0-3)",
        },
        {
-               .name = "ftdi_layout_init",
+               .name = "layout_init",
                .handler = &ftdi_handle_layout_init_command,
                .mode = COMMAND_CONFIG,
                .help = "initialize the FTDI GPIO signals used "
@@ -866,7 +957,7 @@ static const struct command_registration ftdi_command_handlers[] = {
                .usage = "data direction",
        },
        {
-               .name = "ftdi_layout_signal",
+               .name = "layout_signal",
                .handler = &ftdi_handle_layout_signal_command,
                .mode = COMMAND_ANY,
                .help = "define a signal controlled by one or more FTDI GPIO as data "
@@ -874,18 +965,45 @@ static const struct command_registration ftdi_command_handlers[] = {
                .usage = "name [-data mask|-ndata mask] [-oe mask|-noe mask] [-alias|-nalias name]",
        },
        {
-               .name = "ftdi_set_signal",
+               .name = "set_signal",
                .handler = &ftdi_handle_set_signal_command,
                .mode = COMMAND_EXEC,
                .help = "control a layout-specific signal",
                .usage = "name (1|0|z)",
        },
        {
-               .name = "ftdi_vid_pid",
+               .name = "get_signal",
+               .handler = &ftdi_handle_get_signal_command,
+               .mode = COMMAND_EXEC,
+               .help = "read the value of a layout-specific signal",
+               .usage = "name",
+       },
+       {
+               .name = "vid_pid",
                .handler = &ftdi_handle_vid_pid_command,
                .mode = COMMAND_CONFIG,
                .help = "the vendor ID and product ID of the FTDI device",
-               .usage = "(vid pid)* ",
+               .usage = "(vid pid)*",
+       },
+       {
+               .name = "tdo_sample_edge",
+               .handler = &ftdi_handle_tdo_sample_edge_command,
+               .mode = COMMAND_ANY,
+               .help = "set which TCK clock edge is used for sampling TDO "
+                       "- default is rising-edge (Setting to falling-edge may "
+                       "allow signalling speed increase)",
+               .usage = "(rising|falling)",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration ftdi_command_handlers[] = {
+       {
+               .name = "ftdi",
+               .mode = COMMAND_ANY,
+               .help = "perform ftdi management",
+               .chain = ftdi_subcommand_handlers,
+               .usage = "",
        },
        COMMAND_REGISTRATION_DONE
 };
@@ -929,29 +1047,39 @@ static int ftdi_swd_init(void)
        swd_cmd_queue_alloced = 10;
        swd_cmd_queue = malloc(swd_cmd_queue_alloced * sizeof(*swd_cmd_queue));
 
-       return swd_cmd_queue != NULL ? ERROR_OK : ERROR_FAIL;
+       return swd_cmd_queue ? ERROR_OK : ERROR_FAIL;
 }
 
 static void ftdi_swd_swdio_en(bool enable)
 {
        struct signal *oe = find_signal_by_name("SWDIO_OE");
-       if (oe)
-               ftdi_set_signal(oe, enable ? '1' : '0');
+       if (oe) {
+               if (oe->data_mask)
+                       ftdi_set_signal(oe, enable ? '1' : '0');
+               else {
+                       /* Sets TDI/DO pin to input during rx when both pins are connected
+                          to SWDIO */
+                       if (enable)
+                               direction |= jtag_direction_init & 0x0002U;
+                       else
+                               direction &= ~0x0002U;
+                       mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
+               }
+       }
 }
 
 /**
  * Flush the MPSSE queue and process the SWD transaction queue
- * @param dap
  * @return
  */
-static int ftdi_swd_run_queue(struct adiv5_dap *dap)
+static int ftdi_swd_run_queue(void)
 {
-       LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
+       LOG_DEBUG_IO("Executing %zu queued transactions", swd_cmd_queue_length);
        int retval;
        struct signal *led = find_signal_by_name("LED");
 
        if (queued_retval != ERROR_OK) {
-               LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
+               LOG_DEBUG_IO("Skipping due to previous errors: %d", queued_retval);
                goto skip;
        }
 
@@ -970,21 +1098,25 @@ static int ftdi_swd_run_queue(struct adiv5_dap *dap)
        }
 
        for (size_t i = 0; i < swd_cmd_queue_length; i++) {
-               int ack = buf_get_u32(&swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3);
+               int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3);
 
-               LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
+               /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
+               bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd);
+
+               LOG_DEBUG_IO("%s%s %s %s reg %X = %08"PRIx32,
+                               check_ack ? "" : "ack ignored ",
                                ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
-                               swd_cmd_queue[i].cmd & SWD_CMD_APnDP ? "AP" : "DP",
-                               swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write",
+                               swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP",
+                               swd_cmd_queue[i].cmd & SWD_CMD_RNW ? "read" : "write",
                                (swd_cmd_queue[i].cmd & SWD_CMD_A32) >> 1,
                                buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn,
-                                               1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RnW ? 0 : 1), 32));
+                                               1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RNW ? 0 : 1), 32));
 
-               if (ack != SWD_ACK_OK) {
-                       queued_retval = ack;
+               if (ack != SWD_ACK_OK && check_ack) {
+                       queued_retval = swd_ack_to_error_code(ack);
                        goto skip;
 
-               } else if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) {
+               } else if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) {
                        uint32_t data = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3, 32);
                        int parity = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 32, 1);
 
@@ -994,7 +1126,7 @@ static int ftdi_swd_run_queue(struct adiv5_dap *dap)
                                goto skip;
                        }
 
-                       if (swd_cmd_queue[i].dst != NULL)
+                       if (swd_cmd_queue[i].dst)
                                *swd_cmd_queue[i].dst = data;
                }
        }
@@ -1011,15 +1143,15 @@ skip:
        return retval;
 }
 
-static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
+static void ftdi_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
 {
        if (swd_cmd_queue_length >= swd_cmd_queue_alloced) {
                /* Not enough room in the queue. Run the queue and increase its size for next time.
                 * Note that it's not possible to avoid running the queue here, because mpsse contains
                 * pointers into the queue which may be invalid after the realloc. */
-               queued_retval = ftdi_swd_run_queue(dap);
+               queued_retval = ftdi_swd_run_queue();
                struct swd_cmd_queue_entry *q = realloc(swd_cmd_queue, swd_cmd_queue_alloced * 2 * sizeof(*swd_cmd_queue));
-               if (q != NULL) {
+               if (q) {
                        swd_cmd_queue = q;
                        swd_cmd_queue_alloced *= 2;
                        LOG_DEBUG("Increased SWD command queue to %zu elements", swd_cmd_queue_alloced);
@@ -1034,7 +1166,7 @@ static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst
 
        mpsse_clock_data_out(mpsse_ctx, &swd_cmd_queue[i].cmd, 0, 8, SWD_MODE);
 
-       if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) {
+       if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) {
                /* Queue a read transaction */
                swd_cmd_queue[i].dst = dst;
 
@@ -1059,46 +1191,61 @@ static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst
        }
 
        /* Insert idle cycles after AP accesses to avoid WAIT */
-       if (cmd & SWD_CMD_APnDP)
-               mpsse_clock_data_out(mpsse_ctx, NULL, 0, dap->memaccess_tck, SWD_MODE);
-
-}
+       if (cmd & SWD_CMD_APNDP)
+               mpsse_clock_data_out(mpsse_ctx, NULL, 0, ap_delay_clk, SWD_MODE);
 
-static void ftdi_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
-{
-       assert(cmd & SWD_CMD_RnW);
-       ftdi_swd_queue_cmd(dap, cmd, value, 0);
 }
 
-static void ftdi_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
+static void ftdi_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
 {
-       assert(!(cmd & SWD_CMD_RnW));
-       ftdi_swd_queue_cmd(dap, cmd, NULL, value);
+       assert(cmd & SWD_CMD_RNW);
+       ftdi_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
 }
 
-static int_least32_t ftdi_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+static void ftdi_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
 {
-       if (hz > 0)
-               freq = mpsse_set_frequency(mpsse_ctx, hz);
-
-       return freq;
+       assert(!(cmd & SWD_CMD_RNW));
+       ftdi_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
 }
 
-static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
+static int ftdi_swd_switch_seq(enum swd_special_seq seq)
 {
        switch (seq) {
        case LINE_RESET:
                LOG_DEBUG("SWD line reset");
+               ftdi_swd_swdio_en(true);
                mpsse_clock_data_out(mpsse_ctx, swd_seq_line_reset, 0, swd_seq_line_reset_len, SWD_MODE);
                break;
        case JTAG_TO_SWD:
                LOG_DEBUG("JTAG-to-SWD");
+               ftdi_swd_swdio_en(true);
                mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE);
                break;
+       case JTAG_TO_DORMANT:
+               LOG_DEBUG("JTAG-to-DORMANT");
+               ftdi_swd_swdio_en(true);
+               mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len, SWD_MODE);
+               break;
        case SWD_TO_JTAG:
                LOG_DEBUG("SWD-to-JTAG");
+               ftdi_swd_swdio_en(true);
                mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE);
                break;
+       case SWD_TO_DORMANT:
+               LOG_DEBUG("SWD-to-DORMANT");
+               ftdi_swd_swdio_en(true);
+               mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len, SWD_MODE);
+               break;
+       case DORMANT_TO_SWD:
+               LOG_DEBUG("DORMANT-to-SWD");
+               ftdi_swd_swdio_en(true);
+               mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len, SWD_MODE);
+               break;
+       case DORMANT_TO_JTAG:
+               LOG_DEBUG("DORMANT-to-JTAG");
+               ftdi_swd_swdio_en(true);
+               mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len, SWD_MODE);
+               break;
        default:
                LOG_ERROR("Sequence %d not supported", seq);
                return ERROR_FAIL;
@@ -1109,7 +1256,6 @@ static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
 
 static const struct swd_driver ftdi_swd = {
        .init = ftdi_swd_init,
-       .frequency = ftdi_swd_frequency,
        .switch_seq = ftdi_swd_switch_seq,
        .read_reg = ftdi_swd_read_reg,
        .write_reg = ftdi_swd_write_reg,
@@ -1118,17 +1264,23 @@ static const struct swd_driver ftdi_swd = {
 
 static const char * const ftdi_transports[] = { "jtag", "swd", NULL };
 
-struct jtag_interface ftdi_interface = {
-       .name = "ftdi",
+static struct jtag_interface ftdi_interface = {
        .supported = DEBUG_CAP_TMS_SEQ,
-       .commands = ftdi_command_handlers,
+       .execute_queue = ftdi_execute_queue,
+};
+
+struct adapter_driver ftdi_adapter_driver = {
+       .name = "ftdi",
        .transports = ftdi_transports,
-       .swd = &ftdi_swd,
+       .commands = ftdi_command_handlers,
 
        .init = ftdi_initialize,
        .quit = ftdi_quit,
+       .reset = ftdi_reset,
        .speed = ftdi_speed,
-       .speed_div = ftdi_speed_div,
        .khz = ftdi_khz,
-       .execute_queue = ftdi_execute_queue,
+       .speed_div = ftdi_speed_div,
+
+       .jtag_ops = &ftdi_interface,
+       .swd_ops = &ftdi_swd,
 };