jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / adi_v5_jtag.c
index 0a374bea82d500d9134141d718ca3fd9881bf5ef..8d54a50fb0b3482f4278777d045f20715306ddc6 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2006 by Magnus Lundin
  *   lundin@mlu.mine.nu
  *
  *   Copyright (C) 2009-2010 by David Brownell
  *
- *   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
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   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.,
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *   Copyright (C) 2020-2021, Ampere Computing LLC                              *
  ***************************************************************************/
 
 /**
  * @file
  * This file implements JTAG transport support for cores implementing
- the ARM Debug Interface version 5 (ADIv5).
+ the ARM Debug Interface version 5 (ADIv5) and version 6 (ADIv6).
  */
 
 #ifdef HAVE_CONFIG_H
 #include "arm.h"
 #include "arm_adi_v5.h"
 #include <helper/time_support.h>
+#include <helper/list.h>
+#include <jtag/swd.h>
 
+/*#define DEBUG_WAIT*/
 
 /* JTAG instructions/registers for JTAG-DP and SWJ-DP */
-#define JTAG_DP_ABORT          0x8
-#define JTAG_DP_DPACC          0xA
-#define JTAG_DP_APACC          0xB
-#define JTAG_DP_IDCODE         0xE
+#define JTAG_DP_ABORT          0xF8
+#define JTAG_DP_DPACC          0xFA
+#define JTAG_DP_APACC          0xFB
+#define JTAG_DP_IDCODE         0xFE
 
 /* three-bit ACK values for DPACC and APACC reads */
-#define JTAG_ACK_OK_FAULT      0x2
-#define JTAG_ACK_WAIT          0x1
+#define JTAG_ACK_WAIT       0x1     /* ADIv5 and ADIv6 */
+#define JTAG_ACK_OK_FAULT   0x2     /* ADIv5 */
+#define JTAG_ACK_FAULT      0x2     /* ADIv6 */
+#define JTAG_ACK_OK         0x4     /* ADIV6 */
+
+static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack);
+
+#ifdef DEBUG_WAIT
+static const char *dap_reg_name(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr)
+{
+       char *reg_name = "UNK";
+
+       if (instr == JTAG_DP_DPACC) {
+               switch (reg_addr) {
+               case DP_ABORT:
+                       reg_name =  "ABORT";
+                       break;
+               case DP_CTRL_STAT:
+                       reg_name =  "CTRL/STAT";
+                       break;
+               case DP_SELECT:
+                       reg_name = "SELECT";
+                       break;
+               case DP_RDBUFF:
+                       reg_name =  "RDBUFF";
+                       break;
+               case DP_DLCR:
+                       reg_name =  "DLCR";
+                       break;
+               default:
+                       reg_name = "UNK";
+                       break;
+               }
+       }
+
+       if (instr == JTAG_DP_APACC) {
+               if (reg_addr == MEM_AP_REG_CSW(dap))
+                       reg_name = "CSW";
+               else if (reg_addr == MEM_AP_REG_TAR(dap))
+                       reg_name = "TAR";
+               else if (reg_addr == MEM_AP_REG_TAR64(dap))
+                       reg_name = "TAR64";
+               else if (reg_addr == MEM_AP_REG_DRW(dap))
+                       reg_name = "DRW";
+               else if (reg_addr == MEM_AP_REG_BD0(dap))
+                       reg_name = "BD0";
+               else if (reg_addr == MEM_AP_REG_BD1(dap))
+                       reg_name = "BD1";
+               else if (reg_addr == MEM_AP_REG_BD2(dap))
+                       reg_name = "BD2";
+               else if (reg_addr == MEM_AP_REG_BD3(dap))
+                       reg_name = "BD3";
+               else if (reg_addr == MEM_AP_REG_CFG(dap))
+                       reg_name = "CFG";
+               else if (reg_addr == MEM_AP_REG_BASE(dap))
+                       reg_name = "BASE";
+               else if (reg_addr == MEM_AP_REG_BASE64(dap))
+                       reg_name = "BASE64";
+               else if (reg_addr == AP_REG_IDR(dap))
+                       reg_name = "IDR";
+               else
+                       reg_name = "UNK";
+       }
+
+       return reg_name;
+}
+#endif
+
+struct dap_cmd {
+       struct list_head lh;
+       uint8_t instr;
+       uint16_t reg_addr;
+       uint8_t rnw;
+       uint8_t *invalue;
+       uint8_t ack;
+       uint32_t memaccess_tck;
+       uint64_t dp_select;
+
+       struct scan_field fields[2];
+       uint8_t out_addr_buf;
+       uint8_t invalue_buf[4];
+       uint8_t outvalue_buf[4];
+};
+
+#define MAX_DAP_COMMAND_NUM 65536
+
+struct dap_cmd_pool {
+       struct list_head lh;
+       struct dap_cmd cmd;
+};
+
+static void log_dap_cmd(struct adiv5_dap *dap, const char *header, struct dap_cmd *el)
+{
+#ifdef DEBUG_WAIT
+       const char *ack;
+       switch (el->ack) {
+       case JTAG_ACK_WAIT:         /* ADIv5 and ADIv6 */
+               ack = "WAIT";
+               break;
+       case JTAG_ACK_OK_FAULT:     /* ADIv5, same value as JTAG_ACK_FAULT */
+       /* case JTAG_ACK_FAULT: */  /* ADIv6 */
+               if (is_adiv6(dap))
+                       ack = "FAULT";
+               else
+                       ack = "OK";
+               break;
+       case JTAG_ACK_OK:           /* ADIv6 */
+               if (is_adiv6(dap)) {
+                       ack = "OK";
+                       break;
+               }
+               /* fall-through */
+       default:
+               ack = "INVAL";
+               break;
+       }
+       LOG_DEBUG("%s: %2s %6s %5s 0x%08x 0x%08x %2s", header,
+               el->instr == JTAG_DP_APACC ? "AP" : "DP",
+               dap_reg_name(dap, el->instr, el->reg_addr),
+               el->rnw == DPAP_READ ? "READ" : "WRITE",
+               buf_get_u32(el->outvalue_buf, 0, 32),
+               buf_get_u32(el->invalue, 0, 32),
+               ack);
+#endif
+}
+
+static int jtag_limit_queue_size(struct adiv5_dap *dap)
+{
+       if (dap->cmd_pool_size < MAX_DAP_COMMAND_NUM)
+               return ERROR_OK;
+
+       return dap_run(dap);
+}
+
+static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr,
+               uint16_t reg_addr, uint8_t rnw,
+               uint8_t *outvalue, uint8_t *invalue,
+               uint32_t memaccess_tck)
+{
+
+       struct dap_cmd_pool *pool = NULL;
+
+       if (list_empty(&dap->cmd_pool)) {
+               pool = calloc(1, sizeof(struct dap_cmd_pool));
+               if (!pool)
+                       return NULL;
+       } else {
+               pool = list_first_entry(&dap->cmd_pool, struct dap_cmd_pool, lh);
+               list_del(&pool->lh);
+       }
+
+       INIT_LIST_HEAD(&pool->lh);
+       dap->cmd_pool_size++;
+
+       struct dap_cmd *cmd = &pool->cmd;
+       INIT_LIST_HEAD(&cmd->lh);
+       cmd->instr = instr;
+       cmd->reg_addr = reg_addr;
+       cmd->rnw = rnw;
+       if (outvalue)
+               memcpy(cmd->outvalue_buf, outvalue, 4);
+       cmd->invalue = (invalue) ? invalue : cmd->invalue_buf;
+       cmd->memaccess_tck = memaccess_tck;
+
+       return cmd;
+}
+
+static void dap_cmd_release(struct adiv5_dap *dap, struct dap_cmd *cmd)
+{
+       struct dap_cmd_pool *pool = container_of(cmd, struct dap_cmd_pool, cmd);
+       if (dap->cmd_pool_size > MAX_DAP_COMMAND_NUM)
+               free(pool);
+       else
+               list_add(&pool->lh, &dap->cmd_pool);
+
+       dap->cmd_pool_size--;
+}
+
+static void flush_journal(struct adiv5_dap *dap, struct list_head *lh)
+{
+       struct dap_cmd *el, *tmp;
+
+       list_for_each_entry_safe(el, tmp, lh, lh) {
+               list_del(&el->lh);
+               dap_cmd_release(dap, el);
+       }
+}
+
+static void jtag_quit(struct adiv5_dap *dap)
+{
+       struct dap_cmd_pool *el, *tmp;
+       struct list_head *lh = &dap->cmd_pool;
+
+       list_for_each_entry_safe(el, tmp, lh, lh) {
+               list_del(&el->lh);
+               free(el);
+       }
+}
 
 /***************************************************************************
  *
  *
 ***************************************************************************/
 
