This is an automated email from Gerrit. "Daniel Goehring <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9248
-- gerrit commit fdaede4c76ef9c6465825b9d7551b45428d46d1a Author: Daniel Goehring <[email protected]> Date: Fri Jul 18 21:08:45 2025 -0600 target/arm: add nested AP low level JTAG support Add nested Access-Port support to the low level JTAG procedures jtag_ap_q_read() jtag_ap_q_write() When calling these two procedures, if the access port is nested, generate transactions on the first MEM-AP port to access the TAR, CSW, and DRW registers of the downstream AHB-AP port. The updated JTAG read/write queue routines provide the framework for future nested AP support modifications. Change-Id: Id972131378d03db691c3b074cc014413068435a4 Signed-off-by: Daniel Goehring <[email protected]> diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index c9ed5b948b..3d52cd55cf 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -818,9 +818,14 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned int reg) return ERROR_OK; } +static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, + uint32_t data); + static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { + struct adiv5_ap *ap_gateway = ap->ap_gateway; + int retval = jtag_limit_queue_size(ap->dap); if (retval != ERROR_OK) return retval; @@ -829,13 +834,41 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, if (retval != ERROR_OK) return retval; - retval = jtag_ap_q_bankselect(ap, reg); - if (retval != ERROR_OK) - return retval; + if (ap_gateway) { + uint32_t csw = CSW_32BIT | CSW_ADDRINC_OFF | ap_gateway->csw_default; + uint32_t tar = ap->ap_num | reg; + + if (csw != ap_gateway->csw_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_CSW(ap_gateway->dap), csw); + if (retval != ERROR_OK) { + ap_gateway->csw_value = 0; + return retval; + } + ap_gateway->csw_value = csw; + } + + if (!ap_gateway->tar_valid || tar != ap_gateway->tar_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_TAR(ap_gateway->dap), tar); + if (retval != ERROR_OK) { + ap_gateway->tar_valid = false; + return retval; + } + ap_gateway->tar_value = tar; + ap_gateway->tar_valid = true; + } - retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, - DPAP_READ, 0, ap->dap->last_read, ap->memaccess_tck, NULL); - ap->dap->last_read = data; + retval = jtag_ap_q_read(ap_gateway, MEM_AP_REG_DRW(ap_gateway->dap), data); + if (retval != ERROR_OK) + return retval; + } else { + retval = jtag_ap_q_bankselect(ap, reg); + if (retval != ERROR_OK) + return retval; + + retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, + DPAP_READ, 0, ap->dap->last_read, ap->memaccess_tck, NULL); + ap->dap->last_read = data; + } return retval; } @@ -843,6 +876,8 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { + struct adiv5_ap *ap_gateway = ap->ap_gateway; + int retval = jtag_limit_queue_size(ap->dap); if (retval != ERROR_OK) return retval; @@ -851,13 +886,42 @@ static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, if (retval != ERROR_OK) return retval; - retval = jtag_ap_q_bankselect(ap, reg); - if (retval != ERROR_OK) - return retval; + if (ap_gateway) { + uint32_t csw = CSW_32BIT | CSW_ADDRINC_OFF | ap_gateway->csw_default; + uint32_t tar = ap->ap_num | reg; + + if (csw != ap_gateway->csw_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_CSW(ap_gateway->dap), csw); + if (retval != ERROR_OK) { + ap_gateway->csw_value = 0; + return retval; + } + ap_gateway->csw_value = csw; + } + + if (!ap_gateway->tar_valid || tar != ap_gateway->tar_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_TAR(ap_gateway->dap), tar); + if (retval != ERROR_OK) { + ap_gateway->tar_valid = false; + return retval; + } + ap_gateway->tar_value = tar; + ap_gateway->tar_valid = true; + } + + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_DRW(ap_gateway->dap), data); + if (retval != ERROR_OK) + return retval; + } else { + retval = jtag_ap_q_bankselect(ap, reg); + if (retval != ERROR_OK) + return retval; + + retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, + DPAP_WRITE, data, ap->dap->last_read, ap->memaccess_tck, NULL); + ap->dap->last_read = NULL; + } - retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, - DPAP_WRITE, data, ap->dap->last_read, ap->memaccess_tck, NULL); - ap->dap->last_read = NULL; return retval; } diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 67a3fcc577..a87933fe0f 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1177,6 +1177,7 @@ static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { struct adiv5_ap *ap = &dap->ap[i]; if (!is_ap_in_use(ap)) { + ap->ap_gateway = NULL; ap->ap_num = ap_num; ++ap->refcount; return ap; @@ -1188,6 +1189,7 @@ static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) /* ADIv5 */ struct adiv5_ap *ap = &dap->ap[ap_num]; + ap->ap_gateway = NULL; ap->ap_num = ap_num; ++ap->refcount; return ap; diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index ebd2752bd8..49bc3ff0b0 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -260,6 +260,11 @@ struct adiv5_ap { */ uint64_t ap_num; + /** + * Gateway AP + */ + struct adiv5_ap *ap_gateway; + /** * Default value for (MEM-AP) AP_REG_CSW register. */ diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 5ba5e1c387..55f2c99150 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -37,6 +37,7 @@ static void dap_instance_init(struct adiv5_dap *dap) for (i = 0; i <= DP_APSEL_MAX; i++) { dap->ap[i].dap = dap; dap->ap[i].ap_num = DP_APSEL_INVALID; + dap->ap[i].ap_gateway = NULL; /* memaccess_tck max is 255 */ dap->ap[i].memaccess_tck = 255; /* Number of bits for tar autoincrement, impl. dep. at least 10 */ --
