From 7b2309943a8df240e10abad0f97cca23ff431f5d Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Sat, 18 Jun 2016 23:19:04 -0700 Subject: [PATCH] Use Product ID and Componend ID tables instead of defines. This patch adds tables that allow us to decode the Product ID and Component ID registers. Based on those tables we can decide what probe function to use. Also this makes it possible for us to understand what ADIv5 components the target is offering to us, even if we do not need/use them. The tables include a comment describing how the register bits need to be interpreted. --- src/adiv5.c | 266 ++++++++++++++++++++++++++++++++++++++++++------ src/jtag_scan.c | 2 + 2 files changed, 238 insertions(+), 30 deletions(-) diff --git a/src/adiv5.c b/src/adiv5.c index 6907cd3..b8bff89 100644 --- a/src/adiv5.c +++ b/src/adiv5.c @@ -32,16 +32,181 @@ #define DO_RESET_SEQ 0 #endif -/* ROM table CIDR values */ -#define CIDR_ROM_TABLE 0xb105100d -#define CIDR_GENERIC_IP 0xb105e00d -#define CIDR_DEBUG 0xb105900d +/* All this should probably be defined in a dedicated ADIV5 header, so that they + * are consistently named and accessible when needed in the codebase. + */ -#define PIDR_REV_MASK 0x0FFF00000ULL -#define PIDR_ARMv7M 0x4000BB000ULL -#define PIDR_ARMv6M 0x4000BB008ULL -#define PIDR_ARMv7MF 0x4000BB00CULL -#define PIDR_ARMv7A 0x4000BBC09ULL +/* ROM table CIDR values */ +#define CIDR0_OFFSET 0xFF0 /* DBGCID0 */ +#define CIDR1_OFFSET 0xFF4 /* DBGCID1 */ +#define CIDR2_OFFSET 0xFF8 /* DBGCID2 */ +#define CIDR3_OFFSET 0xFFC /* DBGCID3 */ + +/* Component class ID register can be broken down into the following logical + * interpretation of the 32bit value consisting of the least significant bytes + * of the 4 CID registers: + * |7 ID3 reg 0|7 ID2 reg 0|7 ID1 reg 0|7 ID0 reg 0| + * |1|0|1|1|0|0|0|1|0|0|0|0|0|1|0|1| | | | |0|0|0|0|0|0|0|0|1|1|0|1| + * |31 24|23 16|15 12|11 | 0| + * \_______________ ______________/\___ __/\___________ ___________/ + * V V V + * Preamble Component Preamble + * Class + * \_______________________________ _______________________________/ + * V + * Component ID + */ +#define CID_PREAMBLE 0xB105000D +#define CID_CLASS_MASK 0x0000F000 +#define CID_CLASS_SHIFT 12 +/* The following enum is based on the Component Class value table 13-3 of the + * ADIv5 standard. + */ +enum cid_class { + cidc_gvc = 0x0, /* Generic verification component*/ + cidc_romtab = 0x1, /* ROM Table, std. layout (ADIv5 Chapter 14) */ + /* 0x2 - 0x8 */ /* Reserved */ + cidc_dc = 0x9, /* Debug component, std. layout (CoreSight Arch. Spec.) */ + /* 0xA */ /* Reserved */ + cidc_ptb = 0xB, /* Peripheral Test Block (PTB) */ + /* 0xC */ /* Reserved */ + cidc_dess = 0xD, /* OptimoDE Data Engine SubSystem (DESS) component */ + cidc_gipc = 0xE, /* Generic IP Component */ + cidc_pcp = 0xF, /* PrimeCell peripheral */ + cidc_unknown = 0x10 +}; + +#ifdef PLATFORM_HAS_DEBUG +/* The reserved ones only have an R in them, to save a bit of space. */ +static const char const *cidc_debug_strings[] = +{ + [cidc_gvc] = "Generic verification component", /* 0x0 */ + [cidc_romtab] = "ROM Table", /* 0x1 */ + [0x2 ... 0x8] = "R", /* 0x2 - 0x8 */ + [cidc_dc] = "Debug component", /* 0x9 */ + [0xA] = "R", /* 0xA */ + [cidc_ptb] = "Peripheral Test Block", /* 0xB */ + [0xC] = "R", /* 0xC */ + [cidc_dess] = "OptimoDE Data Engine SubSystem component", /* 0xD */ + [cidc_gipc] = "Generic IP component", /* 0xE */ + [cidc_pcp] = "PrimeCell peripheral", /* 0xF */ + [cidc_unknown] = "Unknown component class" /* 0x10 */ +}; +#endif + +#define PIDR0_OFFSET 0xFE0 /* DBGPID0 */ +#define PIDR1_OFFSET 0xFE4 /* DBGPID1 */ +#define PIDR2_OFFSET 0xFE8 /* DBGPID2 */ +#define PIDR3_OFFSET 0xFEC /* DBGPID3 */ +#define PIDR4_OFFSET 0xFD0 /* DBGPID4 */ +#define PIDR5_OFFSET 0xFD4 /* DBGPID5 (Reserved) */ +#define PIDR6_OFFSET 0xFD8 /* DBGPID6 (Reserved) */ +#define PIDR7_OFFSET 0xFDC /* DBGPID7 (Reserved) */ +#define PIDR_REV_MASK 0x0FFF00000ULL /* Revision bits. */ +#define PIDR_PN_MASK 0x000000FFFULL /* Part number bits. */ +#define PIDR_ARM_BITS 0x4000BB000ULL /* These make up the ARM JEP-106 code. */ + +enum arm_arch { + aa_nosupport, + aa_cortexm, + aa_cortexa, + aa_end +}; + +#ifdef PLATFORM_HAS_DEBUG +#define PIDR_PN_BIT_STRINGS(...) __VA_ARGS__ +#else +#define PIDR_PN_BIT_STRINGS(...) +#endif + +/* The part number list was adopted from OpenOCD: + * https://sourceforge.net/p/openocd/code/ci/406f4/tree/src/target/arm_adi_v5.c#l932 + * + * The product ID register consists of several parts. For a full description + * refer to ARM Debug Interface v5 Architecture Specification. Based on the + * document the pidr is 64 bit long and has the following interpratiation: + * |7 ID7 reg 0|7 ID6 reg 0|7 ID5 reg 0|7 ID4 reg 0| + * |0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0| | | | |1|0|0|0| + * |63 56|55 48|47 40|39 36|35 32| + * \_______________________ ______________________/\___ __/\___ ___/ + * V V V + * Reserved, RAZ 4KB | + * count | + * JEP-106 + * Continuation Code + * + * |7 ID3 reg 0|7 ID2 reg 0|7 ID1 reg 0|7 ID0 reg 0| + * | | | | | | | | | | | | |1|0|1|1|1|0|1|1| | | | | | | | | | | | | + * |31 28|27 24|23 20|||18 | 12|11 | 0| + * \___ __/\__ ___/\___ __/ |\______ _____/\___________ ___________/ + * V V V | V V + * RevAnd | Revision | JEP-106 Part number + * | | ID code + * Customer 19 + * modified `- JEP-106 code is used + * + * JEP-106 is a JEDEC standard assigning manufacturer IDs to different + * manufacturers in case of ARM the full code consisting of the JEP-106 + * Continuation code followed by the code used bit and the JEP-106 code itself + * results in the code 0x4BB. These are the bits filled in the above bit table. + * + * We left out some of the Part numbers included in OpenOCD, we only include + * the ones that have ARM as the designer. + */ +static const struct { + uint16_t part_number; + enum arm_arch arch; + enum cid_class cidc; +#ifdef PLATFORM_HAS_DEBUG + const char *type; + const char *full; +#endif +} pidr_pn_bits[] = { + {0x000, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M3 SCS", "(System Control Space)")}, + {0x001, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ITM", "(Instrumentation Trace Module)")}, + {0x002, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 DWT", "(Data Watchpoint and Trace)")}, + {0x003, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 FBP", "(Flash Patch and Breakpoint)")}, + {0x008, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M0 SCS", "(System Control Space)")}, + {0x00a, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 DWT", "(Data Watchpoint and Trace)")}, + {0x00b, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 BPU", "(Breakpoint Unit)")}, + {0x00c, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M4 SCS", "(System Control Space)")}, + {0x00d, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")}, + {0x490, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 GIC", "(Generic Interrupt Controller)")}, + {0x4c7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 PPB", "(Private Peripheral Bus ROM Table)")}, + {0x906, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CTI", "(Cross Trigger)")}, + {0x907, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETB", "(Trace Buffer)")}, + {0x908, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CSTF", "(Trace Funnel)")}, + {0x910, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM9", "(Embedded Trace)")}, + {0x912, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU", "(Trace Port Interface Unit)")}, + {0x913, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ITM", "(Instrumentation Trace Macrocell)")}, + {0x914, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight SWO", "(Single Wire Output)")}, + {0x917, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight HTM", "(AHB Trace Macrocell)")}, + {0x920, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")}, + {0x921, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 ETM", "(Embedded Trace)")}, + {0x922, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 CTI", "(Cross Trigger)")}, + {0x923, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 TPIU", "(Trace Port Interface Unit)")}, + {0x924, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ETM", "(Embedded Trace)")}, + {0x925, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 ETM", "(Embedded Trace)")}, + {0x930, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 ETM", "(Embedded Trace)")}, + {0x941, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU-Lite", "(Trace Port Interface Unit)")}, + {0x950, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A9 component)")}, + {0x955, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A5 component)")}, + {0x95f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PTM", "(Program Trace Macrocell)")}, + {0x961, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TMC", "(Trace Memory Controller)")}, + {0x962, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")}, + {0x9a0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight PMU", "(Performance Monitoring Unit)")}, + {0x9a1, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 TPIU", "(Trace Port Interface Unit)")}, + {0x9a5, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A5 ETM", "(Embedded Trace)")}, + {0x9a7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 PMU", "(Performance Monitor Unit)")}, + {0x9af, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PMU", "(Performance Monitor Unit)")}, + {0xc05, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A5 Debug", "(Debug Unit)")}, + {0xc07, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A7 Debug", "(Debug Unit)")}, + {0xc08, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A8 Debug", "(Debug Unit)")}, + {0xc09, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A9 Debug", "(Debug Unit)")}, + {0xc0f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 Debug", "(Debug Unit)")}, /* support? */ + {0xc14, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 Debug", "(Debug Unit)")}, /* support? */ + {0xfff, aa_end, cidc_unknown, PIDR_PN_BIT_STRINGS("end", "end")} +}; extern bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base); @@ -86,18 +251,35 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr) addr &= ~3; uint64_t pidr = 0; uint32_t cidr = 0; + + /* Assemble logical Product ID register value. */ for (int i = 0; i < 4; i++) { - uint32_t x = adiv5_mem_read32(ap, addr + 0xfe0 + 4*i); + uint32_t x = adiv5_mem_read32(ap, addr + PIDR0_OFFSET + 4*i); pidr |= (x & 0xff) << (i * 8); } - pidr |= (uint64_t)adiv5_mem_read32(ap, addr + 0xfd0) << 32; + { + uint32_t x = adiv5_mem_read32(ap, addr + PIDR4_OFFSET); + pidr |= (uint64_t)x << 32; + } + + /* Assemble logical Component ID register value. */ for (int i = 0; i < 4; i++) { - uint32_t x = adiv5_mem_read32(ap, addr + 0xff0 + 4*i); + uint32_t x = adiv5_mem_read32(ap, addr + CIDR0_OFFSET + 4*i); cidr |= ((uint64_t)(x & 0xff)) << (i * 8); } - switch (cidr) { - case CIDR_ROM_TABLE: /* This is a ROM table, probe recursively */ + /* CIDR preamble sanity check */ + if ((cidr & ~CID_CLASS_MASK) != CID_PREAMBLE) { + DEBUG("0x%X: 0x%X <- does not match preamble (0x%X)\n", addr, cidr, CID_PREAMBLE); + return; + } + + /* Extract Component ID class nibble */ + uint32_t cid_class = (cidr & CID_CLASS_MASK) >> CID_CLASS_SHIFT; + + DEBUG("0x%X: \"%s\"\n", addr, cidc_debug_strings[cid_class]); + + if (cid_class == cidc_romtab) { /* ROM table, probe recursively */ for (int i = 0; i < 256; i++) { uint32_t entry = adiv5_mem_read32(ap, addr + i*4); if (entry == 0) @@ -108,23 +290,48 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr) adiv5_component_probe(ap, addr + (entry & ~0xfff)); } - break; - case CIDR_GENERIC_IP: - switch (pidr & ~PIDR_REV_MASK) { - case PIDR_ARMv7MF: - case PIDR_ARMv7M: - case PIDR_ARMv6M: - cortexm_probe(ap); - break; + } else { + /* Check if the component was designed by ARM, we currently do not support, + * any components by other designers. + */ + if ((pidr & ~(PIDR_REV_MASK | PIDR_PN_MASK)) != PIDR_ARM_BITS) { + DEBUG("0x%X: 0x%llX <- does not match ARM JEP-106\n", addr, pidr); + return; } - break; - case CIDR_DEBUG: - switch (pidr & ~PIDR_REV_MASK) { - case PIDR_ARMv7A: - cortexa_probe(ap, addr); - break; + + /* Extract part number from the part id register. */ + uint16_t part_number = pidr & PIDR_PN_MASK; + /* Find the part number in our part list and run the appropriate probe + * routine if applicable. + */ + for (int i = 0; pidr_pn_bits[i].arch != aa_end; i++) { + if (pidr_pn_bits[i].part_number == part_number) { + DEBUG("0x%X: %s %s\n", addr, + pidr_pn_bits[i].type, + pidr_pn_bits[i].full); + /* Perform sanity check, if we know what to expect as component ID + * class. + */ + if (cid_class != pidr_pn_bits[i].cidc) { + DEBUG("WARNING: \"%s\" !match expected \"%s\"\n", + cidc_debug_strings[cid_class], + cidc_debug_strings[pidr_pn_bits[i].cidc]); + } + switch (pidr_pn_bits[i].arch) { + case aa_cortexm: + DEBUG("-> cortexm_probe\n"); + cortexm_probe(ap); + break; + case aa_cortexa: + DEBUG("-> cortexa_probe\n"); + cortexa_probe(ap, addr); + break; + default: + DEBUG("-> skip\n"); + } + break; + } } - break; } } @@ -363,4 +570,3 @@ uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr) ret = adiv5_dp_read(ap->dp, addr); return ret; } - diff --git a/src/jtag_scan.c b/src/jtag_scan.c index 780bb8f..db39c5c 100644 --- a/src/jtag_scan.c +++ b/src/jtag_scan.c @@ -67,6 +67,8 @@ static struct jtag_dev_descr_s { {.idcode = 0x8940303F, .idmask = 0xFFFFFFFF, .descr = "ATMEL: ATMega16."}, {.idcode = 0x0792603F, .idmask = 0xFFFFFFFF, .descr = "ATMEL: AT91SAM9261."}, {.idcode = 0x20270013, .idmask = 0xFFFFFFFF, .descr = "Intel: i80386ex."}, + {.idcode = 0x07B7617F, .idmask = 0xFFFFFFFF, .descr = "Broadcom: BCM2835."}, + {.idcode = 0x4BA00477, .idmask = 0xFFFFFFFF, .descr = "Broadcom: BCM2836."}, {.idcode = 0, .idmask = 0, .descr = "Unknown"}, };