+static int adi_jtag_dp_scan_cmd(struct adiv5_dap *dap, struct dap_cmd *cmd, uint8_t *ack)
+{
+       struct jtag_tap *tap = dap->tap;
+       int retval;
+
+       retval = arm_jtag_set_instr(tap, cmd->instr, NULL, TAP_IDLE);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Scan out a read or write operation using some DP or AP register.
+        * For APACC access with any sticky error flag set, this is discarded.
+        */
+       cmd->fields[0].num_bits = 3;
+       buf_set_u32(&cmd->out_addr_buf, 0, 3, ((cmd->reg_addr >> 1) & 0x6) | (cmd->rnw & 0x1));
+       cmd->fields[0].out_value = &cmd->out_addr_buf;
+       cmd->fields[0].in_value = (ack) ? ack : &cmd->ack;
+
+       /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not
+        * complete; data we write is discarded, data we read is unpredictable.
+        * When overrun detect is active, STICKYORUN is set.
+        */
+
+       cmd->fields[1].num_bits = 32;
+       cmd->fields[1].out_value = cmd->outvalue_buf;
+       cmd->fields[1].in_value = cmd->invalue;
+
+       jtag_add_dr_scan(tap, 2, cmd->fields, TAP_IDLE);
+
+       /* Add specified number of tck clocks after starting AP register
+        * access or memory bus access, giving the hardware time to complete
+        * the access.
+        * They provide more time for the (MEM) AP to complete the read ...
+        * See "Minimum Response Time" for JTAG-DP, in the ADIv5/ADIv6 spec.
+        */
+       if (cmd->instr == JTAG_DP_APACC && cmd->memaccess_tck != 0)
+               jtag_add_runtest(cmd->memaccess_tck, TAP_IDLE);
+
+       return ERROR_OK;
+}
+
+static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd, uint8_t *ack)
+{
+       int retval;
+
+       retval = adi_jtag_dp_scan_cmd(dap, cmd, ack);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return jtag_execute_queue();
+}
+
 /**
  * Scan DPACC or APACC using target ordered uint8_t buffers.  No endianness
- * conversions are performed.  See section 4.4.3 of the ADIv5 spec, which
+ * conversions are performed.  See section 4.4.3 of the ADIv5/ADIv6 spec, which
  * discusses operations which access these registers.
  *
- * Note that only one scan is performed.  If RnW is set, a separate scan
+ * Note that only one scan is performed.  If rnw is set, a separate scan
  * will be needed to collect the data which was read; the "invalue" collects
  * the posted result of a preceding operation, not the current one.
  *
  * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access)
  * @param reg_addr two significant bits; A[3:2]; for APACC access, the
  *     SELECT register has more addressing bits.
- * @param RnW false iff outvalue will be written to the DP or AP
+ * @param rnw false iff outvalue will be written to the DP or AP
  * @param outvalue points to a 32-bit (little-endian) integer
  * @param invalue NULL, or points to a 32-bit (little-endian) integer
  * @param ack points to where the three bit JTAG_ACK_* code will be stored
+ * @param memaccess_tck number of idle cycles to add after AP access
  */
 
