X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Farm_adi_v5.c;h=dfbc5ade2af1958ceef83b44aea306eb7afd5ab6;hb=e84592d17d11bb1b3bbae24e1aed725913787285;hp=eafc2ddc082f276fd72076f421bc6077fc771b7a;hpb=097aa2979e0eefa822d4a16f055dcf9fc31e3dde;p=openocd.git diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index eafc2ddc08..dfbc5ade2a 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -111,17 +111,68 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw) static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar) { - if (tar != ap->tar_value || - (ap->csw_value & CSW_ADDRINC_MASK)) { + if (!ap->tar_valid || tar != ap->tar_value) { /* LOG_DEBUG("DAP: Set TAR %x",tar); */ int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar); if (retval != ERROR_OK) return retval; ap->tar_value = tar; + ap->tar_valid = true; } return ERROR_OK; } +static int mem_ap_read_tar(struct adiv5_ap *ap, uint32_t *tar) +{ + int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR, tar); + if (retval != ERROR_OK) { + ap->tar_valid = false; + return retval; + } + + retval = dap_run(ap->dap); + if (retval != ERROR_OK) { + ap->tar_valid = false; + return retval; + } + + ap->tar_value = *tar; + ap->tar_valid = true; + return ERROR_OK; +} + +static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap) +{ + switch (ap->csw_value & CSW_ADDRINC_MASK) { + case CSW_ADDRINC_SINGLE: + switch (ap->csw_value & CSW_SIZE_MASK) { + case CSW_8BIT: + return 1; + case CSW_16BIT: + return 2; + case CSW_32BIT: + return 4; + } + case CSW_ADDRINC_PACKED: + return 4; + } + return 0; +} + +/* mem_ap_update_tar_cache is called after an access to MEM_AP_REG_DRW + */ +static void mem_ap_update_tar_cache(struct adiv5_ap *ap) +{ + if (!ap->tar_valid) + return; + + uint32_t inc = mem_ap_get_tar_increment(ap); + if (inc >= max_tar_block_size(ap->tar_autoincr_block, ap->tar_value)) + ap->tar_valid = false; + else + ap->tar_value += inc; +} + /** * Queue transactions setting up transfer parameters for the * currently selected MEM-AP. @@ -170,7 +221,8 @@ int mem_ap_read_u32(struct adiv5_ap *ap, uint32_t address, /* Use banked addressing (REG_BDx) to avoid some link traffic * (updating TAR) when reading several consecutive addresses. */ - retval = mem_ap_setup_transfer(ap, CSW_32BIT | CSW_ADDRINC_OFF, + retval = mem_ap_setup_transfer(ap, + CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK), address & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; @@ -221,7 +273,8 @@ int mem_ap_write_u32(struct adiv5_ap *ap, uint32_t address, /* Use banked addressing (REG_BDx) to avoid some link traffic * (updating TAR) when writing several consecutive addresses. */ - retval = mem_ap_setup_transfer(ap, CSW_32BIT | CSW_ADDRINC_OFF, + retval = mem_ap_setup_transfer(ap, + CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK), address & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; @@ -272,7 +325,7 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; uint32_t csw_size; uint32_t addr_xor; - int retval; + int retval = ERROR_OK; /* TI BE-32 Quirks mode: * Writes on big-endian TMS570 behave very strangely. Observed behavior: @@ -303,10 +356,6 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz if (ap->unaligned_access_bad && (address % size != 0)) return ERROR_TARGET_UNALIGNED_ACCESS; - retval = mem_ap_setup_tar(ap, address ^ addr_xor); - if (retval != ERROR_OK) - return retval; - while (nbytes > 0) { uint32_t this_size = size; @@ -322,34 +371,41 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz if (retval != ERROR_OK) break; + retval = mem_ap_setup_tar(ap, address ^ addr_xor); + if (retval != ERROR_OK) + return retval; + /* How many source bytes each transfer will consume, and their location in the DRW, * depends on the type of transfer and alignment. See ARM document IHI0031C. */ uint32_t outvalue = 0; + uint32_t drw_byte_idx = address; if (dap->ti_be_32_quirks) { switch (this_size) { case 4: - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx & 3) ^ addr_xor); break; case 2: - outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (address++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (address++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx & 3) ^ addr_xor); break; case 1: - outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (address++ & 3) ^ addr_xor); + outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (drw_byte_idx & 3) ^ addr_xor); break; } } else { switch (this_size) { case 4: - outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); - outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); + outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); + /* fallthrough */ case 2: - outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); + /* fallthrough */ case 1: - outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3); } } @@ -359,12 +415,9 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz if (retval != ERROR_OK) break; - /* Rewrite TAR if it wrapped or we're xoring addresses */ - if (addrinc && (addr_xor || (address % ap->tar_autoincr_block < size && nbytes > 0))) { - retval = mem_ap_setup_tar(ap, address ^ addr_xor); - if (retval != ERROR_OK) - break; - } + mem_ap_update_tar_cache(ap); + if (addrinc) + address += this_size; } /* REVISIT: Might want to have a queued version of this function that does not run. */ @@ -373,8 +426,7 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz if (retval != ERROR_OK) { uint32_t tar; - if (dap_queue_ap_read(ap, MEM_AP_REG_TAR, &tar) == ERROR_OK - && dap_run(dap) == ERROR_OK) + if (mem_ap_read_tar(ap, &tar) == ERROR_OK) LOG_ERROR("Failed to write memory at 0x%08"PRIx32, tar); else LOG_ERROR("Failed to write memory and, additionally, failed to find out where"); @@ -403,7 +455,7 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; uint32_t csw_size; uint32_t address = adr; - int retval; + int retval = ERROR_OK; /* TI BE-32 Quirks mode: * Reads on big-endian TMS570 behave strangely differently than writes. @@ -427,19 +479,14 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint /* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant * over-allocation if packed transfers are going to be used, but determining the real need at * this point would be messy. */ - uint32_t *read_buf = malloc(count * sizeof(uint32_t)); + uint32_t *read_buf = calloc(count, sizeof(uint32_t)); + /* Multiplication count * sizeof(uint32_t) may overflow, calloc() is safe */ uint32_t *read_ptr = read_buf; if (read_buf == NULL) { LOG_ERROR("Failed to allocate read buffer"); return ERROR_FAIL; } - retval = mem_ap_setup_tar(ap, address); - if (retval != ERROR_OK) { - free(read_buf); - return retval; - } - /* Queue up all reads. Each read will store the entire DRW word in the read buffer. How many * useful bytes it contains, and their location in the word, depends on the type of transfer * and alignment. */ @@ -457,19 +504,19 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint if (retval != ERROR_OK) break; + retval = mem_ap_setup_tar(ap, address); + if (retval != ERROR_OK) + break; + retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW, read_ptr++); if (retval != ERROR_OK) break; nbytes -= this_size; - address += this_size; + if (addrinc) + address += this_size; - /* Rewrite TAR if it wrapped */ - if (addrinc && address % ap->tar_autoincr_block < size && nbytes > 0) { - retval = mem_ap_setup_tar(ap, address); - if (retval != ERROR_OK) - break; - } + mem_ap_update_tar_cache(ap); } if (retval == ERROR_OK) @@ -484,8 +531,8 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint * at least give the caller what we have. */ if (retval != ERROR_OK) { uint32_t tar; - if (dap_queue_ap_read(ap, MEM_AP_REG_TAR, &tar) == ERROR_OK - && dap_run(dap) == ERROR_OK) { + if (mem_ap_read_tar(ap, &tar) == ERROR_OK) { + /* TAR is incremented after failed transfer on some devices (eg Cortex-M4) */ LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar); if (nbytes > tar - address) nbytes = tar - address; @@ -509,8 +556,10 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint case 4: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); + /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); + /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); } @@ -519,8 +568,10 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint case 4: *buffer++ = *read_ptr >> 8 * (address++ & 3); *buffer++ = *read_ptr >> 8 * (address++ & 3); + /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (address++ & 3); + /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (address++ & 3); } @@ -590,6 +641,22 @@ struct adiv5_dap *dap_init(void) return dap; } +/** + * Invalidate cached DP select and cached TAR and CSW of all APs + */ +void dap_invalidate_cache(struct adiv5_dap *dap) +{ + dap->select = DP_SELECT_INVALID; + dap->last_read = NULL; + + int i; + for (i = 0; i <= 255; i++) { + /* force csw and tar write on the next mem-ap access */ + dap->ap[i].tar_valid = false; + dap->ap[i].csw_value = 0; + } +} + /** * Initialize a DAP. This sets up the power domains, prepares the DP * for further use and activates overrun checking. @@ -609,8 +676,7 @@ int dap_dp_init(struct adiv5_dap *dap) if (!dap->ops) dap->ops = &jtag_dp_ops; - dap->select = DP_SELECT_INVALID; - dap->last_read = NULL; + dap_invalidate_cache(dap); for (size_t i = 0; i < 30; i++) { /* DP initialization */ @@ -682,6 +748,8 @@ int mem_ap_init(struct adiv5_ap *ap) int retval; struct adiv5_dap *dap = ap->dap; + ap->tar_valid = false; + ap->csw_value = 0; /* force csw and tar write */ retval = mem_ap_setup_transfer(ap, CSW_8BIT | CSW_ADDRINC_PACKED, 0); if (retval != ERROR_OK) return retval; @@ -973,12 +1041,14 @@ static const struct { { ARM_ID, 0x4a2, "Cortex-A57 ROM", "(ROM Table)", }, { ARM_ID, 0x4a3, "Cortex-A53 ROM", "(v7 Memory Map ROM Table)", }, { ARM_ID, 0x4a4, "Cortex-A72 ROM", "(ROM Table)", }, + { ARM_ID, 0x4a9, "Cortex-A9 ROM", "(ROM Table)", }, { ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", }, { ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", }, { ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", }, { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", }, { ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", }, + { ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", }, { ARM_ID, 0x470, "Cortex-M1 ROM", "(ROM Table)", }, { ARM_ID, 0x471, "Cortex-M0 ROM", "(ROM Table)", }, { ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", }, @@ -1019,7 +1089,7 @@ static const struct { { ARM_ID, 0x9a9, "Cortex-M7 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", }, - { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitoring Unit)", }, + { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d8, "Cortex-A72 PMU", "(Performance Monitor Unit)", }, @@ -1042,6 +1112,11 @@ static const struct { { 0x0c1, 0x1ed, "XMC1000 ROM", "(ROM Table)" }, { 0x0E5, 0x000, "SHARC+/Blackfin+", "", }, { 0x0F0, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", }, + { 0x3eb, 0x181, "Tegra 186 ROM", "(ROM Table)", }, + { 0x3eb, 0x211, "Tegra 210 ROM", "(ROM Table)", }, + { 0x3eb, 0x202, "Denver ETM", "(Denver Embedded Trace)", }, + { 0x3eb, 0x302, "Denver Debug", "(Debug Unit)", }, + { 0x3eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", }, /* legacy comment: 0x113: what? */ { ANY_ID, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ { ANY_ID, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ @@ -1053,7 +1128,7 @@ static int dap_rom_display(struct command_context *cmd_ctx, int retval; uint64_t pid; uint32_t cid; - char tabs[7] = ""; + char tabs[16] = ""; if (depth > 16) { command_print(cmd_ctx, "\tTables too deep");