Hi! What about implementing more generic access to ADIv5 and APB-AP? I see it like this but what gurus have in mind?
From 5e3072d911f89184d159232c0f410c0252161a25 Mon Sep 17 00:00:00 2001 From: Yauheni Kaliuta <y.kali...@gmail.com> Date: Tue, 13 Oct 2009 12:47:05 +0300 Subject: [PATCH] More abstract interface to access ADIv5 debug components
Analyse romtables and access using addresses from rom tables --- src/target/arm_adi_v5.c | 426 ++++++++++++++++++++++++++++++++++++++++++++++- src/target/arm_adi_v5.h | 62 +++++++- src/target/cortex_a8.c | 2 +- src/target/cortex_m3.c | 2 +- 4 files changed, 478 insertions(+), 14 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 90423f4..0384422 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -244,7 +244,7 @@ int swjdp_transaction_endcheck(swjdp_common_t *swjdp) /* Check power to debug regions */ if ((ctrlstat & 0xf0000000) != 0xf0000000) { - ahbap_debugport_init(swjdp); + adiv5_debugport_init(swjdp); } else { @@ -950,18 +950,343 @@ int mem_ap_read_buf_u8(swjdp_common_t *swjdp, uint8_t *buffer, int count, uint32 return retval; } -int ahbap_debugport_init(swjdp_common_t *swjdp) +static struct adiv5_component *new_adiv5_component(void) { - uint32_t idreg, romaddr, dummy; + struct adiv5_component *comp; + + comp = malloc(sizeof(*comp)); + if (comp == NULL) + return NULL; + + memset(comp, 0, sizeof(*comp)); + + return comp; +} + +static void free_adiv5_component(struct adiv5_component *comp) +{ + free(comp); +} + +static void list_add_tail_comp(struct adiv5_component **comps, + struct adiv5_component *comp) +{ + struct adiv5_component *tmp; + + if (*comps == NULL) + { + *comps = comp; + return; + } + + for (tmp = *comps; tmp->next; tmp = tmp->next) + ; + + tmp->next = comp; +} + +static void free_list_comp(struct adiv5_component **comps) +{ + struct adiv5_component *tmp, *tmp1; + + for (tmp = *comps; tmp;) + { + tmp1 = tmp; + tmp = tmp->next; + + free_adiv5_component(tmp1); + } + *comps = NULL; +} + +static void show_component(struct adiv5_component *comp) +{ + LOG_DEBUG("Component %s, base 0x%08x, start 0x%08x, class %x, part %x", + comp->name, comp->base, comp->start, comp->class, comp->part_num); + +} + +static void show_ap_components(struct adiv5_ap *ap) +{ + struct adiv5_component *comp; + + comp = ap->components; + + for(; comp; comp = comp->next) + show_component(comp); +} + +static void show_ap(struct adiv5_ap *ap) +{ + + LOG_DEBUG("AP number %d, %s ID Register 0x%" PRIx32 + ", Debug ROM Address 0x%" PRIx32 "", + ap->num, ap->name, ap->id, ap->debugbase); + show_ap_components(ap); +} + +static int romtable_read_entry(struct adiv5_ap *ap, uint32_t base, int bit32, + int *offset, uint32_t *entry) +{ + uint32_t tmp; + int r; + int i; + + r = adiv5_ap_read_atomic_u32(ap, (base & 0xFFFFF000) | *offset, &tmp); + if (r < 0) + return ERROR_FAIL; + + *offset += 4; + + if (bit32) { + *entry = tmp; + return ERROR_OK; + } + + *entry = tmp & 0x000000FF; + for (i = 1; i < 4; i++) + { + r = adiv5_ap_read_atomic_u32(ap, (base & 0xFFFFF000) | *offset, &tmp); + if (r < 0) + return ERROR_FAIL; + *entry |= (tmp & 0x000000FF) << (8 * i); + offset += 4; + } + return ERROR_OK; +} + +static int scan_memap_component(struct adiv5_ap *ap, + struct adiv5_component **comps, + uint32_t base); + +static int scan_memap_romtable(struct adiv5_ap *ap, + struct adiv5_component *comp, + struct adiv5_component **out_comps, + uint32_t base) +{ + uint32_t tmp, entry, compbase; + int bit32; + + int r; + int offset = 0; + + r = adiv5_ap_read_atomic_u32(ap, (base & 0xFFFFF000), &tmp); + if (r < 0) + return ERROR_FAIL; + + if (tmp == 0) + { + LOG_DEBUG("Blank first romtable entry?"); + return ERROR_OK; + } + + /* IHI 0031A 14.2 ROM Entries */ + bit32 = tmp & (1 << 1); + + r = romtable_read_entry(ap, base, bit32, &offset, &entry); + if (r < 0) + return ERROR_FAIL; + + comp->name = "ROMTable entry"; + comp->start = base; + + for (; entry; r = romtable_read_entry(ap, base, bit32, &offset, &entry)) + { + if (r < 0) + return ERROR_FAIL; + + if (! (entry & (1 << 0))) /* check presense */ + continue; + + compbase = (base & 0xFFFFF000) + (entry & 0xFFFFF000); + r = scan_memap_component(ap, out_comps, compbase); + if (r < 0) + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int scan_memap_debugcomp(struct adiv5_ap *ap, + struct adiv5_component *comp, + uint32_t base) +{ + comp->start = base - 0x1000 * (comp->pid[4] >> 4); + comp->name = "Coresight component"; + + return ERROR_OK; +} + +static int scan_memap_component(struct adiv5_ap *ap, + struct adiv5_component **comps, + uint32_t base) +{ + struct adiv5_component *comp, *tablecomps = NULL; + int i, r; + + uint32_t tmp; + + comp = new_adiv5_component(); + if (comp == NULL) + { + LOG_ERROR("No memory"); + return ERROR_FAIL; + } + + comp->base = base; + comp->ap = ap; + + for (i = 0; i < 4; i++) + { + r = adiv5_comp_base_read_atomic_u32(comp, 0xFF0 + (i * 4), &tmp); + if (r < 0) + goto err1; + + comp->cid[i] = tmp & 0x000000FF; + } + for (i = 0; i < 4; i++) + { + r = adiv5_comp_base_read_atomic_u32(comp, 0xFE0 + (i * 4), &tmp); + if (r < 0) + goto err1; + + comp->pid[i] = tmp & 0x000000FF; + } + + for (i = 0; i < 4; i++) + { + r = adiv5_comp_base_read_atomic_u32(comp, 0xFD0 + (i * 4), &tmp); + if (r < 0) + goto err1; + + comp->pid[i + 4] = tmp & 0x000000FF; + } + + /* IHI 0031A 13.2 The Component ID Registers */ + comp->class = (comp->cid[1] & 0xF0) >> 4; + comp->part_num = ((uint32_t)comp->pid[1] & 0x0F) << 8 | comp->pid[0]; + + if (comp->class == COMP_CLASS_ROMTABLE) + r = scan_memap_romtable(ap, comp, &tablecomps, base); + else + r = scan_memap_debugcomp(ap, comp, base); + + if (r < 0) + goto err1; + + list_add_tail_comp(comps, comp); + if (tablecomps) + list_add_tail_comp(comps, tablecomps); + + return ERROR_OK; +err1: + free_adiv5_component(comp); + return ERROR_FAIL; +} + +static void init_ap_struct(struct adiv5_ap *ap) +{ + ap->type = AP_TYPE_NONE; + ap->id = 0; + ap->debugbase = 0xFFFFFFFF; + ap->name = "NONE"; + ap->components = NULL; +} + +static int scan_ap(swjdp_common_t *swjdp, struct adiv5_ap *ap, int n) +{ + uint32_t idreg, romaddr; + int r; + + init_ap_struct(ap); + ap->num = n; + ap->swjdp = swjdp; + + swjdp->apsel = n; + dap_ap_select(swjdp, swjdp->apsel); + + dap_ap_read_reg_u32(swjdp, AP_REG_IDR, &idreg); + dap_ap_read_reg_u32(swjdp, AP_REG_DBGROMA, &romaddr); + + r = swjdp_transaction_endcheck(swjdp); + if (r < 0) { + LOG_DEBUG("swjdp_transaction_endcheck failed"); + return ERROR_FAIL; + } + + if (idreg == 0) /* non-existing AP */ + return ERROR_OK; + + ap->id = idreg; + ap->debugbase = romaddr; + + /* IHI 0031A 10.2.2, IDR */ + if (idreg & (1 << 16)) + ap->type = AP_TYPE_MEM; + + switch (idreg & 0x0F) + { + case 0: + ap->type = AP_TYPE_JTAG; + ap->name = "JTAG-AP"; + break; + case 1: + ap->name = "AHB-AP"; + break; + case 2: + ap->name = "APB-AP"; + break; + default: + ap->type = AP_TYPE_UNKNOWN; + ap->name = "Unknown"; + break; + } + + if ((ap->type == AP_TYPE_MEM) && (ap->debugbase != 0xFFFFFFFF)) + r = scan_memap_component(ap, &ap->components, ap->debugbase); + + if (r < 0) { + free_list_comp(&ap->components); + return ERROR_FAIL; + } + + show_ap(ap); + + return ERROR_OK; +} + +static int scan_swjdp(swjdp_common_t *swjdp) +{ + int i, r; + + int max_ap = sizeof(swjdp->ap) / sizeof(swjdp->ap[0]); + + for (i = 0; i < max_ap; i++) + { + r = scan_ap(swjdp, &swjdp->ap[i], i); + if (r < 0) + return ERROR_FAIL; + /* To speedup assume all APs are in the beginning */ + if (swjdp->ap[i].type == AP_TYPE_NONE) + break; + } + + swjdp->apsel = 0; + swjdp->ap_csw_value = -1; + swjdp->ap_tar_value = -1; + + return ERROR_OK; +} + +int adiv5_debugport_init(swjdp_common_t *swjdp) +{ + uint32_t dummy; uint32_t ctrlstat; int cnt = 0; int retval; LOG_DEBUG(" "); - swjdp->apsel = 0; - swjdp->ap_csw_value = -1; - swjdp->ap_tar_value = -1; swjdp->trans_mode = TRANS_MODE_ATOMIC; dap_dp_read_reg(swjdp, &dummy, DP_CTRL_STAT); dap_dp_write_reg(swjdp, SSTICKYERR, DP_CTRL_STAT); @@ -999,10 +1324,10 @@ int ahbap_debugport_init(swjdp_common_t *swjdp) dap_dp_write_reg(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT); dap_dp_read_reg(swjdp, &dummy, DP_CTRL_STAT); - dap_ap_read_reg_u32(swjdp, 0xFC, &idreg); - dap_ap_read_reg_u32(swjdp, 0xF8, &romaddr); - LOG_DEBUG("AHB-AP ID Register 0x%" PRIx32 ", Debug ROM Address 0x%" PRIx32 "", idreg, romaddr); + retval = scan_swjdp(swjdp); + if (retval < 0) + return ERROR_FAIL; return ERROR_OK; } @@ -1211,3 +1536,86 @@ int dap_apid_command(struct command_context_s *cmd_ctx, } +struct adiv5_component *adiv5_find_component(struct adiv5_ap *ap, int part_num) +{ + struct adiv5_component *comp; + + comp = ap->components; + + for(; comp; comp = comp->next) + if (comp->part_num == part_num) + return comp; + return NULL; +} + +int adiv5_ap_read_atomic_u32(struct adiv5_ap *ap, uint32_t reg, uint32_t *val) +{ + swjdp_common_t *swjdp = ap->swjdp; + int r; + + if (ap->type != AP_TYPE_MEM) + { + LOG_ERROR("%s is called for non-mem AP", __FUNCTION__); + return ERROR_FAIL; + } + + dap_ap_select(swjdp, ap->num); + r = mem_ap_read_atomic_u32(swjdp, reg, val); + return r; +} + +int adiv5_ap_write_atomic_u32(struct adiv5_ap *ap, uint32_t reg, uint32_t val) +{ + swjdp_common_t *swjdp = ap->swjdp; + int r; + + if (ap->type != AP_TYPE_MEM) + { + LOG_ERROR("%s is called for non-mem AP", __FUNCTION__); + return ERROR_FAIL; + } + + dap_ap_select(swjdp, ap->num); + r = mem_ap_write_atomic_u32(swjdp, reg, val); + return r; +} + +int adiv5_comp_read_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t *val) +{ + uint32_t base = comp->start; + int r; + + r = adiv5_ap_read_atomic_u32(comp->ap, base + reg, val); + return r; +} + +int adiv5_comp_write_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t val) +{ + uint32_t base = comp->start; + int r; + + r = adiv5_ap_write_atomic_u32(comp->ap, base + reg, val); + return r; +} + +int adiv5_comp_base_read_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t *val) +{ + uint32_t base = comp->base & 0xFFFFF000; + int r; + + r = adiv5_ap_read_atomic_u32(comp->ap, base + (reg & 0x00000FFF), val); + return r; +} + +int adiv5_comp_base_write_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t val) +{ + uint32_t base = comp->base & 0xFFFFF000; + int r; + + r = adiv5_ap_write_atomic_u32(comp->ap, base + (reg & 0x00000FFF), val); + return r; +} diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 3ff883a..4bafbcb 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -57,6 +57,11 @@ #define AP_REG_DBGROMA 0xF8 #define AP_REG_IDR 0xFC +#define AP_TYPE_UNKNOWN 0x00 +#define AP_TYPE_JTAG 0x01 +#define AP_TYPE_MEM 0x02 +#define AP_TYPE_NONE 0xFF + #define CSW_8BIT 0 #define CSW_16BIT 1 #define CSW_32BIT 2 @@ -76,6 +81,44 @@ /* Freerunning transactions with delays and overrun checking */ #define TRANS_MODE_COMPOSITE 2 + +#define COMP_CLASS_ROMTABLE 0x01 +#define COMP_CLASS_DEBUG 0x09 + + +struct adiv5_component; +struct swjdp_common_s; + +struct adiv5_ap +{ + struct swjdp_common_s *swjdp; + + int type; + int num; + uint32_t id; + uint32_t debugbase; + const char *name; + + struct adiv5_component *components; +}; + +struct adiv5_component +{ + struct adiv5_component *next; + + struct adiv5_ap *ap; + + int class; + int part_num; + const char *name; + + uint32_t base; + uint32_t start; + + uint8_t cid[4]; + uint8_t pid[8]; +}; + typedef struct swjdp_reg_s { int addr; @@ -101,7 +144,8 @@ typedef struct swjdp_common_s uint32_t memaccess_tck; /* Size of TAR autoincrement block, ARM ADI Specification requires at least 10 bits */ uint32_t tar_autoincr_block; - + /* connected APs, 8 bits, ARM IHI 0031A */ + struct adiv5_ap ap[256]; } swjdp_common_t; /* Accessor function for currently selected DAP-AP number */ @@ -143,8 +187,20 @@ extern int mem_ap_write_buf_u16(swjdp_common_t *swjdp, uint8_t *buffer, int coun extern int mem_ap_write_buf_u32(swjdp_common_t *swjdp, uint8_t *buffer, int count, uint32_t address); /* Initialisation of the debug system, power domains and registers */ -extern int ahbap_debugport_init(swjdp_common_t *swjdp); - +extern int adiv5_debugport_init(swjdp_common_t *swjdp); + +/* Access to ADIv5 parts */ +extern struct adiv5_component *adiv5_find_component(struct adiv5_ap *ap, int part_num); +extern int adiv5_ap_read_atomic_u32(struct adiv5_ap *ap, uint32_t reg, uint32_t *val); +extern int adiv5_ap_write_atomic_u32(struct adiv5_ap *ap, uint32_t reg, uint32_t val); +extern int adiv5_comp_read_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t *val); +extern int adiv5_comp_write_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t val); +extern int adiv5_comp_base_read_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t *val); +extern int adiv5_comp_base_write_atomic_u32(struct adiv5_component *comp, + uint32_t reg, uint32_t val); /* Commands for user dap access */ int dap_info_command(struct command_context_s *cmd_ctx, diff --git a/src/target/cortex_a8.c b/src/target/cortex_a8.c index 846d90c..a1e791b 100644 --- a/src/target/cortex_a8.c +++ b/src/target/cortex_a8.c @@ -1451,7 +1451,7 @@ int cortex_a8_examine(struct target_s *target) /* We do one extra read to ensure DAP is configured, * we call ahbap_debugport_init(swjdp) instead */ - ahbap_debugport_init(swjdp); + adiv5_debugport_init(swjdp); mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_CPUID, &cpuid); if ((retval = mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_CPUID, &cpuid)) != ERROR_OK) diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c index 5f5287a..33dccfd 100644 --- a/src/target/cortex_m3.c +++ b/src/target/cortex_m3.c @@ -1507,7 +1507,7 @@ int cortex_m3_examine(struct target_s *target) cortex_m3_common_t *cortex_m3 = armv7m->arch_info; swjdp_common_t *swjdp = &armv7m->swjdp_info; - if ((retval = ahbap_debugport_init(swjdp)) != ERROR_OK) + if ((retval = adiv5_debugport_init(swjdp)) != ERROR_OK) return retval; if (!target_was_examined(target)) -- 1.6.4.3
_______________________________________________ Openocd-development mailing list Openocd-development@lists.berlios.de https://lists.berlios.de/mailman/listinfo/openocd-development