-/* FIXME don't export ... this is a temporary workaround for the
- * mem_ap_read_buf_u32() mess, until it's no longer JTAG-specific.
- */
-int adi_jtag_dp_scan(struct adiv5_dap *dap,
-               uint8_t instr, uint8_t reg_addr, uint8_t RnW,
-               uint8_t *outvalue, uint8_t *invalue, uint8_t *ack)
+static int adi_jtag_dp_scan(struct adiv5_dap *dap,
+               uint8_t instr, uint16_t reg_addr, uint8_t rnw,
+               uint8_t *outvalue, uint8_t *invalue,
+               uint32_t memaccess_tck, uint8_t *ack)
 {
-       struct arm_jtag *jtag_info = dap->jtag_info;
-       struct scan_field fields[2];
-       uint8_t out_addr_buf;
-
-       arm_jtag_set_instr(jtag_info, instr, NULL, TAP_IDLE);
-
-       /* Scan out a read or write operation using some DP or AP register.
-        * For APACC access with any sticky error flag set, this is discarded.
-        */
-       fields[0].num_bits = 3;
-       buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
-       fields[0].out_value = &out_addr_buf;
-       fields[0].in_value = ack;
-
-       /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not
-        * complete; data we write is discarded, data we read is unpredictable.
-        * When overrun detect is active, STICKYORUN is set.
-        */
-
-       fields[1].num_bits = 32;
-       fields[1].out_value = outvalue;
-       fields[1].in_value = invalue;
+       struct dap_cmd *cmd;
+       int retval;
 
-       jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
+       cmd = dap_cmd_new(dap, instr, reg_addr, rnw, outvalue, invalue, memaccess_tck);
+       if (cmd)
+               cmd->dp_select = dap->select;
+       else
+               return ERROR_JTAG_DEVICE_ERROR;
 
-       /* Add specified number of tck clocks after starting memory bus
-        * access, giving the hardware time to complete the access.
-        * They provide more time for the (MEM) AP to complete the read ...
-        * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec.
-        */
-       if ((instr == JTAG_DP_APACC)
-                       && ((reg_addr == AP_REG_DRW)
-                               || ((reg_addr & 0xF0) == AP_REG_BD0))
-                       && (dap->memaccess_tck != 0))
-               jtag_add_runtest(dap->memaccess_tck,
-                               TAP_IDLE);
+       retval = adi_jtag_dp_scan_cmd(dap, cmd, ack);
+       if (retval == ERROR_OK)
+               list_add_tail(&cmd->lh, &dap->cmd_journal);
 
-       return ERROR_OK;
+       return retval;
 }
 
 /**
@@ -130,16 +344,39 @@ int adi_jtag_dp_scan(struct adiv5_dap *dap,
  * must be different).
  */
 static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap,
-               uint8_t instr, uint8_t reg_addr, uint8_t RnW,
-               uint32_t outvalue, uint32_t *invalue, uint8_t *ack)
+               uint8_t instr, uint16_t reg_addr, uint8_t rnw,
+               uint32_t outvalue, uint32_t *invalue,
+               uint32_t memaccess_tck, uint8_t *ack)
 {
        uint8_t out_value_buf[4];
        int retval;
+       uint64_t sel = (reg_addr >> 4) & DP_SELECT_DPBANK;
+
+       /* No need to change SELECT or RDBUFF as they are not banked */
+       if (instr == JTAG_DP_DPACC && reg_addr != DP_SELECT && reg_addr != DP_RDBUFF
+                       && (!dap->select_valid || sel != (dap->select & DP_SELECT_DPBANK))) {
+               /* Use the AP part of dap->select regardless of dap->select_valid:
+                * if !dap->select_valid
+                * dap->select contains a speculative value likely going to be used
+                * in the following swd_queue_ap_bankselect() */
+               sel |= dap->select & SELECT_AP_MASK;
+
+               LOG_DEBUG_IO("DP BANK SELECT: %" PRIx32, (uint32_t)sel);
+
+               buf_set_u32(out_value_buf, 0, 32, (uint32_t)sel);
 
+               retval = adi_jtag_dp_scan(dap, JTAG_DP_DPACC,
+                               DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0, NULL);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               dap->select = sel;
+               dap->select_valid = true;
+       }
        buf_set_u32(out_value_buf, 0, 32, outvalue);
 
-       retval = adi_jtag_dp_scan(dap, instr, reg_addr, RnW,
-                       out_value_buf, (uint8_t *)invalue, ack);
+       retval = adi_jtag_dp_scan(dap, instr, reg_addr, rnw,
+                       out_value_buf, (uint8_t *)invalue, memaccess_tck, ack);
        if (retval != ERROR_OK)
                return retval;
 
@@ -150,330 +387,523 @@ static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap,
        return retval;
 }
 
