ADIv5 DAP ops switching to JTAG or SWD modes
[openocd.git] / src / target / arm_adi_v5.c
index bfa5cb4259de7fe431c02e961ade35973fb6d25c..6be60af3c49c94d46eceffaf12ce77fefc60d5b7 100644 (file)
  * use either SWD or JTAG, and is called SWJ-DP.  The most common type of AP
  * is used to access memory mapped resources and is called a MEM-AP.  Also a
  * JTAG-AP is also defined, bridging to JTAG resources; those are uncommon.
+ *
+ * This programming interface allows DAP pipelined operations through a
+ * transaction queue.  This primarily affects AP operations (such as using
+ * a MEM-AP to access memory or registers).  If the current transaction has
+ * not finished by the time the next one must begin, and the ORUNDETECT bit
+ * is set in the DP_CTRL_STAT register, the SSTICKYORUN status is set and
+ * further AP operations will fail.  There are two basic methods to avoid
+ * such overrun errors.  One involves polling for status instead of using
+ * transaction piplining.  The other involves adding delays to ensure the
+ * AP has enough time to complete one operation before starting the next
+ * one.  (For JTAG these delays are controlled by memaccess_tck.)
  */
 
 /*
 #include "arm_adi_v5.h"
 #include <helper/time_support.h>
 
-/*
- * Transaction Mode:
- * swjdp->trans_mode = TRANS_MODE_COMPOSITE;
- * Uses Overrun checking mode and does not do actual JTAG send/receive or transaction
- * result checking until swjdp_end_transaction()
- * This must be done before using or deallocating any return variables.
- * swjdp->trans_mode == TRANS_MODE_ATOMIC
- * All reads and writes to the AHB bus are checked for valid completion, and return values
- * are immediatley available.
-*/
-
 
 /* ARM ADI Specification requires at least 10 bits used for TAR autoincrement  */
 
@@ -119,18 +119,6 @@ static int adi_jtag_dp_scan(struct swjdp_common *swjdp,
        jtag_set_end_state(TAP_IDLE);
        arm_jtag_set_instr(jtag_info, instr, NULL);
 
-       /* Add specified number of tck clocks before accessing memory bus */
-
-       /* REVISIT these TCK cycles should be *AFTER*  updating APACC, since
-        * 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))
-                       && (swjdp->memaccess_tck != 0))
-               jtag_add_runtest(swjdp->memaccess_tck, jtag_set_end_state(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.
         */
@@ -152,103 +140,77 @@ static int adi_jtag_dp_scan(struct swjdp_common *swjdp,
 
        jtag_add_dr_scan(2, fields, jtag_get_end_state());
 
-       return ERROR_OK;
+       /* 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))
+                       && (swjdp->memaccess_tck != 0))
+               jtag_add_runtest(swjdp->memaccess_tck,
+                               jtag_set_end_state(TAP_IDLE));
+
+       return jtag_get_error();
 }
 
-/* Scan out and in from host ordered uint32_t variables */
+/**
+ * Scan DPACC or APACC out and in from host ordered uint32_t buffers.
+ * This is exactly like adi_jtag_dp_scan(), except that endianness
+ * conversions are performed (so the types of invalue and outvalue
+ * must be different).
+ */
 static int adi_jtag_dp_scan_u32(struct swjdp_common *swjdp,
                uint8_t instr, uint8_t reg_addr, uint8_t RnW,
                uint32_t outvalue, uint32_t *invalue, uint8_t *ack)
 {
-       struct arm_jtag *jtag_info = swjdp->jtag_info;
-       struct scan_field fields[2];
        uint8_t out_value_buf[4];
-       uint8_t out_addr_buf;
-
-       jtag_set_end_state(TAP_IDLE);
-       arm_jtag_set_instr(jtag_info, instr, NULL);
-
-       /* Add specified number of tck clocks before accessing memory bus */
-
-       /* REVISIT these TCK cycles should be *AFTER*  updating APACC, since
-        * they provide more time for the (MEM) AP to complete the read ...
-        */
-       if ((instr == JTAG_DP_APACC)
-                       && ((reg_addr == AP_REG_DRW)
-                               || ((reg_addr & 0xF0) == AP_REG_BD0))
-                       && (swjdp->memaccess_tck != 0))
-               jtag_add_runtest(swjdp->memaccess_tck, jtag_set_end_state(TAP_IDLE));
-
-       fields[0].tap = jtag_info->tap;
-       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;
+       int retval;
 
-       fields[1].tap = jtag_info->tap;
-       fields[1].num_bits = 32;
        buf_set_u32(out_value_buf, 0, 32, outvalue);
-       fields[1].out_value = out_value_buf;
-       fields[1].in_value = NULL;
 
-       if (invalue)
-       {
-               fields[1].in_value = (uint8_t *)invalue;
-               jtag_add_dr_scan(2, fields, jtag_get_end_state());
-
-               jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t) invalue);
-       } else
-       {
+       retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW,
+                       out_value_buf, (uint8_t *)invalue, ack);
+       if (retval != ERROR_OK)
+               return retval;
 
-               jtag_add_dr_scan(2, fields, jtag_get_end_state());
-       }
+       if (invalue)
+               jtag_add_callback(arm_le_to_h_u32,
+                               (jtag_callback_data_t) invalue);
 
