arm_adi_v5: prevent possibly endless recursion in dap_dp_init()
[fw/openocd] / src / target / arm_adi_v5.c
index f9b51cdec1e3bb1dc1a66acfb8436a194d1b6594..59bb186c60b325803e2bd8400d3f2c3710b0f7b8 100644 (file)
@@ -51,7 +51,7 @@
  * 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
+ * transaction pipelining.  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.)
  */
@@ -59,7 +59,7 @@
 /*
  * Relevant specifications from ARM include:
  *
- * ARM(tm) Debug Interface v5 Architecture Specification    ARM IHI 0031A
+ * ARM(tm) Debug Interface v5 Architecture Specification    ARM IHI 0031E
  * CoreSight(tm) v1.0 Architecture Specification            ARM IHI 0029B
  *
  * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D
@@ -73,6 +73,8 @@
 #include "jtag/interface.h"
 #include "arm.h"
 #include "arm_adi_v5.h"
+#include "jtag/swd.h"
+#include "transport/transport.h"
 #include <helper/jep106.h>
 #include <helper/time_support.h>
 #include <helper/list.h>
@@ -97,14 +99,15 @@ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address
 
 static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw)
 {
-       csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT |
-               ap->csw_default;
+       csw |= ap->csw_default;
 
        if (csw != ap->csw_value) {
                /* LOG_DEBUG("DAP: Set CSW %x",csw); */
                int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW, csw);
-               if (retval != ERROR_OK)
+               if (retval != ERROR_OK) {
+                       ap->csw_value = 0;
                        return retval;
+               }
                ap->csw_value = csw;
        }
        return ERROR_OK;
@@ -115,8 +118,10 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar)
        if (!ap->tar_valid || tar != ap->tar_value) {
                /* LOG_DEBUG("DAP: Set TAR %x",tar); */
                int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar);
-               if (retval != ERROR_OK)
+               if (retval != ERROR_OK) {
+                       ap->tar_valid = false;
                        return retval;
+               }
                ap->tar_value = tar;
                ap->tar_valid = true;
        }
@@ -153,6 +158,8 @@ static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap)
                        return 2;
                case CSW_32BIT:
                        return 4;
+               default:
+                       return 0;
                }
        case CSW_ADDRINC_PACKED:
                return 4;
@@ -645,17 +652,24 @@ int dap_dp_init(struct adiv5_dap *dap)
 
        LOG_DEBUG("%s", adiv5_dap_name(dap));
 
+       dap->do_reconnect = false;
        dap_invalidate_cache(dap);
 
-       for (size_t i = 0; i < 30; i++) {
-               /* DP initialization */
-
-               retval = dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL);
-               if (retval == ERROR_OK)
-                       break;
-       }
+       /*
+        * Early initialize dap->dp_ctrl_stat.
+        * In jtag mode only, if the following queue run (in dap_dp_poll_register)
+        * fails and sets the sticky error, it will trigger the clearing
+        * of the sticky. Without this initialization system and debug power
+        * would be disabled while clearing the sticky error bit.
+        */
+       dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ;
 
-       retval = dap_queue_dp_write(dap, DP_CTRL_STAT, SSTICKYERR);
+       /*
+        * This write operation clears the sticky error bit in jtag mode only and
+        * is ignored in swd mode. It also powers-up system and debug domains in
+        * both jtag and swd modes, if not done before.
+        */
+       retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR);
        if (retval != ERROR_OK)
                return retval;
 
@@ -663,7 +677,6 @@ int dap_dp_init(struct adiv5_dap *dap)
        if (retval != ERROR_OK)
                return retval;
 
-       dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ;
        retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat);
        if (retval != ERROR_OK)
                return retval;
@@ -705,6 +718,35 @@ int dap_dp_init(struct adiv5_dap *dap)
        return retval;
 }
 