-/**
- * Utility to write AP registers.
- */
-static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap,
-               uint8_t reg_addr, uint8_t *outvalue)
+static int adi_jtag_finish_read(struct adiv5_dap *dap)
 {
-       return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE,
-                       outvalue, NULL, NULL);
+       int retval = ERROR_OK;
+
+       if (dap->last_read) {
+               retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
+                               DP_RDBUFF, DPAP_READ, 0, dap->last_read, 0, NULL);
+               dap->last_read = NULL;
+       }
+
+       return retval;
 }
 
 static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *dap,
-               uint8_t instr, uint8_t reg_addr, uint8_t RnW,
-               uint32_t outvalue, uint32_t *invalue)
+               uint8_t instr, uint16_t reg_addr, uint8_t rnw,
+               uint32_t outvalue, uint32_t *invalue, uint32_t memaccess_tck)
 {
        int retval;
 
        /* Issue the read or write */
        retval = adi_jtag_dp_scan_u32(dap, instr, reg_addr,
-                       RnW, outvalue, NULL, NULL);
+                       rnw, outvalue, NULL, memaccess_tck, NULL);
        if (retval != ERROR_OK)
                return retval;
 
        /* For reads,  collect posted value; RDBUFF has no other effect.
         * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK".
         */
-       if ((RnW == DPAP_READ) && (invalue != NULL))
+       if ((rnw == DPAP_READ) && (invalue)) {
                retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
-                               DP_RDBUFF, DPAP_READ, 0, invalue, &dap->ack);
-       return retval;
+                               DP_RDBUFF, DPAP_READ, 0, invalue, 0, NULL);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return jtag_execute_queue();
 }
 
