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"}, };