-       return ERROR_OK;
+       return retval;
 }
 
-/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */
-static int scan_inout_check(struct swjdp_common *swjdp,
-               uint8_t instr, uint8_t reg_addr, uint8_t RnW,
-               uint8_t *outvalue, uint8_t *invalue)
+/**
+ * Utility to write AP registers.
+ */
+static inline int adi_jtag_ap_write_check(struct swjdp_common *dap,
+               uint8_t reg_addr, uint8_t *outvalue)
 {
-       adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW, outvalue, NULL, NULL);
-
-       if ((RnW == DPAP_READ) && (invalue != NULL))
-               adi_jtag_dp_scan(swjdp, JTAG_DP_DPACC,
-                               DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack);
-
-       /* In TRANS_MODE_ATOMIC all JTAG_DP_APACC transactions wait for
-        * ack = OK/FAULT and the check CTRL_STAT
-        */
-       if ((instr == JTAG_DP_APACC)
-                       && (swjdp->trans_mode == TRANS_MODE_ATOMIC))
-               return jtagdp_transaction_endcheck(swjdp);
-
-       return ERROR_OK;
+       return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE,
+                       outvalue, NULL, NULL);
 }
 
-static int scan_inout_check_u32(struct swjdp_common *swjdp,
+static int adi_jtag_scan_inout_check_u32(struct swjdp_common *swjdp,
                uint8_t instr, uint8_t reg_addr, uint8_t RnW,
                uint32_t outvalue, uint32_t *invalue)
 {
+       int retval;
+
        /* Issue the read or write */
-       adi_jtag_dp_scan_u32(swjdp, instr, reg_addr, RnW, outvalue, NULL, NULL);
+       retval = adi_jtag_dp_scan_u32(swjdp, instr, reg_addr,
+                       RnW, outvalue, NULL, 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))
-               adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC,
+               retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC,
                                DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack);
-
-       /* In TRANS_MODE_ATOMIC all JTAG_DP_APACC transactions wait for
-        * ack = OK/FAULT and then check CTRL_STAT
-        */
-       if ((instr == JTAG_DP_APACC)
-                       && (swjdp->trans_mode == TRANS_MODE_ATOMIC))
-               return jtagdp_transaction_endcheck(swjdp);
-
-       return ERROR_OK;
+       return retval;
 }
 
 int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
@@ -260,7 +222,7 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
 
 #if 0
        /* Danger!!!! BROKEN!!!! */