-static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
+static int jtagdp_overrun_check(struct adiv5_dap *dap)
 {
        int retval;
-       uint32_t ctrlstat;
+       struct dap_cmd *el, *tmp, *prev = NULL;
+       int found_wait = 0;
+       int64_t time_now;
+       LIST_HEAD(replay_list);
 
-       /* too expensive to call keep_alive() here */
-
-#if 0
-       /* Danger!!!! BROKEN!!!! */
-       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                       DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-       /* Danger!!!! BROKEN!!!! Why will jtag_execute_queue() fail here????
-       R956 introduced the check on return value here and now Michael Schwingen reports
-       that this code no longer works....
-
-       https://lists.berlios.de/pipermail/openocd-development/2008-September/003107.html
-       */
-       if ((retval = jtag_execute_queue()) != ERROR_OK)
-       {
-               LOG_ERROR("BUG: Why does this fail the first time????");
+       /* make sure all queued transactions are complete */
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               goto done;
+
+       /* skip all completed transactions up to the first WAIT */
+       list_for_each_entry(el, &dap->cmd_journal, lh) {
+               /*
+                * JTAG_ACK_OK_FAULT (ADIv5) and JTAG_ACK_FAULT (ADIv6) are equal so
+                * the following statement is checking to see if an acknowledgment of
+                * OK or FAULT is generated for ADIv5 or ADIv6
+                */
+               if (el->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && el->ack == JTAG_ACK_OK)) {
+                       log_dap_cmd(dap, "LOG", el);
+               } else if (el->ack == JTAG_ACK_WAIT) {
+                       found_wait = 1;
+                       break;
+               } else {
+                       LOG_ERROR("Invalid ACK (%1x) in DAP response", el->ack);
+                       log_dap_cmd(dap, "ERR", el);
+                       retval = ERROR_JTAG_DEVICE_ERROR;
+                       goto done;
+               }
        }
-       /* Why??? second time it works??? */
-#endif
 
-       /* Post CTRL/STAT read; discard any previous posted read value
-        * but collect its ACK status.
+       /*
+        * If we found a stalled transaction and a previous transaction
+        * exists, check if it's a READ access.
         */
-       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                       DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-       if ((retval = jtag_execute_queue()) != ERROR_OK)
-               return retval;
+       if (found_wait && el != list_first_entry(&dap->cmd_journal, struct dap_cmd, lh)) {
+               prev = list_entry(el->lh.prev, struct dap_cmd, lh);
+               if (prev->rnw == DPAP_READ) {
+                       log_dap_cmd(dap, "PND", prev);
+                       /* search for the next OK transaction, it contains
+                        * the result of the previous READ */
+                       tmp = el;
+                       list_for_each_entry_from(tmp, &dap->cmd_journal, lh) {
+                               /* The following check covers OK and FAULT ACKs for both ADIv5 and ADIv6 */
+                               if (tmp->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && tmp->ack == JTAG_ACK_OK)) {
+                                       /* recover the read value */
+                                       log_dap_cmd(dap, "FND", tmp);
+                                       if (el->invalue != el->invalue_buf) {
+                                               uint32_t invalue = le_to_h_u32(tmp->invalue);
+                                               memcpy(el->invalue, &invalue, sizeof(uint32_t));
+                                       }
+                                       prev = NULL;
+                                       break;
+                               }
+                       }
 
-       dap->ack = dap->ack & 0x7;
-
-       /* common code path avoids calling timeval_ms() */
-       if (dap->ack != JTAG_ACK_OK_FAULT)
-       {
-               long long then = timeval_ms();
-
-               while (dap->ack != JTAG_ACK_OK_FAULT)
-               {
-                       if (dap->ack == JTAG_ACK_WAIT)
-                       {
-                               if ((timeval_ms()-then) > 1000)
-                               {
-                                       /* NOTE:  this would be a good spot
-                                        * to use JTAG_DP_ABORT.
-                                        */
-                                       LOG_WARNING("Timeout (1000ms) waiting "
-                                               "for ACK=OK/FAULT "
-                                               "in JTAG-DP transaction");
-                                       return ERROR_JTAG_DEVICE_ERROR;
+                       if (prev) {
+                               log_dap_cmd(dap, "LST", el);
+
+                               /*
+                               * At this point we're sure that no previous
+                               * transaction completed and the DAP/AP is still
+                               * in busy state. We know that the next "OK" scan
+                               * will return the READ result we need to recover.
+                               * To complete the READ, we just keep polling RDBUFF
+                               * until the WAIT condition clears
+                               */
+                               tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
+                                               DP_RDBUFF, DPAP_READ, NULL, NULL, 0);
+                               if (!tmp) {
+                                       retval = ERROR_JTAG_DEVICE_ERROR;
+                                       goto done;
+                               }
+                               /* synchronously retry the command until it succeeds */
+                               time_now = timeval_ms();
+                               do {
+                                       retval = adi_jtag_dp_scan_cmd_sync(dap, tmp, NULL);
+                                       if (retval != ERROR_OK)
+                                               break;
+                                       /* The following check covers OK and FAULT ACKs for both ADIv5 and ADIv6 */
+                                       if (tmp->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && tmp->ack == JTAG_ACK_OK)) {
+                                               log_dap_cmd(dap, "FND", tmp);
+                                               if (el->invalue != el->invalue_buf) {
+                                                       uint32_t invalue = le_to_h_u32(tmp->invalue);
+                                                       memcpy(el->invalue, &invalue, sizeof(uint32_t));
+                                               }
+                                               break;
+                                       }
+                                       if (tmp->ack != JTAG_ACK_WAIT) {
+                                               LOG_ERROR("Invalid ACK (%1x) in DAP response", tmp->ack);
+                                               log_dap_cmd(dap, "ERR", tmp);
+                                               retval = ERROR_JTAG_DEVICE_ERROR;
+                                               break;
+                                       }
+
+                               } while (timeval_ms() - time_now < 1000);
+
+                               if (retval == ERROR_OK) {
+                                       /* timeout happened */
+                                       if (tmp->ack == JTAG_ACK_WAIT) {
+                                               LOG_ERROR("Timeout during WAIT recovery");
+                                               dap->select_valid = false;
+                                               dap->select1_valid = false;
+                                               /* Keep dap->select unchanged, the same AP and AP bank
+                                                * is likely going to be used further */
+                                               jtag_ap_q_abort(dap, NULL);
+                                               /* clear the sticky overrun condition */
+                                               adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                                                       DP_CTRL_STAT, DPAP_WRITE,
+                                                       dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0);
+                                               retval = ERROR_JTAG_DEVICE_ERROR;
+                                       }
                                }
+
+                               /* we're done with this command, release it */
+                               dap_cmd_release(dap, tmp);
+
+                               if (retval != ERROR_OK)
+                                       goto done;
+
                        }
-                       else
-                       {
-                               LOG_WARNING("Invalid ACK %#x "
-                                               "in JTAG-DP transaction",
-                                               dap->ack);
-                               return ERROR_JTAG_DEVICE_ERROR;
+                       /* make el->invalue point to the default invalue
+                       * so that we can safely retry it without clobbering
+                       * the result we just recovered */
+                       el->invalue = el->invalue_buf;
+               }
+       }
+
+       /* move all remaining transactions over to the replay list */
+       list_for_each_entry_safe_from(el, tmp, &dap->cmd_journal, lh) {
+               log_dap_cmd(dap, "REP", el);
+               list_move_tail(&el->lh, &replay_list);
+       }
+
+       /* we're done with the journal, flush it */
+       flush_journal(dap, &dap->cmd_journal);
+
+       /* check for overrun condition in the last batch of transactions */
+       if (found_wait) {
+               LOG_INFO("DAP transaction stalled (WAIT) - slowing down and resending");
+               /* clear the sticky overrun condition */
+               retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                               DP_CTRL_STAT, DPAP_WRITE,
+                               dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0);
+               if (retval != ERROR_OK)
+                       goto done;
+
+               /* restore SELECT register first */
+               if (!list_empty(&replay_list)) {
+                       el = list_first_entry(&replay_list, struct dap_cmd, lh);
+
+                       uint8_t out_value_buf[4];
+                       buf_set_u32(out_value_buf, 0, 32, (uint32_t)(el->dp_select));
+
+                       tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
+                                         DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0);
+                       if (!tmp) {
+                               retval = ERROR_JTAG_DEVICE_ERROR;
+                               goto done;
                        }
+                       list_add(&tmp->lh, &replay_list);
+
+                       /* TODO: ADIv6 DP SELECT1 handling */
+
+                       dap->select_valid = false;
+               }
 
-                       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                                       DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-                       if ((retval = dap_run(dap)) != ERROR_OK)
-                               return retval;
-                       dap->ack = dap->ack & 0x7;
+               list_for_each_entry_safe(el, tmp, &replay_list, lh) {
+                       time_now = timeval_ms();
+                       do {
+                               retval = adi_jtag_dp_scan_cmd_sync(dap, el, NULL);
+                               if (retval != ERROR_OK)
+                                       break;
+                               log_dap_cmd(dap, "REC", el);
+                               if (el->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && el->ack == JTAG_ACK_OK)) {
+                                       if (el->invalue != el->invalue_buf) {
+                                               uint32_t invalue = le_to_h_u32(el->invalue);
+                                               memcpy(el->invalue, &invalue, sizeof(uint32_t));
+                                       }
+                                       break;
+                               }
+                               if (el->ack != JTAG_ACK_WAIT) {
+                                       LOG_ERROR("Invalid ACK (%1x) in DAP response", el->ack);
+                                       log_dap_cmd(dap, "ERR", el);
+                                       retval = ERROR_JTAG_DEVICE_ERROR;
+                                       break;
+                               }
+                               LOG_DEBUG("DAP transaction stalled during replay (WAIT) - resending");
+                               /* clear the sticky overrun condition */
+                               retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                                               DP_CTRL_STAT, DPAP_WRITE,
+                                               dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0);
+                               if (retval != ERROR_OK)
+                                       break;
+                       } while (timeval_ms() - time_now < 1000);
+
+                       if (retval == ERROR_OK) {
+                               if (el->ack == JTAG_ACK_WAIT) {
+                                       LOG_ERROR("Timeout during WAIT recovery");
+                                       dap->select_valid = false;
+                                       dap->select1_valid = false;
+                                       /* Keep dap->select unchanged, the same AP and AP bank
+                                        * is likely going to be used further */
+                                       jtag_ap_q_abort(dap, NULL);
+                                       /* clear the sticky overrun condition */
+                                       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                                               DP_CTRL_STAT, DPAP_WRITE,
+                                               dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0);
+                                       retval = ERROR_JTAG_DEVICE_ERROR;
+                                       break;
+                               }
+                       } else
+                               break;
                }
        }
 
