tcl/target/ti_k3: Add a gdb-attach event hook for m3 and m4
[fw/openocd] / src / target / adi_v5_jtag.c
index c7dc4f7c988c4059bf9c81845b1ac559f397c8df..be625807c706af1057757f88f0c98eb2ab8ea5a6 100644 (file)
 #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
@@ -72,8 +73,8 @@ static const char *dap_reg_name(int instr, int reg_addr)
                case DP_RDBUFF:
                        reg_name =  "RDBUFF";
                        break;
-               case DP_WCR:
-                       reg_name =  "WCR";
+               case DP_DLCR:
+                       reg_name =  "DLCR";
                        break;
                default:
                        reg_name = "UNK";
@@ -127,7 +128,7 @@ struct dap_cmd {
        struct list_head lh;
        uint8_t instr;
        uint8_t reg_addr;
-       uint8_t RnW;
+       uint8_t rnw;
        uint8_t *invalue;
        uint8_t ack;
        uint32_t memaccess_tck;
@@ -139,13 +140,20 @@ struct dap_cmd {
        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(const char *header, struct dap_cmd *el)
 {
 #ifdef DEBUG_WAIT
        LOG_DEBUG("%s: %2s %6s %5s 0x%08x 0x%08x %2s", header,
                el->instr == JTAG_DP_APACC ? "AP" : "DP",
                dap_reg_name(el->instr, el->reg_addr),
-               el->RnW == DPAP_READ ? "READ" : "WRITE",
+               el->rnw == DPAP_READ ? "READ" : "WRITE",
                buf_get_u32(el->outvalue_buf, 0, 32),
                buf_get_u32(el->invalue, 0, 32),
                el->ack == JTAG_ACK_OK_FAULT ? "OK" :
@@ -153,32 +161,73 @@ static void log_dap_cmd(const char *header, struct dap_cmd *el)
 #endif
 }
 
-static struct dap_cmd *dap_cmd_new(uint8_t instr,
-               uint8_t reg_addr, uint8_t RnW,
+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,
+               uint8_t reg_addr, uint8_t rnw,
                uint8_t *outvalue, uint8_t *invalue,
                uint32_t memaccess_tck)
 {
-       struct dap_cmd *cmd;
 
-       cmd = (struct dap_cmd *)calloc(1, sizeof(struct dap_cmd));
-       if (cmd != NULL) {
-               INIT_LIST_HEAD(&cmd->lh);
-               cmd->instr = instr;
-               cmd->reg_addr = reg_addr;
-               cmd->RnW = RnW;
-               if (outvalue != NULL)
-                       memcpy(cmd->outvalue_buf, outvalue, 4);
-               cmd->invalue = (invalue != NULL) ? invalue : cmd->invalue_buf;
-               cmd->memaccess_tck = 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 flush_journal(struct list_head *lh)
+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);
@@ -204,9 +253,9 @@ static int adi_jtag_dp_scan_cmd(struct adiv5_dap *dap, struct dap_cmd *cmd, uint
         * 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));
+       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 != NULL) ? ack : &cmd->ack;
+       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.
@@ -250,7 +299,7 @@ static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd,
  * conversions are performed.  See section 4.4.3 of the ADIv5 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.
  *
@@ -258,7 +307,7 @@ static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd,
  * @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
@@ -266,15 +315,15 @@ static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd,
  */
 
 static int adi_jtag_dp_scan(struct adiv5_dap *dap,
-               uint8_t instr, uint8_t reg_addr, uint8_t RnW,
+               uint8_t instr, uint8_t reg_addr, uint8_t rnw,
                uint8_t *outvalue, uint8_t *invalue,
                uint32_t memaccess_tck, uint8_t *ack)
 {
        struct dap_cmd *cmd;
        int retval;
 
-       cmd = dap_cmd_new(instr, reg_addr, RnW, outvalue, invalue, memaccess_tck);
-       if (cmd != NULL)
+       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;
@@ -293,7 +342,7 @@ static 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,
+               uint8_t instr, uint8_t reg_addr, uint8_t rnw,
                uint32_t outvalue, uint32_t *invalue,
                uint32_t memaccess_tck, uint8_t *ack)
 {
@@ -302,7 +351,7 @@ static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap,
 
        buf_set_u32(out_value_buf, 0, 32, outvalue);
 
-       retval = adi_jtag_dp_scan(dap, instr, reg_addr, RnW,
+       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;
@@ -318,7 +367,7 @@ static int adi_jtag_finish_read(struct adiv5_dap *dap)
 {
        int retval = ERROR_OK;
 
-       if (dap->last_read != NULL) {
+       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;
@@ -328,21 +377,21 @@ static int adi_jtag_finish_read(struct adiv5_dap *dap)
 }
 
 static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *dap,
-               uint8_t instr, uint8_t reg_addr, uint8_t RnW,
+               uint8_t instr, uint8_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, memaccess_tck, 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, 0, NULL);
                if (retval != ERROR_OK)
@@ -386,7 +435,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
         */
        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) {
+               if (prev->rnw == DPAP_READ) {
                        log_dap_cmd("PND", prev);
                        /* search for the next OK transaction, it contains
                         * the result of the previous READ */
@@ -404,7 +453,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
                                }
                        }
 
-                       if (prev != NULL) {
+                       if (prev) {
                                log_dap_cmd("LST", el);
 
                                /*
@@ -415,9 +464,9 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
                                * To complete the READ, we just keep polling RDBUFF
                                * until the WAIT condition clears
                                */
-                               tmp = dap_cmd_new(JTAG_DP_DPACC,
+                               tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
                                                DP_RDBUFF, DPAP_READ, NULL, NULL, 0);
-                               if (tmp == NULL) {
+                               if (!tmp) {
                                        retval = ERROR_JTAG_DEVICE_ERROR;
                                        goto done;
                                }
@@ -459,7 +508,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
                                }
 
                                /* we're done with this command, release it */
-                               free(tmp);
+                               dap_cmd_release(dap, tmp);
 
                                if (retval != ERROR_OK)
                                        goto done;
@@ -479,7 +528,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
        }
 
        /* we're done with the journal, flush it */
-       flush_journal(&dap->cmd_journal);
+       flush_journal(dap, &dap->cmd_journal);
 
        /* check for overrun condition in the last batch of transactions */
        if (found_wait) {
@@ -494,9 +543,9 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
                /* restore SELECT register first */
                if (!list_empty(&replay_list)) {
                        el = list_first_entry(&replay_list, struct dap_cmd, lh);
-                       tmp = dap_cmd_new(JTAG_DP_DPACC,
+                       tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
                                          DP_SELECT, DPAP_WRITE, (uint8_t *)&el->dp_select, NULL, 0);
-                       if (tmp == NULL) {
+                       if (!tmp) {
                                retval = ERROR_JTAG_DEVICE_ERROR;
                                goto done;
                        }
@@ -525,6 +574,13 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
                                        retval = ERROR_JTAG_DEVICE_ERROR;
                                        break;
                                }
+                               LOG_INFO("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) {
@@ -545,15 +601,15 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
        }
 
  done:
-       flush_journal(&replay_list);
-       flush_journal(&dap->cmd_journal);
+       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;
+       uint32_t ctrlstat, pwrmask;
 
        /* too expensive to call keep_alive() here */
 
@@ -571,9 +627,12 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
        if (ctrlstat & SSTICKYERR) {
                LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
                /* Check power to debug regions */
-               if ((ctrlstat & (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) !=
-                                               (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) {
+               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;
                }
 
                if (ctrlstat & SSTICKYERR)
@@ -592,16 +651,56 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
        }
 
  done:
-       flush_journal(&dap->cmd_journal);
+       flush_journal(dap, &dap->cmd_journal);
        return retval;
 }
 
 /*--------------------------------------------------------------------------*/
 
+static int jtag_connect(struct adiv5_dap *dap)
+{
+       dap->do_reconnect = false;
+       return dap_dp_init(dap);
+}
+
+static int jtag_check_reconnect(struct adiv5_dap *dap)
+{
+       if (dap->do_reconnect)
+               return jtag_connect(dap);
+
+       return ERROR_OK;
+}
+
+static int jtag_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+       int retval;
+
+       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)
 {
-       int retval =  adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg,
+       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;
@@ -610,7 +709,11 @@ static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
 static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg,
                uint32_t data)
 {
-       int retval =  adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
+       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;
@@ -633,7 +736,15 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg)
 static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
                uint32_t *data)
 {
-       int retval = jtag_ap_q_bankselect(ap, 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;
 
@@ -647,7 +758,15 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
 static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg,
                uint32_t data)
 {
-       int retval = jtag_ap_q_bankselect(ap, 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;
 
@@ -692,6 +811,8 @@ static int jtag_dp_sync(struct adiv5_dap *dap)
  * part of DAP setup
 */
 const struct dap_ops jtag_dp_ops = {
+       .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,
@@ -699,53 +820,5 @@ const struct dap_ops jtag_dp_ops = {
        .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;
-}