-       scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+       adi_jtag_scan_inout_check_u32(swjdp, 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
@@ -278,7 +240,7 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
        /* Post CTRL/STAT read; discard any previous posted read value
         * but collect its ACK status.
         */
-       scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+       adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
                        DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
        if ((retval = jtag_execute_queue()) != ERROR_OK)
                return retval;
@@ -313,7 +275,7 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
                                return ERROR_JTAG_DEVICE_ERROR;
                        }
 
-                       scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+                       adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
                                        DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
                        if ((retval = jtag_execute_queue()) != ERROR_OK)
                                return retval;
@@ -334,17 +296,18 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
                {
                        uint32_t mem_ap_csw, mem_ap_tar;
 
-                       /* Maybe print information about last MEM-AP access */
+                       /* Maybe print information about last intended
+                        * MEM-AP access; but not if autoincrementing.
+                        * *Real* CSW and TAR values are always shown.
+                        */
                        if (swjdp->ap_tar_value != (uint32_t) -1)
                                LOG_DEBUG("MEM-AP Cached values: "
                                        "ap_bank 0x%" PRIx32
                                        ", ap_csw 0x%" PRIx32
                                        ", ap_tar 0x%" PRIx32,
-                                       swjdp->dp_select_value,
+                                       swjdp->ap_bank_value,
                                        swjdp->ap_csw_value,
                                        swjdp->ap_tar_value);
-                       else
-                               LOG_ERROR("Invalid MEM-AP TAR cache!");
 
                        if (ctrlstat & SSTICKYORUN)
                                LOG_ERROR("JTAG-DP OVERRUN - check clock, "
@@ -354,11 +317,11 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
                                LOG_ERROR("JTAG-DP STICKY ERROR");
 
                        /* Clear Sticky Error Bits */
-                       scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+                       adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
                                        DP_CTRL_STAT, DPAP_WRITE,
                                        swjdp->dp_ctrl_stat | SSTICKYORUN
                                                | SSTICKYERR, NULL);
-                       scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+                       adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
                                        DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
                        if ((retval = jtag_execute_queue()) != ERROR_OK)
                                return retval;
@@ -390,153 +353,252 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
 static int dap_dp_write_reg(struct swjdp_common *swjdp,
                uint32_t value, uint8_t reg_addr)
 {
-       return scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+       return adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
                        reg_addr, DPAP_WRITE, value, NULL);
 }
 
 static int dap_dp_read_reg(struct swjdp_common *swjdp,
                uint32_t *value, uint8_t reg_addr)
 {
-       return scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+       return adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
                        reg_addr, DPAP_READ, 0, value);
 }
 
-int dap_ap_select(struct swjdp_common *swjdp,uint8_t apsel)
+/**
+ * Select one of the APs connected to the specified DAP.  The
+ * selection is implicitly used with future AP transactions.
+ * This is a NOP if the specified AP is already selected.
+ *
+ * @param swjdp The DAP
+ * @param apsel Number of the AP to (implicitly) use with further
+ *     transactions.  This normally identifies a MEM-AP.
+ */
+void dap_ap_select(struct swjdp_common *swjdp,uint8_t apsel)
 {
-       uint32_t select;
-       select = (apsel << 24) & 0xFF000000;
+       uint32_t select = (apsel << 24) & 0xFF000000;
 
        if (select != swjdp->apsel)
        {
                swjdp->apsel = select;
-               /* Switching AP invalidates cached values */
-               swjdp->dp_select_value = -1;
+               /* Switching AP invalidates cached values.
+                * Values MUST BE UPDATED BEFORE AP ACCESS.
+                */
+               swjdp->ap_bank_value = -1;
                swjdp->ap_csw_value = -1;
                swjdp->ap_tar_value = -1;
        }
-
-       return ERROR_OK;
 }
 