+ done:
+       flush_journal(dap, &replay_list);
+       flush_journal(dap, &dap->cmd_journal);
+       return retval;
+}
+
+static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
+{
+       int retval;
+       uint32_t ctrlstat, pwrmask;
+
+       /* too expensive to call keep_alive() here */
+
+       /* Post CTRL/STAT read; discard any previous posted read value
+        * but collect its ACK status.
+        */
+       retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                       DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat, 0);
+       if (retval != ERROR_OK)
+               goto done;
+
        /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */
 
-       /* Check for STICKYERR and STICKYORUN */
-       if (ctrlstat & (SSTICKYORUN | SSTICKYERR))
-       {
-               LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat);
+       /* Check for STICKYERR */
+       if (ctrlstat & SSTICKYERR) {
+               LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
                /* Check power to debug regions */
-               if ((ctrlstat & 0xf0000000) != 0xf0000000)
-               {
-                       retval = ahbap_debugport_init(dap);
-                       if (retval != ERROR_OK)
-                               return retval;
+               pwrmask = CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ;
+               if (!dap->ignore_syspwrupack)
+                       pwrmask |= CSYSPWRUPACK;
+               if ((ctrlstat & pwrmask) != pwrmask) {
+                       LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened");
+                       dap->do_reconnect = true;
                }
-               else
-               {
-                       uint32_t mem_ap_csw, mem_ap_tar;
-
-                       /* Maybe print information about last intended
-                        * MEM-AP access; but not if autoincrementing.
-                        * *Real* CSW and TAR values are always shown.
-                        */
-                       if (dap->ap_tar_value != (uint32_t) -1)
-                               LOG_DEBUG("MEM-AP Cached values: "
-                                       "ap_bank 0x%" PRIx32
-                                       ", ap_csw 0x%" PRIx32
-                                       ", ap_tar 0x%" PRIx32,
-                                       dap->ap_bank_value,
-                                       dap->ap_csw_value,
-                                       dap->ap_tar_value);
-
-                       if (ctrlstat & SSTICKYORUN)
-                               LOG_ERROR("JTAG-DP OVERRUN - check clock, "
-                                       "memaccess, or reduce jtag speed");
-
-                       if (ctrlstat & SSTICKYERR)
-                               LOG_ERROR("JTAG-DP STICKY ERROR");
-
-                       /* Clear Sticky Error Bits */
-                       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                                       DP_CTRL_STAT, DPAP_WRITE,
-                                       dap->dp_ctrl_stat | SSTICKYORUN
-                                               | SSTICKYERR, NULL);
-                       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                                       DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-                       if ((retval = dap_run(dap)) != ERROR_OK)
-                               return retval;
-
-                       LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
-
-                       retval = dap_queue_ap_read(dap,
-                                       AP_REG_CSW, &mem_ap_csw);
-                       if (retval != ERROR_OK)
-                               return retval;
-
-                       retval = dap_queue_ap_read(dap,
-                                       AP_REG_TAR, &mem_ap_tar);
-                       if (retval != ERROR_OK)
-                               return retval;
-
-                       if ((retval = dap_run(dap)) != ERROR_OK)
-                               return retval;
-                       LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%"
-                                       PRIx32, mem_ap_csw, mem_ap_tar);
 
-               }
-               if ((retval = dap_run(dap)) != ERROR_OK)
-                       return retval;
-               return ERROR_JTAG_DEVICE_ERROR;
+               if (ctrlstat & SSTICKYERR)
+                       LOG_ERROR("JTAG-DP STICKY ERROR");
+               if (ctrlstat & SSTICKYORUN)
+                       LOG_DEBUG("JTAG-DP STICKY OVERRUN");
+
+               /* Clear Sticky Error and Sticky Overrun Bits */
+               retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                               DP_CTRL_STAT, DPAP_WRITE,
+                               dap->dp_ctrl_stat | SSTICKYERR | SSTICKYORUN, NULL, 0);
+               if (retval != ERROR_OK)
+                       goto done;
+
+               retval = ERROR_JTAG_DEVICE_ERROR;
        }
 
