adiv6: add support for ROM tables in AP
authorAntonio Borneo <borneo.antonio@gmail.com>
Wed, 11 Aug 2021 13:29:45 +0000 (15:29 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Fri, 24 Jun 2022 21:38:52 +0000 (21:38 +0000)
ADIv6 adds AP that only contain a ROM table in the AP itself, that
can point to other AP containing either another AP level ROM table
or a MEM-AP to be parsed as usual.

Add support for parsing AP level ROM tables.

Change-Id: Ic25863b16463b8a6adc3b15e26db7fdca858d6df
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6467
Tested-by: jenkins
src/target/arm_adi_v5.c

index ad4d7a7254416d0d9c87c466ad55c18e7b3ab703..84518b0a10199e856ddcb73a204fe0d12e2e7c8c 100644 (file)
@@ -928,6 +928,7 @@ static const struct {
 };
 
 #define DEVARCH_ID_MASK         (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK)
+#define DEVARCH_MEM_AP          ARCH_ID(ARM_ID, 0x0A17)
 #define DEVARCH_ROM_C_0X9       ARCH_ID(ARM_ID, 0x0AF7)
 
 static const char *class0x9_devarch_description(uint32_t devarch)
@@ -1180,6 +1181,17 @@ int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap
        return ERROR_OK;
 }
 
+/**
+ * Method to access the CoreSight component.
+ * On ADIv5, CoreSight components are on the bus behind a MEM-AP.
+ * On ADIv6, CoreSight components can either be on the bus behind a MEM-AP
+ * or directly in the AP.
+ */
+enum coresight_access_mode {
+       CS_ACCESS_AP,
+       CS_ACCESS_MEM_AP,
+};
+
 /** Holds registers and coordinates of a CoreSight component */
 struct cs_component_vals {
        struct adiv5_ap *ap;
@@ -1189,19 +1201,43 @@ struct cs_component_vals {
        uint32_t devarch;
        uint32_t devid;
        uint32_t devtype_memtype;
+       enum coresight_access_mode mode;
 };
 
+/**
+ * Helper to read CoreSight component's registers, either on the bus
+ * behind a MEM-AP or directly in the AP.
+ *
+ * @param mode           Method to access the component (AP or MEM-AP).
+ * @param ap             Pointer to AP containing the component.
+ * @param component_base On MEM-AP access method, base address of the component.
+ * @param reg            Offset of the component's register to read.
+ * @param value          Pointer to the store the read value.
+ *
+ * @return ERROR_OK on success, else a fault code.
+ */
+static int dap_queue_read_reg(enum coresight_access_mode mode, struct adiv5_ap *ap,
+               uint64_t component_base, unsigned int reg, uint32_t *value)
+{
+       if (mode == CS_ACCESS_AP)
+               return dap_queue_ap_read(ap, reg, value);
+
+       /* mode == CS_ACCESS_MEM_AP */
+       return mem_ap_read_u32(ap, component_base + reg, value);
+}
+
 /**
  * Read the CoreSight registers needed during ROM Table Parsing (RTP).
  *
+ * @param mode           Method to access the component (AP or MEM-AP).
  * @param ap             Pointer to AP containing the component.
  * @param component_base On MEM-AP access method, base address of the component.
  * @param v              Pointer to the struct holding the value of registers.
  *
  * @return ERROR_OK on success, else a fault code.
  */
-static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
-               struct cs_component_vals *v)
+static int rtp_read_cs_regs(enum coresight_access_mode mode, struct adiv5_ap *ap,
+               target_addr_t component_base, struct cs_component_vals *v)
 {
        assert(IS_ALIGNED(component_base, ARM_CS_ALIGN));
        assert(ap && v);
@@ -1212,6 +1248,7 @@ static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
 
        v->ap = ap;
        v->component_base = component_base;
+       v->mode = mode;
 
        /* sort by offset to gain speed */
 
@@ -1221,35 +1258,35 @@ static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
         * without triggering error. Read them for eventual use on Class 0x9.
         */
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVARCH, &v->devarch);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVARCH, &v->devarch);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVID, &v->devid);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVID, &v->devid);
 
        /* Same address as ARM_CS_C1_MEMTYPE */
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVTYPE, &v->devtype_memtype);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVTYPE, &v->devtype_memtype);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR4, &pid4);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR4, &pid4);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR0, &pid0);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR0, &pid0);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR1, &pid1);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR1, &pid1);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR2, &pid2);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR2, &pid2);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR3, &pid3);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR3, &pid3);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR0, &cid0);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR0, &cid0);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR1, &cid1);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR1, &cid1);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR2, &cid2);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR2, &cid2);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR3, &cid3);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR3, &cid3);
 
        if (retval == ERROR_OK)
                retval = dap_run(ap->dap);
