adi_v5_jtag.c: Avoid infinite recursion in jtagdp_transaction_endcheck()
[fw/openocd] / src / target / adi_v5_jtag.c
index 44f624f3a50134e00a4603b18e77131fb04bcf32..9f37bd553d841080b8c416eceed2c553d2f1e524 100644 (file)
@@ -40,7 +40,6 @@
 #include "arm_adi_v5.h"
 #include <helper/time_support.h>
 
-
 /* JTAG instructions/registers for JTAG-DP and SWJ-DP */
 #define JTAG_DP_ABORT          0x8
 #define JTAG_DP_DPACC          0xA
@@ -86,8 +85,11 @@ int adi_jtag_dp_scan(struct adiv5_dap *dap,
        struct arm_jtag *jtag_info = dap->jtag_info;
        struct scan_field fields[2];
        uint8_t out_addr_buf;
+       int retval;
 
-       arm_jtag_set_instr(jtag_info, instr, NULL, TAP_IDLE);
+       retval = arm_jtag_set_instr(jtag_info, 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.
@@ -120,7 +122,7 @@ int adi_jtag_dp_scan(struct adiv5_dap *dap,
                jtag_add_runtest(dap->memaccess_tck,
                                TAP_IDLE);
 
-       return jtag_get_error();
+       return ERROR_OK;
 }
 
 /**
@@ -188,44 +190,51 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
 
        /* 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????");
-       }
-       /* Why??? second time it works??? */
-#endif
+       /* Here be dragons!
+        *
+        * It is easy to be in a JTAG clock range where the target
+        * is not operating in a stable fashion. This happens
+        * for a few reasons:
+        *
+        * - the user may construct a simple test case to try to see
+        * if a higher JTAG clock works to eke out more performance.
+        * This simple case may pass, but more complex situations can
+        * fail.
+        *
+        * - The mostly works JTAG clock rate and the complete failure
+        * JTAG clock rate may be as much as 2-4x apart. This seems
+        * to be especially true on RC oscillator driven parts.
+        *
+        * So: even if calling adi_jtag_scan_inout_check_u32() multiple
+        * times here seems to "make things better here", it is just
+        * hiding problems with too high a JTAG clock.
+        *
+        * Note that even if some parts have RCLK/RTCK, that doesn't
+        * mean that RCLK/RTCK is the *correct* rate to run the JTAG
+        * interface at, i.e. RCLK/RTCK rates can be "too high", especially
+        * before the RC oscillator phase is not yet complete.
+        */
 
        /* Post CTRL/STAT read; discard any previous posted read value
         * but collect its ACK status.
         */
-       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+       retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
                        DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-       if ((retval = jtag_execute_queue()) != ERROR_OK)
+       if (retval != ERROR_OK)
+               return retval;
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
                return retval;
 
        dap->ack = dap->ack & 0x7;
 
        /* common code path avoids calling timeval_ms() */
-       if (dap->ack != JTAG_ACK_OK_FAULT)
-       {
+       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)
-                               {
+               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.
                                         */
@@ -234,18 +243,19 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
                                                "in JTAG-DP transaction");
                                        return ERROR_JTAG_DEVICE_ERROR;
                                }
-                       }
-                       else
-                       {
+                       } else {
                                LOG_WARNING("Invalid ACK %#x "
                                                "in JTAG-DP transaction",
                                                dap->ack);
                                return ERROR_JTAG_DEVICE_ERROR;
                        }
 
-                       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                       retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
                                        DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-                       if ((retval = dap_run(dap)) != ERROR_OK)
+                       if (retval != ERROR_OK)
+                               return retval;
+                       retval = jtag_execute_queue();
+                       if (retval != ERROR_OK)
                                return retval;
                        dap->ack = dap->ack & 0x7;
                }
@@ -254,18 +264,14 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
        /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */
 
        /* Check for STICKYERR and STICKYORUN */
-       if (ctrlstat & (SSTICKYORUN | SSTICKYERR))
-       {
+       if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) {
                LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat);
                /* Check power to debug regions */
-               if ((ctrlstat & 0xf0000000) != 0xf0000000)
-               {
+               if ((ctrlstat & 0xf0000000) != 0xf0000000) {
                        retval = ahbap_debugport_init(dap);
                        if (retval != ERROR_OK)
                                return retval;
-               }
-               else
-               {
+               } else {
                        uint32_t mem_ap_csw, mem_ap_tar;
 
                        /* Maybe print information about last intended
@@ -289,13 +295,18 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
                                LOG_ERROR("JTAG-DP STICKY ERROR");
 
                        /* Clear Sticky Error Bits */
-                       adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+                       retval = 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,
+                       if (retval != ERROR_OK)
+                               return retval;
+                       retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
                                        DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
-                       if ((retval = dap_run(dap)) != ERROR_OK)
+                       if (retval != ERROR_OK)
+                               return retval;
+                       retval = jtag_execute_queue();
+                       if (retval != ERROR_OK)
                                return retval;
 
                        LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
@@ -310,13 +321,15 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
                        if (retval != ERROR_OK)
                                return retval;
 
-                       if ((retval = dap_run(dap)) != ERROR_OK)
+                       retval = jtag_execute_queue();
+                       if (retval != 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)
+               retval = jtag_execute_queue();
+               if (retval != ERROR_OK)
                        return retval;
                return ERROR_JTAG_DEVICE_ERROR;
        }
@@ -343,14 +356,11 @@ static int jtag_idcode_q_read(struct adiv5_dap *dap,
        fields[0].in_value = (void *) data;
 
        jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE);
-       retval = jtag_get_error();
-       if (retval != ERROR_OK)
-               return retval;
 
        jtag_add_callback(arm_le_to_h_u32,
                        (jtag_callback_data_t) data);
 
-       return retval;
+       return ERROR_OK;
 }
 
 static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
@@ -376,7 +386,7 @@ static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
                return ERROR_OK;
        dap->ap_bank_value = select_ap_bank;
 
-       select_ap_bank |= dap->apsel;
+       select_ap_bank |= dap->ap_current;
 
        return jtag_dp_q_write(dap, DP_SELECT, select_ap_bank);
 }