target/profiling: Use the correct method to access registers
[fw/openocd] / src / target / adi_v5_jtag.c
index 0a374bea82d500d9134141d718ca3fd9881bf5ef..1100b17d21cfa761de0476f99dbff85fb6b73b60 100644 (file)
@@ -23,7 +23,7 @@
  *   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.
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  ***************************************************************************/
 
 /**
@@ -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
@@ -51,6 +50,8 @@
 #define JTAG_ACK_OK_FAULT      0x2
 #define JTAG_ACK_WAIT          0x1
 
+static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack);
+
 /***************************************************************************
  *
  * DPACC and APACC scanchain access through JTAG-DP (or SWJ-DP)
  * @param ack points to where the three bit JTAG_ACK_* code will be stored
  */
 
-/* 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,
+static 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)
 {
        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.
@@ -188,64 +189,76 @@ 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)
-                               {
-                                       /* NOTE:  this would be a good spot
-                                        * to use JTAG_DP_ABORT.
-                                        */
+               while (dap->ack != JTAG_ACK_OK_FAULT) {
+                       if (dap->ack == JTAG_ACK_WAIT) {
+                               if ((timeval_ms()-then) > 1000) {
                                        LOG_WARNING("Timeout (1000ms) waiting "
                                                "for ACK=OK/FAULT "
-                                               "in JTAG-DP transaction");
+                                               "in JTAG-DP transaction - aborting");
+
+                                       uint8_t ack;
+                                       int abort_ret = jtag_ap_q_abort(dap, &ack);
+
+                                       if (abort_ret != 0)
+                                               LOG_WARNING("Abort failed : return=%d ack=%d", abort_ret, ack);
+
                                        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 +267,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 +298,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 +324,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;
        }
@@ -326,30 +342,6 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
 
 /*--------------------------------------------------------------------------*/
 
-static int jtag_idcode_q_read(struct adiv5_dap *dap,
-               uint8_t *ack, uint32_t *data)
-{
-       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;
-
-       fields[0].num_bits = 32;
-       fields[0].out_value = NULL;
-       fields[0].in_value = (void *) data;
-
-       jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE);
-
-       jtag_add_callback(arm_le_to_h_u32,
-                       (jtag_callback_data_t) data);
-
-       return ERROR_OK;
-}
-
 static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
                uint32_t *data)
 {
@@ -373,7 +365,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);
 }
@@ -420,13 +412,12 @@ static int jtag_dp_run(struct adiv5_dap *dap)
  * 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,
+       .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,
 };