-static int dap_dp_bankselect(struct swjdp_common *swjdp, uint32_t ap_reg)
+/** Select the AP register bank matching bits 7:4 of ap_reg. */
+static int dap_ap_bankselect(struct swjdp_common *swjdp, uint32_t ap_reg)
 {
-       uint32_t select;
-       select = (ap_reg & 0x000000F0);
+       uint32_t select = (ap_reg & 0x000000F0);
 
-       if (select != swjdp->dp_select_value)
+       if (select != swjdp->ap_bank_value)
        {
-               dap_dp_write_reg(swjdp, select | swjdp->apsel, DP_SELECT);
-               swjdp->dp_select_value = select;
-       }
-
-       return ERROR_OK;
+               swjdp->ap_bank_value = select;
+               select |= swjdp->apsel;
+               return dap_dp_write_reg(swjdp, select, DP_SELECT);
+       } else
+               return ERROR_OK;
 }
 
 static int dap_ap_write_reg(struct swjdp_common *swjdp,
                uint32_t reg_addr, uint8_t *out_value_buf)
 {
-       dap_dp_bankselect(swjdp, reg_addr);
-       scan_inout_check(swjdp, JTAG_DP_APACC, reg_addr,
-                       DPAP_WRITE, out_value_buf, NULL);
+       int retval;
 
-       return ERROR_OK;
+       retval = dap_ap_bankselect(swjdp, reg_addr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return adi_jtag_ap_write_check(swjdp, reg_addr, out_value_buf);
 }
 
-int dap_ap_write_reg_u32(struct swjdp_common *swjdp, uint32_t reg_addr, uint32_t value)
+/**
+ * Asynchronous (queued) AP register write.
+ *
+ * @param swjdp The DAP whose currently selected AP will be written.
+ * @param reg_addr Eight bit AP register address.
+ * @param value Word to be written at reg_addr
+ *
+ * @return ERROR_OK if the transaction was properly queued, else a fault code.
+ */
+int dap_ap_write_reg_u32(struct swjdp_common *swjdp,
+               uint32_t reg_addr, uint32_t value)
 {
        uint8_t out_value_buf[4];
 
        buf_set_u32(out_value_buf, 0, 32, value);
-       dap_dp_bankselect(swjdp, reg_addr);
-       scan_inout_check(swjdp, JTAG_DP_APACC, reg_addr,
-                       DPAP_WRITE, out_value_buf, NULL);
-
-       return ERROR_OK;
+       return dap_ap_write_reg(swjdp,
+                       reg_addr, out_value_buf);
 }
 
-int dap_ap_read_reg_u32(struct swjdp_common *swjdp, uint32_t reg_addr, uint32_t *value)
+/**
+ * Asynchronous (queued) AP register eread.
+ *
+ * @param swjdp The DAP whose currently selected AP will be read.
+ * @param reg_addr Eight bit AP register address.
+ * @param value Points to where the 32-bit (little-endian) word will be stored.
+ *
+ * @return ERROR_OK if the transaction was properly queued, else a fault code.
+ */
+int dap_ap_read_reg_u32(struct swjdp_common *swjdp,
+               uint32_t reg_addr, uint32_t *value)
 {
-       dap_dp_bankselect(swjdp, reg_addr);
-       scan_inout_check_u32(swjdp, JTAG_DP_APACC, reg_addr,
-                       DPAP_READ, 0, value);
+       int retval;
 
-       return ERROR_OK;
-}
+       retval = dap_ap_bankselect(swjdp, reg_addr);
+       if (retval != ERROR_OK)
+               return retval;
 
-/***************************************************************************
- *                                                                         *
- * AHB-AP access to memory and system registers on AHB bus                 *
- *                                                                         *
-***************************************************************************/
+       return adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_APACC, reg_addr,
+                       DPAP_READ, 0, value);
+}
 
