+static const struct dap_part_nums *pidr_to_part_num(unsigned int designer_id, unsigned int part_num)
+{
+ static const struct dap_part_nums unknown = {
+ .type = "Unrecognized",
+ .full = "",
+ };
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(dap_part_nums); i++)
+ if (dap_part_nums[i].designer_id == designer_id && dap_part_nums[i].part_num == part_num)
+ return &dap_part_nums[i];
+
+ return &unknown;
+}
+
+static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype)
+{
+ const char *major = "Reserved", *subtype = "Reserved";
+ const unsigned int minor = (devtype & ARM_CS_C9_DEVTYPE_SUB_MASK) >> ARM_CS_C9_DEVTYPE_SUB_SHIFT;
+ const unsigned int devtype_major = (devtype & ARM_CS_C9_DEVTYPE_MAJOR_MASK) >> ARM_CS_C9_DEVTYPE_MAJOR_SHIFT;
+ switch (devtype_major) {
+ case 0:
+ major = "Miscellaneous";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 4:
+ subtype = "Validation component";
+ break;
+ }
+ break;
+ case 1:
+ major = "Trace Sink";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 1:
+ subtype = "Port";
+ break;
+ case 2:
+ subtype = "Buffer";
+ break;
+ case 3:
+ subtype = "Router";
+ break;
+ }
+ break;
+ case 2:
+ major = "Trace Link";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 1:
+ subtype = "Funnel, router";
+ break;
+ case 2:
+ subtype = "Filter";
+ break;
+ case 3:
+ subtype = "FIFO, buffer";
+ break;
+ }
+ break;
+ case 3:
+ major = "Trace Source";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 1:
+ subtype = "Processor";
+ break;
+ case 2:
+ subtype = "DSP";
+ break;
+ case 3:
+ subtype = "Engine/Coprocessor";
+ break;
+ case 4:
+ subtype = "Bus";
+ break;
+ case 6:
+ subtype = "Software";
+ break;
+ }
+ break;
+ case 4:
+ major = "Debug Control";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 1:
+ subtype = "Trigger Matrix";
+ break;
+ case 2:
+ subtype = "Debug Auth";
+ break;
+ case 3:
+ subtype = "Power Requestor";
+ break;
+ }
+ break;
+ case 5:
+ major = "Debug Logic";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 1:
+ subtype = "Processor";
+ break;
+ case 2:
+ subtype = "DSP";
+ break;
+ case 3:
+ subtype = "Engine/Coprocessor";
+ break;
+ case 4:
+ subtype = "Bus";
+ break;
+ case 5:
+ subtype = "Memory";
+ break;
+ }
+ break;
+ case 6:
+ major = "Performance Monitor";
+ switch (minor) {
+ case 0:
+ subtype = "other";
+ break;
+ case 1:
+ subtype = "Processor";
+ break;
+ case 2:
+ subtype = "DSP";
+ break;
+ case 3:
+ subtype = "Engine/Coprocessor";
+ break;
+ case 4:
+ subtype = "Bus";
+ break;
+ case 5:
+ subtype = "Memory";
+ break;
+ }
+ break;
+ }
+ command_print(cmd, "\t\tType is 0x%02x, %s, %s",
+ devtype & ARM_CS_C9_DEVTYPE_MASK,
+ major, subtype);
+ return ERROR_OK;
+}
+
+/**
+ * Actions/operations to be executed while parsing ROM tables.
+ */
+struct rtp_ops {
+ /**
+ * Executed at the start of a new MEM-AP, typically to print the MEM-AP header.
+ * @param retval Error encountered while reading AP.
+ * @param ap Pointer to AP.
+ * @param dbgbase Value of MEM-AP Debug Base Address register.
+ * @param apid Value of MEM-AP IDR Identification Register.
+ * @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 (*mem_ap_header)(int retval, struct adiv5_ap *ap, uint64_t dbgbase,
+ uint32_t apid, int depth, void *priv);
+ /**
+ * Executed when a CoreSight component is parsed, typically to print
+ * information on the component.
+ * @param retval Error encountered while reading component's registers.
+ * @param v Pointer to a container of the component's registers.
+ * @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 (*cs_component)(int retval, struct cs_component_vals *v, int depth, void *priv);
+ /**
+ * Executed for each entry of a ROM table, typically to print the entry
+ * and information about validity or end-of-table mark.
+ * @param retval Error encountered while reading the ROM table entry.
+ * @param depth The current depth level of ROM table.
+ * @param offset The offset of the entry in the ROM table.
+ * @param romentry The value of the ROM table entry.
+ * @param priv Pointer to private data.
+ * @return ERROR_OK on success, else a fault code.
+ */
+ int (*rom_table_entry)(int retval, int depth, unsigned int offset, uint64_t romentry,
+ void *priv);
+ /**
+ * Private data
+ */
+ void *priv;
+};
+
+/**
+ * Wrapper around struct rtp_ops::mem_ap_header.
+ * Input parameter @a retval is propagated.
+ */
+static int rtp_ops_mem_ap_header(const struct rtp_ops *ops,
+ int retval, struct adiv5_ap *ap, uint64_t dbgbase, uint32_t apid, int depth)
+{
+ if (!ops->mem_ap_header)
+ return retval;
+
+ int retval1 = ops->mem_ap_header(retval, ap, dbgbase, apid, depth, ops->priv);
+ if (retval != ERROR_OK)
+ return retval;
+ return retval1;
+}
+
+/**
+ * Wrapper around struct rtp_ops::cs_component.
+ * Input parameter @a retval is propagated.
+ */
+static int rtp_ops_cs_component(const struct rtp_ops *ops,
+ int retval, struct cs_component_vals *v, int depth)
+{
+ if (!ops->cs_component)
+ return retval;
+
+ int retval1 = ops->cs_component(retval, v, depth, ops->priv);
+ if (retval != ERROR_OK)
+ return retval;
+ return retval1;
+}
+
+/**
+ * Wrapper around struct rtp_ops::rom_table_entry.
+ * Input parameter @a retval is propagated.
+ */
+static int rtp_ops_rom_table_entry(const struct rtp_ops *ops,
+ int retval, int depth, unsigned int offset, uint64_t romentry)
+{
+ if (!ops->rom_table_entry)
+ return retval;
+
+ int retval1 = ops->rom_table_entry(retval, depth, offset, romentry, ops->priv);
+ if (retval != ERROR_OK)
+ return retval;
+ return retval1;
+}
+
+/* Broken ROM tables can have circular references. Stop after a while */
+#define ROM_TABLE_MAX_DEPTH (16)
+
+/**
+ * Value used only during lookup of a CoreSight component in ROM table.
+ * Return CORESIGHT_COMPONENT_FOUND when component is found.
+ * Return ERROR_OK when component is not found yet.
+ * Return any other ERROR_* in case of error.
+ */
+#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_rom_loop(const struct rtp_ops *ops,
+ struct adiv5_ap *ap, target_addr_t base_address, int depth,
+ unsigned int width, unsigned int max_entries)
+{
+ assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
+
+ unsigned int offset = 0;
+ while (max_entries--) {
+ uint64_t romentry;
+ uint32_t romentry_low, romentry_high;
+ target_addr_t component_base;
+ unsigned int saved_offset = offset;
+
+ int retval = mem_ap_read_u32(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);
+ offset += 4;
+ }
+ if (retval == ERROR_OK)
+ retval = dap_run(ap->dap);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("Failed read ROM table entry");
+ return retval;
+ }
+
+ if (width == 64) {
+ romentry = (((uint64_t)romentry_high) << 32) | romentry_low;
+ component_base = base_address +
+ ((((uint64_t)romentry_high) << 32) | (romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK));
+ } else {
+ romentry = romentry_low;
+ /* "romentry" is signed */
+ component_base = base_address + (int32_t)(romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK);
+ if (!is_64bit_ap(ap))
+ component_base = (uint32_t)component_base;
+ }
+ retval = rtp_ops_rom_table_entry(ops, retval, depth, saved_offset, romentry);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (romentry == 0) {
+ /* End of ROM table */
+ break;
+ }
+
+ if (!(romentry & ARM_CS_ROMENTRY_PRESENT))
+ continue;
+
+ /* Recurse */
+ retval = rtp_cs_component(ops, ap, component_base, depth + 1);
+ if (retval == CORESIGHT_COMPONENT_FOUND)
+ return CORESIGHT_COMPONENT_FOUND;
+ if (retval != ERROR_OK) {
+ /* TODO: do we need to send an ABORT before continuing? */
+ LOG_DEBUG("Ignore error parsing CoreSight component");
+ continue;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int rtp_cs_component(const struct rtp_ops *ops,
+ struct adiv5_ap *ap, target_addr_t base_address, int depth)