@@ -1572,6 +1609,14 @@ static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype)
  * Actions/operations to be executed while parsing ROM tables.
  */
 struct rtp_ops {
+       /**
+        * Executed at the start of a new AP, typically to print the AP header.
+        * @param ap        Pointer to AP.
+        * @param depth     The current depth level of ROM table.
+        * @param priv      Pointer to private data.
+        * @return          ERROR_OK on success, else a fault code.
+        */
+       int (*ap_header)(struct adiv5_ap *ap, int depth, void *priv);
        /**
         * Executed at the start of a new MEM-AP, typically to print the MEM-AP header.
         * @param retval    Error encountered while reading AP.
@@ -1612,6 +1657,18 @@ struct rtp_ops {
        void *priv;
 };
 
+/**
+ * Wrapper around struct rtp_ops::ap_header.
+ */
+static int rtp_ops_ap_header(const struct rtp_ops *ops,
+               struct adiv5_ap *ap, int depth)
+{
+       if (ops->ap_header)
+               return ops->ap_header(ap, depth, ops->priv);
+
+       return ERROR_OK;
+}
+
 /**
  * Wrapper around struct rtp_ops::mem_ap_header.
  * Input parameter @a retval is propagated.
@@ -1671,13 +1728,18 @@ static int rtp_ops_rom_table_entry(const struct rtp_ops *ops,
  */
 #define CORESIGHT_COMPONENT_FOUND (1)
 
-static int rtp_cs_component(const struct rtp_ops *ops,
-               struct adiv5_ap *ap, target_addr_t dbgbase, int depth);
+static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth);
+static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops,
+               struct adiv5_ap *ap, target_addr_t dbgbase, bool *is_mem_ap, int depth);
 
-static int rtp_rom_loop(const struct rtp_ops *ops,
+static int rtp_rom_loop(enum coresight_access_mode mode, const struct rtp_ops *ops,
                struct adiv5_ap *ap, target_addr_t base_address, int depth,
                unsigned int width, unsigned int max_entries)
 {
+       /* ADIv6 AP ROM table provide offset from current AP */
+       if (mode == CS_ACCESS_AP)
+               base_address = ap->ap_num;
+
        assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
 
        unsigned int offset = 0;
@@ -1687,10 +1749,10 @@ static int rtp_rom_loop(const struct rtp_ops *ops,
                target_addr_t component_base;
                unsigned int saved_offset = offset;
 
-               int retval = mem_ap_read_u32(ap, base_address + offset, &romentry_low);
+               int retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_low);
                offset += 4;
                if (retval == ERROR_OK && width == 64) {
-                       retval = mem_ap_read_u32(ap, base_address + offset, &romentry_high);
+                       retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_high);
                        offset += 4;
                }
                if (retval == ERROR_OK)
@@ -1724,7 +1786,18 @@ static int rtp_rom_loop(const struct rtp_ops *ops,
                        continue;
 
                /* Recurse */
-               retval = rtp_cs_component(ops, ap, component_base, depth + 1);
+               if (mode == CS_ACCESS_AP) {
+                       struct adiv5_ap *next_ap = dap_get_ap(ap->dap, component_base);
+                       if (!next_ap) {
+                               LOG_DEBUG("Wrong AP # 0x%" PRIx64, component_base);
+                               continue;
+                       }
+                       retval = rtp_ap(ops, next_ap, depth + 1);
+                       dap_put_ap(next_ap);
+               } else {
+                       /* mode == CS_ACCESS_MEM_AP */
+                       retval = rtp_cs_component(mode, ops, ap, component_base, NULL, depth + 1);
+               }
                if (retval == CORESIGHT_COMPONENT_FOUND)
                        return CORESIGHT_COMPONENT_FOUND;
                if (retval != ERROR_OK) {
@@ -1737,18 +1810,21 @@ static int rtp_rom_loop(const struct rtp_ops *ops,
        return ERROR_OK;
 }
 
-static int rtp_cs_component(const struct rtp_ops *ops,
-               struct adiv5_ap *ap, target_addr_t base_address, int depth)
+static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops,
+               struct adiv5_ap *ap, target_addr_t base_address, bool *is_mem_ap, int depth)
 {
        struct cs_component_vals v;
        int retval;
 
        assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
 
+       if (is_mem_ap)
+               *is_mem_ap = false;
+
        if (depth > ROM_TABLE_MAX_DEPTH)
                retval = ERROR_FAIL;
        else
-               retval = rtp_read_cs_regs(ap, base_address, &v);
+               retval = rtp_read_cs_regs(mode, ap, base_address, &v);
 
        retval = rtp_ops_cs_component(ops, retval, &v, depth);
        if (retval == CORESIGHT_COMPONENT_FOUND)
@@ -1762,20 +1838,23 @@ static int rtp_cs_component(const struct rtp_ops *ops,
        const unsigned int class = ARM_CS_CIDR_CLASS(v.cid);
 
        if (class == ARM_CS_CLASS_0X1_ROM_TABLE)
-               return rtp_rom_loop(ops, ap, base_address, depth, 32, 960);
+               return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 960);
 
        if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
                if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
                        return ERROR_OK;
 
+               if (is_mem_ap && (v.devarch & DEVARCH_ID_MASK) == DEVARCH_MEM_AP)
+                       *is_mem_ap = true;
+
                /* quit if not ROM table */
                if ((v.devarch & DEVARCH_ID_MASK) != DEVARCH_ROM_C_0X9)
                        return ERROR_OK;
 
                if ((v.devid & ARM_CS_C9_DEVID_FORMAT_MASK) == ARM_CS_C9_DEVID_FORMAT_64BIT)
-                       return rtp_rom_loop(ops, ap, base_address, depth, 64, 256);
+                       return rtp_rom_loop(mode, ops, ap, base_address, depth, 64, 256);
                else
-                       return rtp_rom_loop(ops, ap, base_address, depth, 32, 512);
+                       return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 512);
        }
 
        /* Class other than 0x1 and 0x9 */
@@ -1784,10 +1863,26 @@ static int rtp_cs_component(const struct rtp_ops *ops,
 
 static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth)
 {
-       int retval;
        uint32_t apid;
        target_addr_t dbgbase, invalid_entry;
 
+       int retval = rtp_ops_ap_header(ops, ap, depth);
+       if (retval != ERROR_OK || depth > ROM_TABLE_MAX_DEPTH)
+               return ERROR_OK; /* Don't abort recursion */
+
+       if (is_adiv6(ap->dap)) {
+               bool is_mem_ap;
+               retval = rtp_cs_component(CS_ACCESS_AP, ops, ap, 0, &is_mem_ap, depth);
+               if (retval == CORESIGHT_COMPONENT_FOUND)
+                       return CORESIGHT_COMPONENT_FOUND;
+               if (retval != ERROR_OK)
+                       return ERROR_OK; /* Don't abort recursion */
+
+               if (!is_mem_ap)
+                       return ERROR_OK;
+               /* Continue for an ADIv6 MEM-AP */
+       }
+
        /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec  */
        retval = dap_get_debugbase(ap, &dbgbase, &apid);
        if (retval != ERROR_OK)
@@ -1811,7 +1906,8 @@ static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth)
                        invalid_entry = 0xFFFFFFFFul;
 
                if (dbgbase != invalid_entry && (dbgbase & 0x3) != 0x2) {
-                       retval = rtp_cs_component(ops, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, depth);
+                       retval = rtp_cs_component(CS_ACCESS_MEM_AP, ops, ap,
+                                       dbgbase & 0xFFFFFFFFFFFFF000ull, NULL, depth);
                        if (retval == CORESIGHT_COMPONENT_FOUND)
                                return CORESIGHT_COMPONENT_FOUND;
                }
@@ -1822,6 +1918,19 @@ static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth)
 
 /* Actions for command "dap info" */
 