+/**
+ * Queue transactions setting up transfer parameters for the
+ * currently selected MEM-AP.
+ *
+ * Subsequent transfers using registers like AP_REG_DRW or AP_REG_BD2
+ * initiate data reads or writes using memory or peripheral addresses.
+ * If the CSW is configured for it, the TAR may be automatically
+ * incremented after each transfer.
+ *
+ * @todo Rename to reflect it being specifically a MEM-AP function.
+ *
+ * @param swjdp The DAP connected to the MEM-AP.
+ * @param csw MEM-AP Control/Status Word (CSW) register to assign.  If this
+ *     matches the cached value, the register is not changed.
+ * @param tar MEM-AP Transfer Address Register (TAR) to assign.  If this
+ *     matches the cached address, the register is not changed.
+ *
+ * @return ERROR_OK if the transaction was properly queued, else a fault code.
+ */
 int dap_setup_accessport(struct swjdp_common *swjdp, uint32_t csw, uint32_t tar)
 {
+       int retval;
+
        csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT;
        if (csw != swjdp->ap_csw_value)
        {
                /* LOG_DEBUG("DAP: Set CSW %x",csw); */
-               dap_ap_write_reg_u32(swjdp, AP_REG_CSW, csw);
+               retval = dap_ap_write_reg_u32(swjdp, AP_REG_CSW, csw);
+               if (retval != ERROR_OK)
+                       return retval;
                swjdp->ap_csw_value = csw;
        }
        if (tar != swjdp->ap_tar_value)
        {
                /* LOG_DEBUG("DAP: Set TAR %x",tar); */
-               dap_ap_write_reg_u32(swjdp, AP_REG_TAR, tar);
+               retval = dap_ap_write_reg_u32(swjdp, AP_REG_TAR, tar);
+               if (retval != ERROR_OK)
+                       return retval;
                swjdp->ap_tar_value = tar;
        }
+       /* Disable TAR cache when autoincrementing */
        if (csw & CSW_ADDRINC_MASK)
-       {
-               /* Do not cache TAR value when autoincrementing */
                swjdp->ap_tar_value = -1;
-       }
        return ERROR_OK;
 }
 
-/*****************************************************************************
-*                                                                            *
-* mem_ap_read_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t *value)      *
-*                                                                            *
-* Read a uint32_t value from memory or system register                            *
-* Functionally equivalent to target_read_u32(target, address, uint32_t *value),   *
-* but with less overhead                                                     *
-*****************************************************************************/
-int mem_ap_read_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t *value)
+/**
+ * Asynchronous (queued) read of a word from memory or a system register.
+ *
+ * @param swjdp The DAP connected to the MEM-AP performing the read.
+ * @param address Address of the 32-bit word to read; it must be
+ *     readable by the currently selected MEM-AP.
+ * @param value points to where the word will be stored when the
+ *     transaction queue is flushed (assuming no errors).
+ *
+ * @return ERROR_OK for success.  Otherwise a fault code.
+ */
+int mem_ap_read_u32(struct swjdp_common *swjdp, uint32_t address,
+               uint32_t *value)
 {
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
+       int retval;
 
-       dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0);
-       dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), value);
+       /* Use banked addressing (REG_BDx) to avoid some link traffic
+        * (updating TAR) when reading several consecutive addresses.
+        */
+       retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF,
+                       address & 0xFFFFFFF0);
+       if (retval != ERROR_OK)
+               return retval;
 
-       return ERROR_OK;
+       return dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), value);
 }
 
-int mem_ap_read_atomic_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t *value)
+/**
+ * Synchronous read of a word from memory or a system register.
+ * As a side effect, this flushes any queued transactions.
+ *
+ * @param swjdp The DAP connected to the MEM-AP performing the read.
+ * @param address Address of the 32-bit word to read; it must be
+ *     readable by the currently selected MEM-AP.
+ * @param value points to where the result will be stored.
+ *
+ * @return ERROR_OK for success; *value holds the result.
+ * Otherwise a fault code.
+ */
+int mem_ap_read_atomic_u32(struct swjdp_common *swjdp, uint32_t address,
+               uint32_t *value)
 {
-       mem_ap_read_u32(swjdp, address, value);
+       int retval;
+
+       retval = mem_ap_read_u32(swjdp, address, value);
+       if (retval != ERROR_OK)
+               return retval;
 
        return jtagdp_transaction_endcheck(swjdp);
 }
 
