|
36 | 36 | #include "target_internal.h" |
37 | 37 | #include "jep106.h" |
38 | 38 | #include "adi.h" |
| 39 | +#include "adiv5.h" |
39 | 40 | #include "cortex.h" |
40 | 41 | #include "cortex_internal.h" |
41 | 42 |
|
| 43 | +/* Used to probe for a protected SAMX5X device */ |
| 44 | +#define SAMX5X_DSU_CTRLSTAT 0x41002100U |
| 45 | +#define SAMX5X_STATUSB_PROT (1U << 16U) |
| 46 | + |
| 47 | +#define ID_SAMx5x 0xcd0U |
| 48 | + |
42 | 49 | #if ENABLE_DEBUG == 1 |
43 | 50 | #define ARM_COMPONENT_STR(...) __VA_ARGS__ |
44 | 51 | #else |
@@ -460,3 +467,193 @@ void adi_ap_resume_cores(adiv5_access_port_s *const ap) |
460 | 467 | } |
461 | 468 | } |
462 | 469 | } |
| 470 | + |
| 471 | +static uint32_t adi_ap_read_id(adiv5_access_port_s *ap, uint32_t addr) |
| 472 | +{ |
| 473 | + uint32_t res = 0; |
| 474 | + uint8_t data[16]; |
| 475 | + adiv5_mem_read(ap, data, addr, sizeof(data)); |
| 476 | + for (size_t i = 0; i < 4U; ++i) |
| 477 | + res |= (uint32_t)data[4U * i] << (i * 8U); |
| 478 | + return res; |
| 479 | +} |
| 480 | + |
| 481 | +static uint64_t adi_ap_read_pidr(adiv5_access_port_s *ap, uint32_t addr) |
| 482 | +{ |
| 483 | + const uint32_t pidr_upper = adi_ap_read_id(ap, addr + PIDR4_OFFSET); |
| 484 | + const uint32_t pidr_lower = adi_ap_read_id(ap, addr + PIDR0_OFFSET); |
| 485 | + return ((uint64_t)pidr_upper << 32U) | (uint64_t)pidr_lower; |
| 486 | +} |
| 487 | + |
| 488 | +uint32_t adi_mem_read32(adiv5_access_port_s *const ap, const target_addr32_t addr) |
| 489 | +{ |
| 490 | + uint32_t ret; |
| 491 | + adiv5_mem_read(ap, &ret, addr, sizeof(ret)); |
| 492 | + return ret; |
| 493 | +} |
| 494 | + |
| 495 | +static void adi_parse_adi_rom_table(adiv5_access_port_s *const ap, const target_addr32_t base_address, |
| 496 | + const size_t recursion_depth, const char *const indent, const uint64_t pidr) |
| 497 | +{ |
| 498 | +#if defined(DEBUG_WARN_IS_NOOP) && defined(DEBUG_ERROR_IS_NOOP) |
| 499 | + (void)indent; |
| 500 | +#endif |
| 501 | + |
| 502 | + /* Extract the designer code and part number from the part ID register */ |
| 503 | + const uint16_t designer_code = adi_designer_from_pidr(pidr); |
| 504 | + const uint16_t part_number = pidr & PIDR_PN_MASK; |
| 505 | + |
| 506 | + if (recursion_depth == 0U) { |
| 507 | + ap->designer_code = designer_code; |
| 508 | + ap->partno = part_number; |
| 509 | + |
| 510 | + if (ap->designer_code == JEP106_MANUFACTURER_ATMEL && ap->partno == ID_SAMx5x) { |
| 511 | + uint32_t ctrlstat = adi_mem_read32(ap, SAMX5X_DSU_CTRLSTAT); |
| 512 | + if (ctrlstat & SAMX5X_STATUSB_PROT) { |
| 513 | + /* A protected SAMx5x device is found. |
| 514 | + * Handle it here, as access only to limited memory region |
| 515 | + * is allowed |
| 516 | + */ |
| 517 | + cortexm_probe(ap); |
| 518 | + return; |
| 519 | + } |
| 520 | + } |
| 521 | + } |
| 522 | + |
| 523 | + /* Check SYSMEM bit */ |
| 524 | + const bool memtype = adi_mem_read32(ap, base_address + ADIV5_ROM_MEMTYPE) & ADIV5_ROM_MEMTYPE_SYSMEM; |
| 525 | + if (adiv5_dp_error(ap->dp)) |
| 526 | + DEBUG_ERROR("Fault reading ROM table entry\n"); |
| 527 | + else if (memtype) |
| 528 | + ap->flags |= ADIV5_AP_FLAGS_HAS_MEM; |
| 529 | + DEBUG_INFO("ROM Table: BASE=0x%" PRIx32 " SYSMEM=%u, Manufacturer %03x Partno %03x (PIDR = 0x%02" PRIx32 |
| 530 | + "%08" PRIx32 ")\n", |
| 531 | + base_address, memtype, designer_code, part_number, (uint32_t)(pidr >> 32U), (uint32_t)pidr); |
| 532 | + |
| 533 | + for (uint32_t i = 0; i < 960U; i++) { |
| 534 | + adiv5_dp_error(ap->dp); |
| 535 | + |
| 536 | + uint32_t entry = adi_mem_read32(ap, base_address + i * 4U); |
| 537 | + if (adiv5_dp_error(ap->dp)) { |
| 538 | + DEBUG_ERROR("%sFault reading ROM table entry %" PRIu32 "\n", indent, i); |
| 539 | + break; |
| 540 | + } |
| 541 | + |
| 542 | + if (entry == 0) |
| 543 | + break; |
| 544 | + |
| 545 | + if (!(entry & ADIV5_ROM_ROMENTRY_PRESENT)) { |
| 546 | + DEBUG_INFO("%s%" PRIu32 " Entry 0x%08" PRIx32 " -> Not present\n", indent, i, entry); |
| 547 | + continue; |
| 548 | + } |
| 549 | + |
| 550 | + /* Probe recursively */ |
| 551 | + adi_ap_component_probe(ap, base_address + (entry & ADIV5_ROM_ROMENTRY_OFFSET), recursion_depth + 1U, i); |
| 552 | + } |
| 553 | + DEBUG_INFO("%sROM Table: END\n", indent); |
| 554 | +} |
| 555 | + |
| 556 | +/* Return true if we find a debuggable device. */ |
| 557 | +void adi_ap_component_probe( |
| 558 | + adiv5_access_port_s *ap, target_addr64_t base_address, const size_t recursion, const uint32_t entry_number) |
| 559 | +{ |
| 560 | +#ifdef DEBUG_WARN_IS_NOOP |
| 561 | + (void)entry_number; |
| 562 | +#endif |
| 563 | + |
| 564 | + const uint32_t cidr = adi_ap_read_id(ap, base_address + CIDR0_OFFSET); |
| 565 | + if (ap->dp->fault) { |
| 566 | + DEBUG_ERROR("Error reading CIDR on AP%u: %u\n", ap->apsel, ap->dp->fault); |
| 567 | + return; |
| 568 | + } |
| 569 | + |
| 570 | +#if ENABLE_DEBUG == 1 |
| 571 | + char *const indent = alloca(recursion + 1U); |
| 572 | + |
| 573 | + for (size_t i = 0; i < recursion; i++) |
| 574 | + indent[i] = ' '; |
| 575 | + indent[recursion] = 0; |
| 576 | +#else |
| 577 | + const char *const indent = " "; |
| 578 | +#endif |
| 579 | + |
| 580 | + if (adiv5_dp_error(ap->dp)) { |
| 581 | + DEBUG_ERROR("%sFault reading ID registers\n", indent); |
| 582 | + return; |
| 583 | + } |
| 584 | + |
| 585 | + /* CIDR preamble sanity check */ |
| 586 | + if ((cidr & ~CID_CLASS_MASK) != CID_PREAMBLE) { |
| 587 | + DEBUG_WARN("%s%" PRIu32 " 0x%0" PRIx32 "%08" PRIx32 ": 0x%08" PRIx32 " <- does not match preamble (0x%08" PRIx32 |
| 588 | + ")\n", |
| 589 | + indent, entry_number, (uint32_t)(base_address >> 32U), (uint32_t)base_address, cidr, CID_PREAMBLE); |
| 590 | + return; |
| 591 | + } |
| 592 | + |
| 593 | + /* Extract Component ID class nibble */ |
| 594 | + const uint8_t cid_class = (cidr & CID_CLASS_MASK) >> CID_CLASS_SHIFT; |
| 595 | + |
| 596 | + /* Read out the peripheral ID register */ |
| 597 | + const uint64_t pidr = adi_ap_read_pidr(ap, base_address); |
| 598 | + |
| 599 | + /* ROM table */ |
| 600 | + if (cid_class == cidc_romtab) { |
| 601 | + /* Validate that the SIZE field is 0 per the spec */ |
| 602 | + if (pidr & PIDR_SIZE_MASK) { |
| 603 | + DEBUG_ERROR("Fault reading ROM table\n"); |
| 604 | + return; |
| 605 | + } |
| 606 | + adi_parse_adi_rom_table(ap, base_address, recursion, indent, pidr); |
| 607 | + } else { |
| 608 | + /* Extract the designer code from the part ID register */ |
| 609 | + const uint16_t designer_code = adi_designer_from_pidr(pidr); |
| 610 | + |
| 611 | + if (designer_code != JEP106_MANUFACTURER_ARM && designer_code != JEP106_MANUFACTURER_ARM_CHINA) { |
| 612 | +#ifndef DEBUG_TARGET_IS_NOOP |
| 613 | + const uint16_t part_number = pidr & PIDR_PN_MASK; |
| 614 | +#endif |
| 615 | + /* non-ARM components are not supported currently */ |
| 616 | + DEBUG_WARN("%s%" PRIu32 " 0x%0" PRIx32 "%08" PRIx32 ": 0x%02" PRIx32 "%08" PRIx32 " Non-ARM component " |
| 617 | + "ignored\n", |
| 618 | + indent + 1, entry_number, (uint32_t)(base_address >> 32U), (uint32_t)base_address, |
| 619 | + (uint32_t)(pidr >> 32U), (uint32_t)pidr); |
| 620 | + DEBUG_TARGET("%s -> designer: %x, part no: %x\n", indent, designer_code, part_number); |
| 621 | + return; |
| 622 | + } |
| 623 | + |
| 624 | + /* Check if this is a CoreSight component */ |
| 625 | + uint8_t dev_type = 0; |
| 626 | + uint16_t arch_id = 0; |
| 627 | + if (cid_class == cidc_dc) { |
| 628 | + /* Read out the component's identification information */ |
| 629 | + const uint32_t devarch = adi_mem_read32(ap, base_address + DEVARCH_OFFSET); |
| 630 | + dev_type = adi_mem_read32(ap, base_address + DEVTYPE_OFFSET) & DEVTYPE_MASK; |
| 631 | + |
| 632 | + if (devarch & DEVARCH_PRESENT) |
| 633 | + arch_id = devarch & DEVARCH_ARCHID_MASK; |
| 634 | + } |
| 635 | + |
| 636 | + /* Look the component up and dispatch to a probe routine accordingly */ |
| 637 | + const arm_coresight_component_s *const component = |
| 638 | + adi_lookup_component(base_address, entry_number, indent, cid_class, pidr, dev_type, arch_id); |
| 639 | + |
| 640 | + if (component) { |
| 641 | + switch (component->arch) { |
| 642 | + case aa_cortexm: |
| 643 | + DEBUG_INFO("%s-> cortexm_probe\n", indent + 1); |
| 644 | + cortexm_probe(ap); |
| 645 | + break; |
| 646 | + case aa_cortexa: |
| 647 | + DEBUG_INFO("%s-> cortexa_probe\n", indent + 1); |
| 648 | + cortexa_probe(ap, base_address); |
| 649 | + break; |
| 650 | + case aa_cortexr: |
| 651 | + DEBUG_INFO("%s-> cortexr_probe\n", indent + 1); |
| 652 | + cortexr_probe(ap, base_address); |
| 653 | + break; |
| 654 | + default: |
| 655 | + break; |
| 656 | + } |
| 657 | + } |
| 658 | + } |
| 659 | +} |
0 commit comments