+static int dap_info_ap_header(struct adiv5_ap *ap, int depth, void *priv)
+{
+       struct command_invocation *cmd = priv;
+
+       if (depth > ROM_TABLE_MAX_DEPTH) {
+               command_print(cmd, "\tTables too deep");
+               return ERROR_FAIL;
+       }
+
+       command_print(cmd, "%sAP # 0x%" PRIx64, (depth) ? "\t\t" : "", ap->ap_num);
+       return ERROR_OK;
+}
+
 static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
                target_addr_t dbgbase, uint32_t apid, int depth, void *priv)
 {
@@ -1842,8 +1951,6 @@ static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
        if (depth)
                snprintf(tabs, sizeof(tabs), "\t[L%02d] ", depth);
 
-       command_print(cmd, "%sAP # 0x%" PRIx64, tabs, ap->ap_num);
-
        command_print(cmd, "\t\tAP ID register 0x%8.8" PRIx32, apid);
        if (apid == 0) {
                command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64, ap->ap_num);
@@ -1887,7 +1994,8 @@ static int dap_info_cs_component(int retval, struct cs_component_vals *v, int de
                return ERROR_FAIL;
        }
 
-       command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base);
+       if (v->mode == CS_ACCESS_MEM_AP)
+               command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base);
 
        if (retval != ERROR_OK) {
                command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off");
@@ -1998,6 +2106,7 @@ static int dap_info_rom_table_entry(int retval, int depth,
 int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap)
 {
        struct rtp_ops dap_info_ops = {
+               .ap_header       = dap_info_ap_header,
                .mem_ap_header   = dap_info_mem_ap_header,
                .cs_component    = dap_info_cs_component,
                .rom_table_entry = dap_info_rom_table_entry,
@@ -2054,6 +2163,7 @@ int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type,
                .idx  = core_id,
        };
        struct rtp_ops dap_lookup_cs_component_ops = {
+               .ap_header       = NULL,
                .mem_ap_header   = NULL,
                .cs_component    = dap_lookup_cs_component_cs_component,
                .rom_table_entry = NULL,