-/*****************************************************************************
-*                                                                            *
-* mem_ap_write_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t value)      *
-*                                                                            *
-* Write a uint32_t value to memory or memory mapped register                              *
-*                                                                            *
-*****************************************************************************/
-int mem_ap_write_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t value)
+/**
+ * Asynchronous (queued) write of a word to memory or a system register.
+ *
+ * @param swjdp The DAP connected to the MEM-AP.
+ * @param address Address to be written; it must be writable by
+ *     the currently selected MEM-AP.
+ * @param value Word that will be written to the address when transaction
+ *     queue is flushed (assuming no errors).
+ *
+ * @return ERROR_OK for success.  Otherwise a fault code.
+ */
+int mem_ap_write_u32(struct swjdp_common *swjdp, uint32_t address,
+               uint32_t value)
 {
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
+       int retval;
 
-       dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0);
-       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), value);
+       /* Use banked addressing (REG_BDx) to avoid some link traffic
+        * (updating TAR) when writing several consecutive addresses.
+        */
+       retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF,
+                       address & 0xFFFFFFF0);
+       if (retval != ERROR_OK)
+               return retval;
 
-       return ERROR_OK;
+       return dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC),
+                       value);
 }
 
-int mem_ap_write_atomic_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t value)
+/**
+ * Synchronous write of a word to memory or a system register.
+ * As a side effect, this flushes any queued transactions.
+ *
+ * @param swjdp The DAP connected to the MEM-AP.
+ * @param address Address to be written; it must be writable by
+ *     the currently selected MEM-AP.
+ * @param value Word that will be written.
+ *
+ * @return ERROR_OK for success; the data was written.  Otherwise a fault code.
+ */
+int mem_ap_write_atomic_u32(struct swjdp_common *swjdp, uint32_t address,
+               uint32_t value)
 {
-       mem_ap_write_u32(swjdp, address, value);
+       int retval = mem_ap_write_u32(swjdp, address, value);
+
+       if (retval != ERROR_OK)
+               return retval;
 
        return jtagdp_transaction_endcheck(swjdp);
 }
@@ -554,8 +616,6 @@ int mem_ap_write_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count,
        uint32_t adr = address;
        uint8_t* pBuffer = buffer;
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        count >>= 2;
        wcount = count;
 