-       return ERROR_OK;
+ done:
+       flush_journal(dap, &dap->cmd_journal);
+       return retval;
 }
 
 /*--------------------------------------------------------------------------*/
 
-static int jtag_idcode_q_read(struct adiv5_dap *dap,
-               uint8_t *ack, uint32_t *data)
+static int jtag_connect(struct adiv5_dap *dap)
 {
-       struct arm_jtag *jtag_info = dap->jtag_info;
-       int retval;
-       struct scan_field fields[1];
-
-       /* This is a standard JTAG operation -- no DAP tweakage */
-       retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL, TAP_IDLE);
-       if (retval != ERROR_OK)
-               return retval;
+       dap->do_reconnect = false;
+       return dap_dp_init(dap);
+}
 
-       fields[0].num_bits = 32;
-       fields[0].out_value = NULL;
-       fields[0].in_value = (void *) data;
+static int jtag_check_reconnect(struct adiv5_dap *dap)
+{
+       if (dap->do_reconnect)
+               return jtag_connect(dap);
 
-       jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE);
+       return ERROR_OK;
+}
 
-       jtag_add_callback(arm_le_to_h_u32,
-                       (jtag_callback_data_t) data);
+static int jtag_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+       int retval;
 
-       return ERROR_OK;
+       switch (seq) {
+       case JTAG_TO_SWD:
+               retval =  jtag_add_tms_seq(swd_seq_jtag_to_swd_len,
+                               swd_seq_jtag_to_swd, TAP_INVALID);
+               break;
+       case SWD_TO_JTAG:
+               retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len,
+                               swd_seq_swd_to_jtag, TAP_RESET);
+               break;
+       default:
+               LOG_ERROR("Sequence %d not supported", seq);
+               return ERROR_FAIL;
+       }
+       if (retval == ERROR_OK)
+               retval = jtag_execute_queue();
+       return retval;
 }
 
 static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
                uint32_t *data)
 {
-       return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                       reg, DPAP_READ, 0, data);
+       int retval = jtag_limit_queue_size(dap);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval =  adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg,
+                       DPAP_READ, 0, dap->last_read, 0, NULL);
+       dap->last_read = data;
+       return retval;
 }
 
 static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg,
                uint32_t data)
 {
-       return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
-                       reg, DPAP_WRITE, data, NULL);
+       int retval = jtag_limit_queue_size(dap);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval =  adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
+                       reg, DPAP_WRITE, data, dap->last_read, 0, NULL);
+       dap->last_read = NULL;
+       return retval;
 }
 
-/** Select the AP register bank matching bits 7:4 of reg. */
-static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
+/** Select the AP register bank */
+static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg)
 {
-       uint32_t select_ap_bank = reg & 0x000000F0;
+       int retval;
+       struct adiv5_dap *dap = ap->dap;
+       uint64_t sel;
+
+       if (is_adiv6(dap))
+               sel = ap->ap_num | (reg & 0x00000FF0);
+       else
+               sel = (ap->ap_num << 24) | (reg & ADIV5_DP_SELECT_APBANK);
+
+       uint64_t sel_diff = (sel ^ dap->select) & SELECT_AP_MASK;
+
+       bool set_select = !dap->select_valid || (sel_diff & 0xffffffffull);
+       bool set_select1 = is_adiv6(dap) && dap->asize > 32
+                                               && (!dap->select1_valid
+                                                       || sel_diff & (0xffffffffull << 32));
+
+       if (set_select && set_select1) {
+               /* Prepare DP bank for DP_SELECT1 now to save one write */
+               sel |= (DP_SELECT1 >> 4) & DP_SELECT_DPBANK;
+       } else {
+               /* Use the DP part of dap->select regardless of dap->select_valid:
+                * if !dap->select_valid
+                * dap->select contains a speculative value likely going to be used
+                * in the following swd_queue_dp_bankselect().
+                * Moreover dap->select_valid should never be false here as a DP bank
+                * is always selected before selecting an AP bank */
+               sel |= dap->select & DP_SELECT_DPBANK;
+       }
 
-       if (select_ap_bank == dap->ap_bank_value)
-               return ERROR_OK;
-       dap->ap_bank_value = select_ap_bank;
+       if (set_select) {
+               LOG_DEBUG_IO("AP BANK SELECT: %" PRIx32, (uint32_t)sel);
 
-       select_ap_bank |= dap->apsel;
+               retval = jtag_dp_q_write(dap, DP_SELECT, (uint32_t)sel);
+               if (retval != ERROR_OK) {
+                       dap->select_valid = false;
+                       return retval;
+               }
+       }
+
+       if (set_select1) {
+               LOG_DEBUG_IO("AP BANK SELECT1: %" PRIx32, (uint32_t)(sel >> 32));
+
+               retval = jtag_dp_q_write(dap, DP_SELECT1, (uint32_t)(sel >> 32));
+               if (retval != ERROR_OK) {
+                       dap->select1_valid = false;
+                       return retval;
+               }
+       }
 
-       return jtag_dp_q_write(dap, DP_SELECT, select_ap_bank);
+       dap->select = sel;
+       return ERROR_OK;
 }
 