+/**
+ * Initialize a DAP or do reconnect if DAP is not accessible.
+ *
+ * @param dap The DAP being initialized.
+ */
+int dap_dp_init_or_reconnect(struct adiv5_dap *dap)
+{
+       LOG_DEBUG("%s", adiv5_dap_name(dap));
+
+       /*
+        * Early initialize dap->dp_ctrl_stat.
+        * In jtag mode only, if the following atomic reads fail and set the
+        * sticky error, it will trigger the clearing of the sticky. Without this
+        * initialization system and debug power would be disabled while clearing
+        * the sticky error bit.
+        */
+       dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ;
+
+       dap->do_reconnect = false;
+
+       dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL);
+       if (dap->do_reconnect) {
+               /* dap connect calls dap_dp_init() after transport dependent initialization */
+               return dap->ops->connect(dap);
+       } else {
+               return dap_dp_init(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
@@ -764,6 +806,43 @@ int mem_ap_init(struct adiv5_ap *ap)
        return ERROR_OK;
 }
 
+/**
+ * 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.
+ *
+ * Note that targets using the JTAG-DP do not support SWD, and that
+ * some targets which could otherwise support it may have been
+ * configured to disable SWD signaling
+ *
+ * @param dap The DAP used
+ * @return ERROR_OK or else a fault code.
+ */
+int dap_to_swd(struct adiv5_dap *dap)
+{
+       LOG_DEBUG("Enter SWD mode");
+
+       return dap_send_sequence(dap, JTAG_TO_SWD);
+}
+
+/**
+ * Put the debug link into JTAG mode, if the target supports it.
+ * The link's initial mode may be either SWD or JTAG.
+ *
+ * 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
+ *
+ * @param dap The DAP used
+ * @return ERROR_OK or else a fault code.
+ */
+int dap_to_jtag(struct adiv5_dap *dap)
+{
+       LOG_DEBUG("Enter JTAG mode");
+
+       return dap_send_sequence(dap, SWD_TO_JTAG);
+}
+
 /* CID interpretation -- see ARM IHI 0029B section 3
  * and ARM IHI 0031A table 13-3.
  */
@@ -788,7 +867,7 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
        int ap_num;
 
        /* Maximum AP number is 255 since the SELECT register is 8 bits */
-       for (ap_num = 0; ap_num <= 255; ap_num++) {
+       for (ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) {
 
                /* read the IDR register of the Access Port */
                uint32_t id_val = 0;
@@ -809,7 +888,7 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
                 *  3-0  : AP Type (0=JTAG-AP 1=AHB-AP 2=APB-AP 4=AXI-AP)
                 */
 
-               /* Reading register for a non-existant AP should not cause an error,
+               /* Reading register for a non-existent AP should not cause an error,
                 * but just to be sure, try to continue searching if an error does happen.
                 */
                if ((retval == ERROR_OK) &&                  /* Register read success */
@@ -817,7 +896,8 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
                        ((id_val & IDR_TYPE) == type_to_find)) {      /* type matches*/
 
                        LOG_DEBUG("Found %s at AP index: %d (IDR=0x%08" PRIX32 ")",
-                                               (type_to_find == AP_TYPE_AHB_AP)  ? "AHB-AP"  :
+                                               (type_to_find == AP_TYPE_AHB3_AP)  ? "AHB3-AP"  :
+                                               (type_to_find == AP_TYPE_AHB5_AP)  ? "AHB5-AP"  :
                                                (type_to_find == AP_TYPE_APB_AP)  ? "APB-AP"  :
                                                (type_to_find == AP_TYPE_AXI_AP)  ? "AXI-AP"  :
                                                (type_to_find == AP_TYPE_JTAG_AP) ? "JTAG-AP" : "Unknown",
@@ -829,7 +909,8 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
        }
 
        LOG_DEBUG("No %s found",
-                               (type_to_find == AP_TYPE_AHB_AP)  ? "AHB-AP"  :
+                               (type_to_find == AP_TYPE_AHB3_AP)  ? "AHB3-AP"  :
+                               (type_to_find == AP_TYPE_AHB5_AP)  ? "AHB5-AP"  :
                                (type_to_find == AP_TYPE_APB_AP)  ? "APB-AP"  :
                                (type_to_find == AP_TYPE_AXI_AP)  ? "AXI-AP"  :
                                (type_to_find == AP_TYPE_JTAG_AP) ? "JTAG-AP" : "Unknown");
@@ -1007,21 +1088,23 @@ static const struct {
        { ARM_ID, 0x00c, "Cortex-M4 SCS",              "(System Control Space)", },
        { ARM_ID, 0x00d, "CoreSight ETM11",            "(Embedded Trace)", },
        { ARM_ID, 0x00e, "Cortex-M7 FPB",              "(Flash Patch and Breakpoint)", },
+       { ARM_ID, 0x470, "Cortex-M1 ROM",              "(ROM Table)", },
+       { ARM_ID, 0x471, "Cortex-M0 ROM",              "(ROM Table)", },
        { ARM_ID, 0x490, "Cortex-A15 GIC",             "(Generic Interrupt Controller)", },
        { ARM_ID, 0x4a1, "Cortex-A53 ROM",             "(v8 Memory Map ROM Table)", },
        { ARM_ID, 0x4a2, "Cortex-A57 ROM",             "(ROM Table)", },
        { ARM_ID, 0x4a3, "Cortex-A53 ROM",             "(v7 Memory Map ROM Table)", },
        { ARM_ID, 0x4a4, "Cortex-A72 ROM",             "(ROM Table)", },
        { ARM_ID, 0x4a9, "Cortex-A9 ROM",              "(ROM Table)", },
+       { ARM_ID, 0x4aa, "Cortex-A35 ROM",             "(v8 Memory Map ROM Table)", },
        { ARM_ID, 0x4af, "Cortex-A15 ROM",             "(ROM Table)", },
+       { ARM_ID, 0x4b5, "Cortex-R5 ROM",              "(ROM Table)", },
        { ARM_ID, 0x4c0, "Cortex-M0+ ROM",             "(ROM Table)", },
        { ARM_ID, 0x4c3, "Cortex-M3 ROM",              "(ROM Table)", },
        { ARM_ID, 0x4c4, "Cortex-M4 ROM",              "(ROM Table)", },
        { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM",          "(Private Peripheral Bus ROM Table)", },
        { ARM_ID, 0x4c8, "Cortex-M7 ROM",              "(ROM Table)", },
-       { ARM_ID, 0x4b5, "Cortex-R5 ROM",              "(ROM Table)", },
-       { ARM_ID, 0x470, "Cortex-M1 ROM",              "(ROM Table)", },
-       { ARM_ID, 0x471, "Cortex-M0 ROM",              "(ROM Table)", },
+       { ARM_ID, 0x4e0, "Cortex-A35 ROM",             "(v7 Memory Map ROM Table)", },
        { ARM_ID, 0x906, "CoreSight CTI",              "(Cross Trigger)", },
        { ARM_ID, 0x907, "CoreSight ETB",              "(Trace Buffer)", },
        { ARM_ID, 0x908, "CoreSight CSTF",             "(Trace Funnel)", },
@@ -1064,6 +1147,7 @@ static const struct {
        { ARM_ID, 0x9d3, "Cortex-A53 PMU",             "(Performance Monitor Unit)", },
        { ARM_ID, 0x9d7, "Cortex-A57 PMU",             "(Performance Monitor Unit)", },
        { ARM_ID, 0x9d8, "Cortex-A72 PMU",             "(Performance Monitor Unit)", },
+       { ARM_ID, 0x9da, "Cortex-A35 PMU/CTI/ETM",     "(Performance Monitor Unit/Cross Trigger/ETM)", },
        { ARM_ID, 0xc05, "Cortex-A5 Debug",            "(Debug Unit)", },
        { ARM_ID, 0xc07, "Cortex-A7 Debug",            "(Debug Unit)", },
        { ARM_ID, 0xc08, "Cortex-A8 Debug",            "(Debug Unit)", },
@@ -1074,6 +1158,7 @@ static const struct {
        { ARM_ID, 0xc15, "Cortex-R5 Debug",            "(Debug Unit)", },
        { ARM_ID, 0xc17, "Cortex-R7 Debug",            "(Debug Unit)", },
        { ARM_ID, 0xd03, "Cortex-A53 Debug",           "(Debug Unit)", },
+       { ARM_ID, 0xd04, "Cortex-A35 Debug",           "(Debug Unit)", },
        { ARM_ID, 0xd07, "Cortex-A57 Debug",           "(Debug Unit)", },
        { ARM_ID, 0xd08, "Cortex-A72 Debug",           "(Debug Unit)", },
        { 0x097,  0x9af, "MSP432 ROM",                 "(ROM Table)" },
@@ -1084,8 +1169,8 @@ static const struct {
        { 0x0E5,  0x000, "SHARC+/Blackfin+",           "", },
        { 0x0F0,  0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", },
        { 0x3eb,  0x181, "Tegra 186 ROM",              "(ROM Table)", },
-       { 0x3eb,  0x211, "Tegra 210 ROM",              "(ROM Table)", },
        { 0x3eb,  0x202, "Denver ETM",                 "(Denver Embedded Trace)", },
+       { 0x3eb,  0x211, "Tegra 210 ROM",              "(ROM Table)", },
        { 0x3eb,  0x302, "Denver Debug",               "(Debug Unit)", },
        { 0x3eb,  0x402, "Denver PMU",                 "(Performance Monitor Unit)", },
        /* legacy comment: 0x113: what? */
@@ -1093,7 +1178,7 @@ static const struct {
        { ANY_ID, 0x343, "TI DAPCTL",                  "", }, /* from OMAP3 memmap */
 };
 
-static int dap_rom_display(struct command_context *cmd_ctx,
+static int dap_rom_display(struct command_invocation *cmd,
                                struct adiv5_ap *ap, uint32_t dbgbase, int depth)
 {
        int retval;
@@ -1102,7 +1187,7 @@ static int dap_rom_display(struct command_context *cmd_ctx,
        char tabs[16] = "";
 
        if (depth > 16) {
-               command_print(cmd_ctx, "\tTables too deep");
+               command_print(cmd, "\tTables too deep");
                return ERROR_FAIL;
        }
 
@@ -1110,25 +1195,25 @@ static int dap_rom_display(struct command_context *cmd_ctx,
                snprintf(tabs, sizeof(tabs), "[L%02d] ", depth);
 
        uint32_t base_addr = dbgbase & 0xFFFFF000;
-       command_print(cmd_ctx, "\t\tComponent base address 0x%08" PRIx32, base_addr);
+       command_print(cmd, "\t\tComponent base address 0x%08" PRIx32, base_addr);
 
        retval = dap_read_part_id(ap, base_addr, &cid, &pid);
        if (retval != ERROR_OK) {
-               command_print(cmd_ctx, "\t\tCan't read component, the corresponding core might be turned off");
+               command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off");
                return ERROR_OK; /* Don't abort recursion */
        }
 
        if (!is_dap_cid_ok(cid)) {
-               command_print(cmd_ctx, "\t\tInvalid CID 0x%08" PRIx32, cid);
+               command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, cid);
                return ERROR_OK; /* Don't abort recursion */
        }
 
        /* component may take multiple 4K pages */
        uint32_t size = (pid >> 36) & 0xf;
        if (size > 0)
-               command_print(cmd_ctx, "\t\tStart address 0x%08" PRIx32, (uint32_t)(base_addr - 0x1000 * size));
+               command_print(cmd, "\t\tStart address 0x%08" PRIx32, (uint32_t)(base_addr - 0x1000 * size));
 
-       command_print(cmd_ctx, "\t\tPeripheral ID 0x%010" PRIx64, pid);
+       command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, pid);
 
        uint8_t class = (cid >> 12) & 0xf;
        uint16_t part_num = pid & 0xfff;
@@ -1136,12 +1221,12 @@ static int dap_rom_display(struct command_context *cmd_ctx,
 
        if (designer_id & 0x80) {
                /* JEP106 code */
-               command_print(cmd_ctx, "\t\tDesigner is 0x%03" PRIx16 ", %s",
+               command_print(cmd, "\t\tDesigner is 0x%03" PRIx16 ", %s",
                                designer_id, jep106_manufacturer(designer_id >> 8, designer_id & 0x7f));
        } else {
                /* Legacy ASCII ID, clear invalid bits */
                designer_id &= 0x7f;
-               command_print(cmd_ctx, "\t\tDesigner ASCII code 0x%02" PRIx16 ", %s",
+               command_print(cmd, "\t\tDesigner ASCII code 0x%02" PRIx16 ", %s",
                                designer_id, designer_id == 0x41 ? "ARM" : "<unknown>");
        }
 
@@ -1163,8 +1248,8 @@ static int dap_rom_display(struct command_context *cmd_ctx,
                break;
        }
 
-       command_print(cmd_ctx, "\t\tPart is 0x%" PRIx16", %s %s", part_num, type, full);
-       command_print(cmd_ctx, "\t\tComponent class is 0x%" PRIx8 ", %s", class, class_description[class]);
+       command_print(cmd, "\t\tPart is 0x%" PRIx16", %s %s", part_num, type, full);
+       command_print(cmd, "\t\tComponent class is 0x%" PRIx8 ", %s", class, class_description[class]);
 
        if (class == 1) { /* ROM Table */
                uint32_t memtype;
@@ -1173,9 +1258,9 @@ static int dap_rom_display(struct command_context *cmd_ctx,
                        return retval;
 
                if (memtype & 0x01)
-                       command_print(cmd_ctx, "\t\tMEMTYPE system memory present on bus");
+                       command_print(cmd, "\t\tMEMTYPE system memory present on bus");
                else
-                       command_print(cmd_ctx, "\t\tMEMTYPE system memory not present: dedicated debug bus");
+                       command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
 
                /* Read ROM table entries from base address until we get 0x00000000 or reach the reserved area */
                for (uint16_t entry_offset = 0; entry_offset < 0xF00; entry_offset += 4) {
@@ -1183,17 +1268,17 @@ static int dap_rom_display(struct command_context *cmd_ctx,
                        retval = mem_ap_read_atomic_u32(ap, base_addr | entry_offset, &romentry);
                        if (retval != ERROR_OK)
                                return retval;
-                       command_print(cmd_ctx, "\t%sROMTABLE[0x%x] = 0x%" PRIx32 "",
+                       command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%" PRIx32 "",
                                        tabs, entry_offset, romentry);
                        if (romentry & 0x01) {
                                /* Recurse */
-                               retval = dap_rom_display(cmd_ctx, ap, base_addr + (romentry & 0xFFFFF000), depth + 1);
+                               retval = dap_rom_display(cmd, ap, base_addr + (romentry & 0xFFFFF000), depth + 1);
                                if (retval != ERROR_OK)
                                        return retval;
                        } else if (romentry != 0) {
-                               command_print(cmd_ctx, "\t\tComponent not present");
+                               command_print(cmd, "\t\tComponent not present");
                        } else {
-                               command_print(cmd_ctx, "\t%s\tEnd of ROM table", tabs);
+                               command_print(cmd, "\t%s\tEnd of ROM table", tabs);
                                break;
                        }
                }
@@ -1315,7 +1400,7 @@ static int dap_rom_display(struct command_context *cmd_ctx,
                        }
                        break;
                case 6:
-                       major = "Perfomance Monitor";
+                       major = "Performance Monitor";
                        switch (minor) {
                        case 0:
                                subtype = "other";
@@ -1338,7 +1423,7 @@ static int dap_rom_display(struct command_context *cmd_ctx,
                        }
                        break;
                }
-               command_print(cmd_ctx, "\t\tType is 0x%02" PRIx8 ", %s, %s",
+               command_print(cmd, "\t\tType is 0x%02" PRIx8 ", %s, %s",
                                (uint8_t)(devtype & 0xff),
                                major, subtype);
                /* REVISIT also show 0xfc8 DevId */
@@ -1347,7 +1432,7 @@ static int dap_rom_display(struct command_context *cmd_ctx,
        return ERROR_OK;
 }
 
-int dap_info_command(struct command_context *cmd_ctx,
+int dap_info_command(struct command_invocation *cmd,
                struct adiv5_ap *ap)
 {
        int retval;
@@ -1359,27 +1444,30 @@ int dap_info_command(struct command_context *cmd_ctx,
        if (retval != ERROR_OK)
                return retval;
 
-       command_print(cmd_ctx, "AP ID register 0x%8.8" PRIx32, apid);
+       command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid);
        if (apid == 0) {
-               command_print(cmd_ctx, "No AP found at this ap 0x%x", ap->ap_num);
+               command_print(cmd, "No AP found at this ap 0x%x", ap->ap_num);
                return ERROR_FAIL;
        }
 
        switch (apid & (IDR_JEP106 | IDR_TYPE)) {
        case IDR_JEP106_ARM | AP_TYPE_JTAG_AP:
-               command_print(cmd_ctx, "\tType is JTAG-AP");
+               command_print(cmd, "\tType is JTAG-AP");
+               break;
+       case IDR_JEP106_ARM | AP_TYPE_AHB3_AP:
+               command_print(cmd, "\tType is MEM-AP AHB3");
                break;
-       case IDR_JEP106_ARM | AP_TYPE_AHB_AP:
-               command_print(cmd_ctx, "\tType is MEM-AP AHB");
+       case IDR_JEP106_ARM | AP_TYPE_AHB5_AP:
+               command_print(cmd, "\tType is MEM-AP AHB5");
                break;
        case IDR_JEP106_ARM | AP_TYPE_APB_AP:
-               command_print(cmd_ctx, "\tType is MEM-AP APB");
+               command_print(cmd, "\tType is MEM-AP APB");
                break;
        case IDR_JEP106_ARM | AP_TYPE_AXI_AP:
-               command_print(cmd_ctx, "\tType is MEM-AP AXI");
+               command_print(cmd, "\tType is MEM-AP AXI");
                break;
        default:
-               command_print(cmd_ctx, "\tUnknown AP type");
+               command_print(cmd, "\tUnknown AP type");
                break;
        }
 
@@ -1388,17 +1476,17 @@ int dap_info_command(struct command_context *cmd_ctx,
         */
        mem_ap = (apid & IDR_CLASS) == AP_CLASS_MEM_AP;
        if (mem_ap) {
-               command_print(cmd_ctx, "MEM-AP BASE 0x%8.8" PRIx32, dbgbase);
+               command_print(cmd, "MEM-AP BASE 0x%8.8" PRIx32, dbgbase);
 
                if (dbgbase == 0xFFFFFFFF || (dbgbase & 0x3) == 0x2) {
-                       command_print(cmd_ctx, "\tNo ROM table present");
+                       command_print(cmd, "\tNo ROM table present");
                } else {
                        if (dbgbase & 0x01)
-                               command_print(cmd_ctx, "\tValid ROM table present");
+                               command_print(cmd, "\tValid ROM table present");
                        else
-                               command_print(cmd_ctx, "\tROM table in legacy format");
+                               command_print(cmd, "\tROM table in legacy format");
 
-                       dap_rom_display(cmd_ctx, ap, dbgbase & 0xFFFFF000, 0);
+                       dap_rom_display(cmd, ap, dbgbase & 0xFFFFF000, 0);
                }
        }
 
@@ -1407,15 +1495,118 @@ int dap_info_command(struct command_context *cmd_ctx,
 
 enum adiv5_cfg_param {
        CFG_DAP,
-       CFG_AP_NUM
+       CFG_AP_NUM,
+       CFG_BASEADDR,
+       CFG_CTIBASE, /* DEPRECATED */
 };
 
 static const Jim_Nvp nvp_config_opts[] = {
-       { .name = "-dap",    .value = CFG_DAP },
-       { .name = "-ap-num", .value = CFG_AP_NUM },
+       { .name = "-dap",       .value = CFG_DAP },
+       { .name = "-ap-num",    .value = CFG_AP_NUM },
+       { .name = "-baseaddr",  .value = CFG_BASEADDR },
+       { .name = "-ctibase",   .value = CFG_CTIBASE }, /* DEPRECATED */
        { .name = NULL, .value = -1 }
 };
 
+static int adiv5_jim_spot_configure(Jim_GetOptInfo *goi,
+               struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p)
+{
+       if (!goi->argc)
+               return JIM_OK;
+
+       Jim_SetEmptyResult(goi->interp);
+
+       Jim_Nvp *n;
+       int e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts,
+                               goi->argv[0], &n);
+       if (e != JIM_OK)
+               return JIM_CONTINUE;
+
+       /* base_p can be NULL, then '-baseaddr' option is treated as unknown */
+       if (!base_p && (n->value == CFG_BASEADDR || n->value == CFG_CTIBASE))
+               return JIM_CONTINUE;
+
+       e = Jim_GetOpt_Obj(goi, NULL);
+       if (e != JIM_OK)
+               return e;
+
+       switch (n->value) {
+       case CFG_DAP:
+               if (goi->isconfigure) {
+                       Jim_Obj *o_t;
+                       struct adiv5_dap *dap;
+                       e = Jim_GetOpt_Obj(goi, &o_t);
+                       if (e != JIM_OK)
+                               return e;
+                       dap = dap_instance_by_jim_obj(goi->interp, o_t);
+                       if (!dap) {
+                               Jim_SetResultString(goi->interp, "DAP name invalid!", -1);
+                               return JIM_ERR;
+                       }
+                       if (*dap_p && *dap_p != dap) {
+                               Jim_SetResultString(goi->interp,
+                                       "DAP assignment cannot be changed!", -1);
+                               return JIM_ERR;
+                       }
+                       *dap_p = dap;
+               } else {
+                       if (goi->argc)
+                               goto err_no_param;
+                       if (!*dap_p) {
+                               Jim_SetResultString(goi->interp, "DAP not configured", -1);
+                               return JIM_ERR;
+                       }
+                       Jim_SetResultString(goi->interp, adiv5_dap_name(*dap_p), -1);
+               }
+               break;
+
+       case CFG_AP_NUM:
+               if (goi->isconfigure) {
+                       jim_wide ap_num;
+                       e = Jim_GetOpt_Wide(goi, &ap_num);
+                       if (e != JIM_OK)
+                               return e;
+                       if (ap_num < 0 || ap_num > DP_APSEL_MAX) {
+                               Jim_SetResultString(goi->interp, "Invalid AP number!", -1);
+                               return JIM_ERR;
+                       }
+                       *ap_num_p = ap_num;
+               } else {
+                       if (goi->argc)
+                               goto err_no_param;
+                       if (*ap_num_p == DP_APSEL_INVALID) {
+                               Jim_SetResultString(goi->interp, "AP number not configured", -1);
+                               return JIM_ERR;
+                       }
+                       Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *ap_num_p));
+               }
+               break;
+
+       case CFG_CTIBASE:
+               LOG_WARNING("DEPRECATED! use \'-baseaddr' not \'-ctibase\'");
+               /* fall through */
+       case CFG_BASEADDR:
+               if (goi->isconfigure) {
+                       jim_wide base;
+                       e = Jim_GetOpt_Wide(goi, &base);
+                       if (e != JIM_OK)
+                               return e;
+                       *base_p = (uint32_t)base;
+               } else {
+                       if (goi->argc)
+                               goto err_no_param;
+                       Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *base_p));
+               }
+               break;
+       };
+
+       return JIM_OK;
+
+err_no_param:
+       Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
+       return JIM_ERR;
+}
+
 int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi)
 {
        struct adiv5_private_config *pc;
@@ -1424,92 +1615,25 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi)
        pc = (struct adiv5_private_config *)target->private_config;
        if (pc == NULL) {
                pc = calloc(1, sizeof(struct adiv5_private_config));
-               pc->ap_num = -1;
+               pc->ap_num = DP_APSEL_INVALID;
                target->private_config = pc;
        }
 
        target->has_dap = true;
 
-       if (goi->argc > 0) {
-               Jim_Nvp *n;
-
-               Jim_SetEmptyResult(goi->interp);
-
-               /* check first if topmost item is for us */
-               e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts,
-                                                                  goi->argv[0], &n);
-               if (e != JIM_OK)
-                       return JIM_CONTINUE;
-
-               e = Jim_GetOpt_Obj(goi, NULL);
-               if (e != JIM_OK)
-                       return e;
-
-               switch (n->value) {
-               case CFG_DAP:
-                       if (goi->isconfigure) {
-                               Jim_Obj *o_t;
-                               struct adiv5_dap *dap;
-                               e = Jim_GetOpt_Obj(goi, &o_t);
-                               if (e != JIM_OK)
-                                       return e;
-                               dap = dap_instance_by_jim_obj(goi->interp, o_t);
-                               if (dap == NULL) {
-                                       Jim_SetResultString(goi->interp, "DAP name invalid!", -1);
-                                       return JIM_ERR;
-                               }
-                               if (pc->dap != NULL && pc->dap != dap) {
-                                       Jim_SetResultString(goi->interp,
-                                               "DAP assignment cannot be changed after target was created!", -1);
-                                       return JIM_ERR;
-                               }
-                               if (target->tap_configured) {
-                                       Jim_SetResultString(goi->interp,
-                                               "-chain-position and -dap configparams are mutually exclusive!", -1);
-                                       return JIM_ERR;
-                               }
-                               pc->dap = dap;
-                               target->tap = dap->tap;
-                               target->dap_configured = true;
-                       } else {
-                               if (goi->argc != 0) {
-                                       Jim_WrongNumArgs(goi->interp,
-                                                                               goi->argc, goi->argv,
-                                       "NO PARAMS");
-                                       return JIM_ERR;
-                               }
-
-                               if (pc->dap == NULL) {
-                                       Jim_SetResultString(goi->interp, "DAP not configured", -1);
-                                       return JIM_ERR;
-                               }
-                               Jim_SetResultString(goi->interp, adiv5_dap_name(pc->dap), -1);
-                       }
-                       break;
+       e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL);
+       if (e != JIM_OK)
+               return e;
 
-               case CFG_AP_NUM:
-                       if (goi->isconfigure) {
-                               jim_wide ap_num;
-                               e = Jim_GetOpt_Wide(goi, &ap_num);
-                               if (e != JIM_OK)
-                                       return e;
-                               pc->ap_num = ap_num;
-                       } else {
-                               if (goi->argc != 0) {
-                                       Jim_WrongNumArgs(goi->interp,
-                                                                        goi->argc, goi->argv,
-                                         "NO PARAMS");
-                                       return JIM_ERR;
-                               }
-
-                               if (pc->ap_num < 0) {
-                                       Jim_SetResultString(goi->interp, "AP number not configured", -1);
-                                       return JIM_ERR;
-                               }
-                               Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, (int)pc->ap_num));
-                       }
-                       break;
+       if (pc->dap && !target->dap_configured) {
+               if (target->tap_configured) {
+                       pc->dap = NULL;
+                       Jim_SetResultString(goi->interp,
+                               "-chain-position and -dap configparams are mutually exclusive!", -1);
+                       return JIM_ERR;
                }
+               target->tap = pc->dap->tap;
+               target->dap_configured = true;
        }
 
        return JIM_OK;
@@ -1526,6 +1650,19 @@ int adiv5_verify_config(struct adiv5_private_config *pc)
        return ERROR_OK;
 }
 
+int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg,
+               Jim_GetOptInfo *goi)
+{
+       return adiv5_jim_spot_configure(goi, &cfg->dap, &cfg->ap_num, &cfg->base);
+}
+
+int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p)
+{
+       p->dap = NULL;
+       p->ap_num = DP_APSEL_INVALID;
+       p->base = 0;
+       return ERROR_OK;
+}
 
 COMMAND_HANDLER(handle_dap_info_command)
 {
@@ -1538,14 +1675,16 @@ COMMAND_HANDLER(handle_dap_info_command)
                break;
        case 1:
                COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
-               if (apsel >= 256)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               if (apsel > DP_APSEL_MAX) {
+                       command_print(CMD, "Invalid AP number");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
                break;
        default:
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       return dap_info_command(CMD_CTX, &dap->ap[apsel]);
+       return dap_info_command(CMD, &dap->ap[apsel]);
 }
 
 COMMAND_HANDLER(dap_baseaddr_command)
@@ -1561,8 +1700,10 @@ COMMAND_HANDLER(dap_baseaddr_command)
        case 1:
                COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
                /* AP address is in bits 31:24 of DP_SELECT */
-               if (apsel >= 256)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               if (apsel > DP_APSEL_MAX) {
+                       command_print(CMD, "Invalid AP number");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
                break;
        default:
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1580,7 +1721,7 @@ COMMAND_HANDLER(dap_baseaddr_command)
        if (retval != ERROR_OK)
                return retval;
 
-       command_print(CMD_CTX, "0x%8.8" PRIx32, baseaddr);
+       command_print(CMD, "0x%8.8" PRIx32, baseaddr);
 
        return retval;
 }
@@ -1602,7 +1743,7 @@ COMMAND_HANDLER(dap_memaccess_command)
        }
        dap->ap[dap->apsel].memaccess_tck = memaccess_tck;
 
-       command_print(CMD_CTX, "memory bus access delay set to %" PRIi32 " tck",
+       command_print(CMD, "memory bus access delay set to %" PRIu32 " tck",
                        dap->ap[dap->apsel].memaccess_tck);
 
        return ERROR_OK;
@@ -1611,58 +1752,59 @@ COMMAND_HANDLER(dap_memaccess_command)
 COMMAND_HANDLER(dap_apsel_command)
 {
        struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
-       uint32_t apsel, apid;
-       int retval;
+       uint32_t apsel;
 
        switch (CMD_ARGC) {
        case 0:
-               apsel = dap->apsel;
-               break;
+               command_print(CMD, "%" PRIu32, dap->apsel);
+               return ERROR_OK;
        case 1:
                COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
                /* AP address is in bits 31:24 of DP_SELECT */
-               if (apsel >= 256)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               if (apsel > DP_APSEL_MAX) {
+                       command_print(CMD, "Invalid AP number");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
                break;
        default:
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        dap->apsel = apsel;
-
-       retval = dap_queue_ap_read(dap_ap(dap, apsel), AP_REG_IDR, &apid);
-       if (retval != ERROR_OK)
-               return retval;
-       retval = dap_run(dap);
-       if (retval != ERROR_OK)
-               return retval;
-
-       command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32,
-                       apsel, apid);
-
-       return retval;
+       return ERROR_OK;
 }
 
 COMMAND_HANDLER(dap_apcsw_command)
 {
        struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
        uint32_t apcsw = dap->ap[dap->apsel].csw_default;
-       uint32_t sprot = 0;
+       uint32_t csw_val, csw_mask;
 
        switch (CMD_ARGC) {
        case 0:
-               command_print(CMD_CTX, "apsel %" PRIi32 " selected, csw 0x%8.8" PRIx32,
-                       (dap->apsel), apcsw);
-               break;
+               command_print(CMD, "ap %" PRIu32 " selected, csw 0x%8.8" PRIx32,
+                       dap->apsel, apcsw);
+               return ERROR_OK;
        case 1:
-               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], sprot);
-               /* AP address is in bits 31:24 of DP_SELECT */
-               if (sprot > 1)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
-               if (sprot)
-                       apcsw |= CSW_SPROT;
+               if (strcmp(CMD_ARGV[0], "default") == 0)
+                       csw_val = CSW_AHB_DEFAULT;
                else
-                       apcsw &= ~CSW_SPROT;
+                       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val);
+
+               if (csw_val & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) {
+                       LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+               apcsw = csw_val;
+               break;
+       case 2:
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], csw_mask);
+               if (csw_mask & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) {
+                       LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+               apcsw = (apcsw & ~csw_mask) | (csw_val & csw_mask);
                break;
        default:
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1687,8 +1829,10 @@ COMMAND_HANDLER(dap_apid_command)
        case 1:
                COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
                /* AP address is in bits 31:24 of DP_SELECT */
-               if (apsel >= 256)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               if (apsel > DP_APSEL_MAX) {
+                       command_print(CMD, "Invalid AP number");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
                break;
        default:
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1701,7 +1845,7 @@ COMMAND_HANDLER(dap_apid_command)
        if (retval != ERROR_OK)
                return retval;
 
-       command_print(CMD_CTX, "0x%8.8" PRIx32, apid);
+       command_print(CMD, "0x%8.8" PRIx32, apid);
 
        return retval;
 }
@@ -1710,6 +1854,7 @@ COMMAND_HANDLER(dap_apreg_command)
 {
        struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
        uint32_t apsel, reg, value;
+       struct adiv5_ap *ap;
        int retval;
 
        if (CMD_ARGC < 2 || CMD_ARGC > 3)
@@ -1717,18 +1862,38 @@ COMMAND_HANDLER(dap_apreg_command)
 
        COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
        /* AP address is in bits 31:24 of DP_SELECT */
-       if (apsel >= 256)
-               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (apsel > DP_APSEL_MAX) {
+               command_print(CMD, "Invalid AP number");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       ap = dap_ap(dap, apsel);
 
        COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg);
-       if (reg >= 256 || (reg & 3))
-               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (reg >= 256 || (reg & 3)) {
+               command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
 
        if (CMD_ARGC == 3) {
                COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
-               retval = dap_queue_ap_write(dap_ap(dap, apsel), reg, value);
+               switch (reg) {
+               case MEM_AP_REG_CSW:
+                       ap->csw_value = 0;  /* invalid, in case write fails */
+                       retval = dap_queue_ap_write(ap, reg, value);
+                       if (retval == ERROR_OK)
+                               ap->csw_value = value;
+                       break;
+               case MEM_AP_REG_TAR:
+                       ap->tar_valid = false;  /* invalid, force write */
+                       retval = mem_ap_setup_tar(ap, value);
+                       break;
+               default:
+                       retval = dap_queue_ap_write(ap, reg, value);
+                       break;
+               }
        } else {
-               retval = dap_queue_ap_read(dap_ap(dap, apsel), reg, &value);
+               retval = dap_queue_ap_read(ap, reg, &value);
        }
        if (retval == ERROR_OK)
                retval = dap_run(dap);
@@ -1737,32 +1902,49 @@ COMMAND_HANDLER(dap_apreg_command)
                return retval;
 
        if (CMD_ARGC == 2)
-               command_print(CMD_CTX, "0x%08" PRIx32, value);
+               command_print(CMD, "0x%08" PRIx32, value);
 
        return retval;
 }
 
-COMMAND_HANDLER(dap_ti_be_32_quirks_command)
+COMMAND_HANDLER(dap_dpreg_command)
 {
        struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
-       uint32_t enable = dap->ti_be_32_quirks;
+       uint32_t reg, value;
+       int retval;
 
-       switch (CMD_ARGC) {
-       case 0:
-               break;
-       case 1:
-               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], enable);
-               if (enable > 1)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
-               break;
-       default:
+       if (CMD_ARGC < 1 || CMD_ARGC > 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg);
+       if (reg >= 256 || (reg & 3)) {
+               command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
        }
-       dap->ti_be_32_quirks = enable;
-       command_print(CMD_CTX, "TI BE-32 quirks mode %s",
-               enable ? "enabled" : "disabled");
 
-       return 0;
+       if (CMD_ARGC == 2) {
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+               retval = dap_queue_dp_write(dap, reg, value);
+       } else {
+               retval = dap_queue_dp_read(dap, reg, &value);
+       }
+       if (retval == ERROR_OK)
+               retval = dap_run(dap);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (CMD_ARGC == 1)
+               command_print(CMD, "0x%08" PRIx32, value);
+
+       return retval;
+}
+
+COMMAND_HANDLER(dap_ti_be_32_quirks_command)
+{
+       struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
+       return CALL_COMMAND_HANDLER(handle_command_parse_bool, &dap->ti_be_32_quirks,
+               "TI BE-32 quirks mode");
 }
 
 const struct command_registration dap_instance_commands[] = {
@@ -1777,7 +1959,7 @@ const struct command_registration dap_instance_commands[] = {
        {
                .name = "apsel",
                .handler = dap_apsel_command,
-               .mode = COMMAND_EXEC,
+               .mode = COMMAND_ANY,
                .help = "Set the currently selected AP (default 0) "
                        "and display the result",
                .usage = "[ap_num]",
@@ -1785,9 +1967,9 @@ const struct command_registration dap_instance_commands[] = {
        {
                .name = "apcsw",
                .handler = dap_apcsw_command,
-               .mode = COMMAND_EXEC,
-               .help = "Set csw access bit ",
-               .usage = "[sprot]",
+               .mode = COMMAND_ANY,
+               .help = "Set CSW default bits",
+               .usage = "[value [mask]]",
        },
 
        {
@@ -1806,6 +1988,14 @@ const struct command_registration dap_instance_commands[] = {
                        "(reg is byte address of a word register, like 0 4 8...)",
                .usage = "ap_num reg [value]",
        },
+       {
+               .name = "dpreg",
+               .handler = dap_dpreg_command,
+               .mode = COMMAND_EXEC,
+               .help = "read/write a register from DP "
+                       "(reg is byte address (bank << 4 | reg) of a word register, like 0 4 8...)",
+               .usage = "reg [value]",
+       },
        {
                .name = "baseaddr",
                .handler = dap_baseaddr_command,