@@ -623,8 +683,6 @@ static int mem_ap_write_buf_packed_u16(struct swjdp_common *swjdp,
        int retval = ERROR_OK;
        int wcount, blocksize, writecount, i;
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        wcount = count >> 1;
 
        while (wcount > 0)
@@ -701,8 +759,6 @@ int mem_ap_write_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count,
        if (count >= 4)
                return mem_ap_write_buf_packed_u16(swjdp, buffer, count, address);
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        while (count > 0)
        {
                dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address);
@@ -725,8 +781,6 @@ static int mem_ap_write_buf_packed_u8(struct swjdp_common *swjdp,
        int retval = ERROR_OK;
        int wcount, blocksize, writecount, i;
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        wcount = count;
 
        while (wcount > 0)
@@ -798,8 +852,6 @@ int mem_ap_write_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count,
        if (count >= 4)
                return mem_ap_write_buf_packed_u8(swjdp, buffer, count, address);
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        while (count > 0)
        {
                dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
@@ -814,28 +866,32 @@ int mem_ap_write_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count,
        return retval;
 }
 
-/*********************************************************************************
-*                                                                                *
-* mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)  *
-*                                                                                *
-* Read block fast in target order (little endian) into a buffer                  *
-*                                                                                *
-**********************************************************************************/
-int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)
+/**
+ * Synchronously read a block of 32-bit words into a buffer
+ * @param swjdp The DAP connected to the MEM-AP.
+ * @param buffer where the words will be stored (in host byte order).
+ * @param count How many words to read.
+ * @param address Memory address from which to read words; all the
+ *     words must be readable by the currently selected MEM-AP.
+ */
+int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer,
+               int count, uint32_t address)
 {
        int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK;
        uint32_t adr = address;
        uint8_t* pBuffer = buffer;
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        count >>= 2;
        wcount = count;
 
        while (wcount > 0)
        {
-               /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/
-               blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address);
+               /* Adjust to read blocks within boundaries aligned to the
+                * TAR autoincrement size (at least 2^10).  Autoincrement
+                * mode avoids an extra per-word roundtrip to update TAR.
+                */
+               blocksize = max_tar_block_size(swjdp->tar_autoincr_block,
+                               address);
                if (wcount < blocksize)
                        blocksize = wcount;
 
@@ -843,7 +899,8 @@ int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count,
                if (blocksize == 0)
                        blocksize = 1;
 
-               dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address);
+               dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE,
+                               address);
 
                /* Scan out first read */
                adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW,
@@ -878,7 +935,8 @@ int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count,
 
                if (errorcount > 1)
                {
-                       LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count);
+                       LOG_WARNING("Block read error address 0x%" PRIx32
+                               ", count 0x%x", address, count);
                        return ERROR_JTAG_DEVICE_ERROR;
                }
        }
@@ -894,7 +952,8 @@ int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count,
 
                        for (i = 0; i < 4; i++)
                        {
-                               *((uint8_t*)pBuffer) = (data >> 8 * (adr & 0x3));
+                               *((uint8_t*)pBuffer) =
+                                               (data >> 8 * (adr & 0x3));
                                pBuffer++;
                                adr++;
                        }