-static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg,
+static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
                uint32_t *data)
 {
-       int retval = jtag_ap_q_bankselect(dap, reg);
+       int retval = jtag_limit_queue_size(ap->dap);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = jtag_check_reconnect(ap->dap);
+       if (retval != ERROR_OK)
+               return retval;
 
+       retval = jtag_ap_q_bankselect(ap, reg);
        if (retval != ERROR_OK)
                return retval;
 
-       return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg,
-                       DPAP_READ, 0, data);
+       retval =  adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg,
+                       DPAP_READ, 0, ap->dap->last_read, ap->memaccess_tck, NULL);
+       ap->dap->last_read = data;
+
+       return retval;
 }
 
-static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg,
+static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg,
                uint32_t data)
 {
-       uint8_t out_value_buf[4];
+       int retval = jtag_limit_queue_size(ap->dap);
+       if (retval != ERROR_OK)
+               return retval;
 
-       int retval = jtag_ap_q_bankselect(dap, reg);
+       retval = jtag_check_reconnect(ap->dap);
        if (retval != ERROR_OK)
                return retval;
 
-       buf_set_u32(out_value_buf, 0, 32, data);
+       retval = jtag_ap_q_bankselect(ap, reg);
+       if (retval != ERROR_OK)
+               return retval;
 
-       return adi_jtag_ap_write_check(dap, reg, out_value_buf);
+       retval =  adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg,
+                       DPAP_WRITE, data, ap->dap->last_read, ap->memaccess_tck, NULL);
+       ap->dap->last_read = NULL;
+       return retval;
 }
 
 static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
 {
        /* for JTAG, this is the only valid ABORT register operation */
-       return adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT,
-                       0, DPAP_WRITE, 1, NULL, ack);
+       int retval =  adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT,
+                       0, DPAP_WRITE, 1, NULL, 0, NULL);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return jtag_execute_queue();
 }
 
 static int jtag_dp_run(struct adiv5_dap *dap)
 {
-       return jtagdp_transaction_endcheck(dap);
+       int retval;
+       int retval2 = ERROR_OK;
+
+       retval = adi_jtag_finish_read(dap);
+       if (retval != ERROR_OK)
+               goto done;
+       retval2 = jtagdp_overrun_check(dap);
+       retval = jtagdp_transaction_endcheck(dap);
+
+ done:
+       return (retval2 != ERROR_OK) ? retval2 : retval;
+}
+
+static int jtag_dp_sync(struct adiv5_dap *dap)
+{
+       return jtagdp_overrun_check(dap);
 }
 
 /* FIXME don't export ... just initialize as
  * part of DAP setup
 */
 const struct dap_ops jtag_dp_ops = {
-       .queue_idcode_read =    jtag_idcode_q_read,
-       .queue_dp_read =        jtag_dp_q_read,
-       .queue_dp_write =       jtag_dp_q_write,
-       .queue_ap_read =        jtag_ap_q_read,
-       .queue_ap_write =       jtag_ap_q_write,
-       .queue_ap_abort =       jtag_ap_q_abort,
-       .run =                  jtag_dp_run,
+       .connect             = jtag_connect,
+       .send_sequence       = jtag_send_sequence,
+       .queue_dp_read       = jtag_dp_q_read,
+       .queue_dp_write      = jtag_dp_q_write,
+       .queue_ap_read       = jtag_ap_q_read,
+       .queue_ap_write      = jtag_ap_q_write,
+       .queue_ap_abort      = jtag_ap_q_abort,
+       .run                 = jtag_dp_run,
+       .sync                = jtag_dp_sync,
+       .quit                = jtag_quit,
 };
-
-
-static const uint8_t swd2jtag_bitseq[] = {
-       /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
-        * putting both JTAG and SWD logic into reset state.
-        */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       /* Switching equence disables SWD and enables JTAG
-        * NOTE: bits in the DP's IDCODE can expose the need for
-        * the old/deprecated sequence (0xae 0xde).
-        */
-       0x3c, 0xe7,
-       /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high,
-        * putting both JTAG and SWD logic into reset state.
-        * NOTE:  some docs say "at least 5".
-        */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-/** Put the debug link into JTAG mode, if the target supports it.
- * The link's initial mode may be either SWD or JTAG.
- *
- * @param target Enters JTAG mode (if possible).
- *
- * Note that targets implemented with SW-DP do not support JTAG, and
- * that some targets which could otherwise support it may have been
- * configured to disable JTAG signaling
- *
- * @return ERROR_OK or else a fault code.
- */
-int dap_to_jtag(struct target *target)
-{
-       int retval;
-
-       LOG_DEBUG("Enter JTAG mode");
-
-       /* REVISIT it's nasty to need to make calls to a "jtag"
-        * subsystem if the link isn't in JTAG mode...
-        */
-
-       retval = jtag_add_tms_seq(8 * sizeof(swd2jtag_bitseq),
-                       swd2jtag_bitseq, TAP_RESET);
-       if (retval == ERROR_OK)
-               retval = jtag_execute_queue();
-
-       /* REVISIT set up the DAP's ops vector for JTAG mode. */
-
-       return retval;
-}

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)