@@ -911,8 +970,6 @@ static int mem_ap_read_buf_packed_u16(struct swjdp_common *swjdp,
        int retval = ERROR_OK;
        int wcount, blocksize, readcount, i;
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        wcount = count >> 1;
 
        while (wcount > 0)
@@ -957,7 +1014,16 @@ static int mem_ap_read_buf_packed_u16(struct swjdp_common *swjdp,
        return retval;
 }
 
-int mem_ap_read_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)
+/**
+ * Synchronously read a block of 16-bit halfwords into a buffer
+ * @param swjdp The DAP connected to the MEM-AP.
+ * @param buffer where the halfwords will be stored (in host byte order).
+ * @param count How many halfwords to read.
+ * @param address Memory address from which to read words; all the
+ *     words must be readable by the currently selected MEM-AP.
+ */
+int mem_ap_read_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer,
+               int count, uint32_t address)
 {
        uint32_t invalue, i;
        int retval = ERROR_OK;
@@ -965,8 +1031,6 @@ int mem_ap_read_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count,
        if (count >= 4)
                return mem_ap_read_buf_packed_u16(swjdp, buffer, count, address);
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        while (count > 0)
        {
                dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address);
@@ -1007,8 +1071,6 @@ static int mem_ap_read_buf_packed_u8(struct swjdp_common *swjdp,
        int retval = ERROR_OK;
        int wcount, blocksize, readcount, i;
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        wcount = count;
 
        while (wcount > 0)
@@ -1050,7 +1112,16 @@ static int mem_ap_read_buf_packed_u8(struct swjdp_common *swjdp,
        return retval;
 }
 
-int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)
+/**
+ * Synchronously read a block of bytes into a buffer
+ * @param swjdp The DAP connected to the MEM-AP.
+ * @param buffer where the bytes will be stored.
+ * @param count How many bytes to read.
+ * @param address Memory address from which to read data; all the
+ *     data must be readable by the currently selected MEM-AP.
+ */
+int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer,
+               int count, uint32_t address)
 {
        uint32_t invalue;
        int retval = ERROR_OK;
@@ -1058,8 +1129,6 @@ int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, u
        if (count >= 4)
                return mem_ap_read_buf_packed_u8(swjdp, buffer, count, address);
 
-       swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
        while (count > 0)
        {
                dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
@@ -1075,7 +1144,11 @@ int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, u
 }
 
 /**
- * Initialize a DAP.
+ * Initialize a DAP.  This sets up the power domains, prepares the DP
+ * for further use, and arranges to use AP #0 for all AP operations
+ * until dap_ap-select() changes that policy.
+ *
+ * @param swjdp The DAP being initialized.
  *
  * @todo Rename this.  We also need an initialization scheme which account
  * for SWD transports not just JTAG; that will need to address differences
@@ -1094,15 +1167,13 @@ int ahbap_debugport_init(struct swjdp_common *swjdp)
        /* Default MEM-AP setup.
         *
         * REVISIT AP #0 may be an inappropriate default for this.
-        * Should we probe, or receve a hint from the caller?
+        * Should we probe, or take a hint from the caller?
         * Presumably we can ignore the possibility of multiple APs.
         */
-       swjdp->apsel = 0;
-       swjdp->ap_csw_value = -1;
-       swjdp->ap_tar_value = -1;
+       swjdp->apsel = !0;
+       dap_ap_select(swjdp, 0);
 
        /* DP initialization */
-       swjdp->trans_mode = TRANS_MODE_ATOMIC;
        dap_dp_read_reg(swjdp, &dummy, DP_CTRL_STAT);
        dap_dp_write_reg(swjdp, SSTICKYERR, DP_CTRL_STAT);
        dap_dp_read_reg(swjdp, &dummy, DP_CTRL_STAT);
@@ -1645,3 +1716,116 @@ DAP_COMMAND_HANDLER(dap_apid_command)
 
        return retval;
 }
+
+/*
+ * This represents the bits which must be sent out on TMS/SWDIO to
+ * switch a DAP implemented using an SWJ-DP module into SWD mode.
+ * These bits are stored (and transmitted) LSB-first.
+ *
+ * See the DAP-Lite specification, section 2.2.5 for information
+ * about making the debug link select SWD or JTAG.  (Similar info
+ * is in a few other ARM documents.)
+ */
+static const uint8_t jtag2swd_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 sequence enables SWD and disables JTAG
+        * NOTE: bits in the DP's IDCODE may expose the need for
+        * an old/deprecated sequence (0xb6 0xed).
+        */
+       0x9e, 0xe7,
+       /* 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,
+};
+
+/**
+ * Put the debug link into SWD mode, if the target supports it.
+ * The link's initial mode may be either JTAG (for example,
+ * with SWJ-DP after reset) or SWD.
+ *
+ * @param target Enters SWD mode (if possible).
+ *
+ * Note that targets using the JTAG-DP do not support SWD, and that
+ * some targets which could otherwise support it may have have been
+ * configured to disable SWD signaling
+ *
+ * @return ERROR_OK or else a fault code.
+ */
+int dap_to_swd(struct target *target)
+{
+       int retval;
+
+       LOG_DEBUG("Enter SWD 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(jtag2swd_bitseq),
+                       jtag2swd_bitseq, TAP_INVALID);
+       if (retval == ERROR_OK)
+               retval = jtag_execute_queue();
+
+       /* REVISIT set up the DAP's ops vector for SWD mode. */
+
+       return retval;
+}
+
+/**
+ * This represents the bits which must be sent out on TMS/SWDIO to
+ * switch a DAP implemented using an SWJ-DP module into JTAG mode.
+ * These bits are stored (and transmitted) LSB-first.
+ *
+ * These bits are stored (and transmitted) LSB-first.
+ */
+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)