adiv6: use struct adiv5_ap->ap_num to contain the AP base address

ADIv5 DAP can only have 256 AP, while ADIv6 can provide till
2**40 (1,099,511,627,776) AP per DAP.

Reuse the field ap_num in struct adiv5_ap, currently used on ADIv5
to hold the ADIv5 AP number (apsel), to contain the ADIv6 AP base
address.

Convert struct adiv5_ap->ap_num to 64 bit and initialize it to
DP_APSEL_INVALID for unused AP.
Restrict dap_find_get_ap() to ADIv5 only. To be enhanced.
On ADIv6, let dap_get_ap() return an already allocated AP, or
allocate and return an unused AP.
Add function is_ap_num_valid() and use it.

Change-Id: Ib2fe8c7ec0d08393cd91c29fdac5d632dfc1e438
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6461
Reviewed-by: Daniel Goehring <dgoehrin@os.amperecomputing.com>
Tested-by: jenkins
This commit is contained in:
Antonio Borneo 2021-08-14 23:56:12 +02:00
parent 72fb88613f
commit 3f4bc6ce7f
9 changed files with 156 additions and 73 deletions

View File

@ -4680,6 +4680,8 @@ for TCL scripting.
@deffn {Command} {dap info} [num] @deffn {Command} {dap info} [num]
Displays the ROM table for MEM-AP @var{num}, Displays the ROM table for MEM-AP @var{num},
defaulting to the currently selected AP of the currently selected target. defaulting to the currently selected AP of the currently selected target.
On ADIv5 DAP @var{num} is the numeric index of the AP.
On ADIv6 DAP @var{num} is the base address of the AP.
@end deffn @end deffn
@deffn {Command} {dap init} @deffn {Command} {dap init}
@ -4693,21 +4695,29 @@ The following commands exist as subcommands of DAP instances:
@deffn {Command} {$dap_name info} [num] @deffn {Command} {$dap_name info} [num]
Displays the ROM table for MEM-AP @var{num}, Displays the ROM table for MEM-AP @var{num},
defaulting to the currently selected AP. defaulting to the currently selected AP.
On ADIv5 DAP @var{num} is the numeric index of the AP.
On ADIv6 DAP @var{num} is the base address of the AP.
@end deffn @end deffn
@deffn {Command} {$dap_name apid} [num] @deffn {Command} {$dap_name apid} [num]
Displays ID register from AP @var{num}, defaulting to the currently selected AP. Displays ID register from AP @var{num}, defaulting to the currently selected AP.
On ADIv5 DAP @var{num} is the numeric index of the AP.
On ADIv6 DAP @var{num} is the base address of the AP.
@end deffn @end deffn
@anchor{DAP subcommand apreg} @anchor{DAP subcommand apreg}
@deffn {Command} {$dap_name apreg} ap_num reg [value] @deffn {Command} {$dap_name apreg} ap_num reg [value]
Displays content of a register @var{reg} from AP @var{ap_num} Displays content of a register @var{reg} from AP @var{ap_num}
or set a new value @var{value}. or set a new value @var{value}.
On ADIv5 DAP @var{ap_num} is the numeric index of the AP.
On ADIv6 DAP @var{ap_num} is the base address of the AP.
@var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. @var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc.
@end deffn @end deffn
@deffn {Command} {$dap_name apsel} [num] @deffn {Command} {$dap_name apsel} [num]
Select AP @var{num}, defaulting to 0. Select AP @var{num}, defaulting to 0.
On ADIv5 DAP @var{num} is the numeric index of the AP.
On ADIv6 DAP @var{num} is the base address of the AP.
@end deffn @end deffn
@deffn {Command} {$dap_name dpreg} reg [value] @deffn {Command} {$dap_name dpreg} reg [value]
@ -4725,6 +4735,8 @@ background activity by OpenOCD while you are operating at such low-level.
@deffn {Command} {$dap_name baseaddr} [num] @deffn {Command} {$dap_name baseaddr} [num]
Displays debug base address from MEM-AP @var{num}, Displays debug base address from MEM-AP @var{num},
defaulting to the currently selected AP. defaulting to the currently selected AP.
On ADIv5 DAP @var{num} is the numeric index of the AP.
On ADIv6 DAP @var{num} is the base address of the AP.
@end deffn @end deffn
@deffn {Command} {$dap_name memaccess} [value] @deffn {Command} {$dap_name memaccess} [value]
@ -5098,8 +5110,9 @@ The value should normally correspond to a static mapping for the
scan and after a reset. A manual call to arp_examine is required to scan and after a reset. A manual call to arp_examine is required to
access the target for debugging. access the target for debugging.
@item @code{-ap-num} @var{ap_number} -- set DAP access port for target, @item @code{-ap-num} @var{ap_number} -- set DAP access port for target.
@var{ap_number} is the numeric index of the DAP AP the target is connected to. On ADIv5 DAP @var{ap_number} is the numeric index of the DAP AP the target is connected to.
On ADIv6 DAP @var{ap_number} is the base address of the DAP AP the target is connected to.
Use this option with systems where multiple, independent cores are connected Use this option with systems where multiple, independent cores are connected
to separate access ports of the same DAP. to separate access ports of the same DAP.
@ -9449,7 +9462,10 @@ the @emph{cti} group of commands.
@deffn {Command} {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-baseaddr} base_address @deffn {Command} {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-baseaddr} base_address
Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP
@var{apn}. The @var{base_address} must match the base address of the CTI @var{apn}.
On ADIv5 DAP @var{apn} is the numeric index of the DAP AP the CTI is connected to.
On ADIv6 DAP @var{apn} is the base address of the DAP AP the CTI is connected to.
The @var{base_address} must match the base address of the CTI
on the respective MEM-AP. All arguments are mandatory. This creates a on the respective MEM-AP. All arguments are mandatory. This creates a
new command @command{$cti_name} which is used for various purposes new command @command{$cti_name} which is used for various purposes
including additional configuration. including additional configuration.
@ -10114,8 +10130,9 @@ using the @command{$tpiu_name cget} command.
@item @code{-dap} @var{dap_name} -- names the DAP used to access this @item @code{-dap} @var{dap_name} -- names the DAP used to access this
TPIU. @xref{dapdeclaration,,DAP declaration}, on how to create and manage DAP instances. TPIU. @xref{dapdeclaration,,DAP declaration}, on how to create and manage DAP instances.
@item @code{-ap-num} @var{ap_number} -- sets DAP access port for TPIU, @item @code{-ap-num} @var{ap_number} -- sets DAP access port for TPIU.
@var{ap_number} is the numeric index of the DAP AP the TPIU is connected to. On ADIv5 DAP @var{ap_number} is the numeric index of the DAP AP the TPIU is connected to.
On ADIv6 DAP @var{ap_number} is the base address of the DAP AP the TPIU is connected to.
@item @code{-baseaddr} @var{base_address} -- sets the TPIU @var{base_address} where @item @code{-baseaddr} @var{base_address} -- sets the TPIU @var{base_address} where
to access the TPIU in the DAP AP memory space. to access the TPIU in the DAP AP memory space.

View File

@ -4152,7 +4152,7 @@ static int stlink_dap_reinit_interface(void)
stlink_dap_handle->reconnect_pending = false; stlink_dap_handle->reconnect_pending = false;
/* on new FW, calling mode-leave closes all the opened AP; reopen them! */ /* on new FW, calling mode-leave closes all the opened AP; reopen them! */
if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT) if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)
for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++) for (unsigned int apsel = 0; apsel <= DP_APSEL_MAX; apsel++)
if (test_bit(apsel, opened_ap)) { if (test_bit(apsel, opened_ap)) {
clear_bit(apsel, opened_ap); clear_bit(apsel, opened_ap);
stlink_dap_open_ap(apsel); stlink_dap_open_ap(apsel);
@ -4348,7 +4348,7 @@ static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, u
LOG_DEBUG("Queue: %u commands in %u items", len, items); LOG_DEBUG("Queue: %u commands in %u items", len, items);
int ap_num = DP_APSEL_INVALID; uint32_t ap_num = DP_APSEL_INVALID;
unsigned int cmd_index = 0; unsigned int cmd_index = 0;
unsigned int val_index = ALIGN_UP(items, 4); unsigned int val_index = ALIGN_UP(items, 4);
for (unsigned int i = 0; i < len; i++) { for (unsigned int i = 0; i < len; i++) {
@ -4497,7 +4497,7 @@ static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *
{ {
struct stlink_usb_handle_s *h = handle; struct stlink_usb_handle_s *h = handle;
unsigned int i, items = 0; unsigned int i, items = 0;
int ap_num = DP_APSEL_INVALID; uint32_t ap_num = DP_APSEL_INVALID;
unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE; unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE;
if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
@ -4864,9 +4864,10 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg,
q->ap_w.reg = reg; q->ap_w.reg = reg;
q->ap_w.ap = ap; q->ap_w.ap = ap;
q->ap_w.data = data; q->ap_w.data = data;
if (reg == ADIV5_MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap->ap_num]) { uint8_t ap_num = ap->ap_num;
if (reg == ADIV5_MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap_num]) {
q->ap_w.changes_csw_default = true; q->ap_w.changes_csw_default = true;
last_csw_default[ap->ap_num] = ap->csw_default; last_csw_default[ap_num] = ap->csw_default;
} else { } else {
q->ap_w.changes_csw_default = false; q->ap_w.changes_csw_default = false;
} }

View File

@ -966,16 +966,45 @@ static const char *ap_type_to_description(enum ap_type type)
return "Unknown"; return "Unknown";
} }
bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num)
{
if (!dap)
return false;
/* no autodetection, by now, so uninitialized is equivalent to ADIv5 for
* backward compatibility */
if (!is_adiv6(dap)) {
if (ap_num > DP_APSEL_MAX)
return false;
return true;
}
if (is_adiv6(dap)) {
if (ap_num & 0x0fffULL)
return false;
if (dap->asize != 0)
if (ap_num & ((~0ULL) << dap->asize))
return false;
return true;
}
return false;
}
/* /*
* This function checks the ID for each access port to find the requested Access Port type * This function checks the ID for each access port to find the requested Access Port type
* It also calls dap_get_ap() to increment the AP refcount * It also calls dap_get_ap() to increment the AP refcount
*/ */
int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out) int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out)
{ {
int ap_num; if (is_adiv6(dap)) {
/* TODO: scan the ROM table and detect the AP available */
LOG_DEBUG("On ADIv6 we cannot scan all the possible AP");
return ERROR_FAIL;
}
/* Maximum AP number is 255 since the SELECT register is 8 bits */ /* Maximum AP number is 255 since the SELECT register is 8 bits */
for (ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) { for (unsigned int ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) {
struct adiv5_ap *ap = dap_get_ap(dap, ap_num); struct adiv5_ap *ap = dap_get_ap(dap, ap_num);
if (!ap) if (!ap)
continue; continue;
@ -1014,33 +1043,55 @@ static inline bool is_ap_in_use(struct adiv5_ap *ap)
return ap->refcount > 0 || ap->config_ap_never_release; return ap->refcount > 0 || ap->config_ap_never_release;
} }
static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, unsigned int ap_num) static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num)
{ {
if (ap_num > DP_APSEL_MAX) { if (!is_ap_num_valid(dap, ap_num)) {
LOG_ERROR("Invalid AP#%u", ap_num); LOG_ERROR("Invalid AP#0x%" PRIx64, ap_num);
return NULL; return NULL;
} }
if (is_adiv6(dap)) {
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_num == ap_num) {
++ap->refcount;
return ap;
}
}
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_num = ap_num;
++ap->refcount;
return ap;
}
}
LOG_ERROR("No more AP available!");
return NULL;
}
/* ADIv5 */
struct adiv5_ap *ap = &dap->ap[ap_num]; struct adiv5_ap *ap = &dap->ap[ap_num];
ap->ap_num = ap_num;
++ap->refcount; ++ap->refcount;
return ap; return ap;
} }
/* Return AP with specified ap_num. Increment AP refcount */ /* Return AP with specified ap_num. Increment AP refcount */
struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, unsigned int ap_num) struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num)
{ {
struct adiv5_ap *ap = _dap_get_ap(dap, ap_num); struct adiv5_ap *ap = _dap_get_ap(dap, ap_num);
if (ap) if (ap)
LOG_DEBUG("refcount AP#%u get %u", ap_num, ap->refcount); LOG_DEBUG("refcount AP#0x%" PRIx64 " get %u", ap_num, ap->refcount);
return ap; return ap;
} }
/* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ /* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */
struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, unsigned int ap_num) struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num)
{ {
struct adiv5_ap *ap = _dap_get_ap(dap, ap_num); struct adiv5_ap *ap = _dap_get_ap(dap, ap_num);
if (ap) { if (ap) {
ap->config_ap_never_release = true; ap->config_ap_never_release = true;
LOG_DEBUG("refcount AP#%u get_config %u", ap_num, ap->refcount); LOG_DEBUG("refcount AP#0x%" PRIx64 " get_config %u", ap_num, ap->refcount);
} }
return ap; return ap;
} }
@ -1049,15 +1100,16 @@ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, unsigned int ap_num)
int dap_put_ap(struct adiv5_ap *ap) int dap_put_ap(struct adiv5_ap *ap)
{ {
if (ap->refcount == 0) { if (ap->refcount == 0) {
LOG_ERROR("BUG: refcount AP#%" PRIu8 " put underflow", ap->ap_num); LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " put underflow", ap->ap_num);
return ERROR_FAIL; return ERROR_FAIL;
} }
--ap->refcount; --ap->refcount;
LOG_DEBUG("refcount AP#%" PRIu8 " put %u", ap->ap_num, ap->refcount); LOG_DEBUG("refcount AP#0x%" PRIx64 " put %u", ap->ap_num, ap->refcount);
if (!is_ap_in_use(ap)) { if (!is_ap_in_use(ap)) {
/* defaults from dap_instance_init() */ /* defaults from dap_instance_init() */
ap->ap_num = DP_APSEL_INVALID;
ap->memaccess_tck = 255; ap->memaccess_tck = 255;
ap->tar_autoincr_block = (1 << 10); ap->tar_autoincr_block = (1 << 10);
ap->csw_default = CSW_AHB_DEFAULT; ap->csw_default = CSW_AHB_DEFAULT;
@ -1756,7 +1808,7 @@ static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid); command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid);
if (apid == 0) { if (apid == 0) {
command_print(cmd, "No AP found at this ap 0x%x", ap->ap_num); command_print(cmd, "No AP found at this AP#0x%" PRIx64, ap->ap_num);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -2000,7 +2052,7 @@ static const struct jim_nvp nvp_config_opts[] = {
}; };
static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p) struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint32_t *base_p)
{ {
assert(dap_p && ap_num_p); assert(dap_p && ap_num_p);
@ -2055,11 +2107,13 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
case CFG_AP_NUM: case CFG_AP_NUM:
if (goi->isconfigure) { if (goi->isconfigure) {
/* jim_wide is a signed 64 bits int, ap_num is unsigned with max 52 bits */
jim_wide ap_num; jim_wide ap_num;
e = jim_getopt_wide(goi, &ap_num); e = jim_getopt_wide(goi, &ap_num);
if (e != JIM_OK) if (e != JIM_OK)
return e; return e;
if (ap_num < 0 || ap_num > DP_APSEL_MAX) { /* we still don't know dap->adi_version */
if (ap_num < 0 || (ap_num > DP_APSEL_MAX && (ap_num & 0xfff))) {
Jim_SetResultString(goi->interp, "Invalid AP number!", -1); Jim_SetResultString(goi->interp, "Invalid AP number!", -1);
return JIM_ERR; return JIM_ERR;
} }
@ -2164,15 +2218,15 @@ int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p)
COMMAND_HANDLER(handle_dap_info_command) COMMAND_HANDLER(handle_dap_info_command)
{ {
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel; uint64_t apsel;
switch (CMD_ARGC) { switch (CMD_ARGC) {
case 0: case 0:
apsel = dap->apsel; apsel = dap->apsel;
break; break;
case 1: case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (apsel > DP_APSEL_MAX) { if (!is_ap_num_valid(dap, apsel)) {
command_print(CMD, "Invalid AP number"); command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID; return ERROR_COMMAND_ARGUMENT_INVALID;
} }
@ -2195,7 +2249,8 @@ COMMAND_HANDLER(handle_dap_info_command)
COMMAND_HANDLER(dap_baseaddr_command) COMMAND_HANDLER(dap_baseaddr_command)
{ {
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, baseaddr_lower, baseaddr_upper; uint64_t apsel;
uint32_t baseaddr_lower, baseaddr_upper;
struct adiv5_ap *ap; struct adiv5_ap *ap;
target_addr_t baseaddr; target_addr_t baseaddr;
int retval; int retval;
@ -2207,9 +2262,8 @@ COMMAND_HANDLER(dap_baseaddr_command)
apsel = dap->apsel; apsel = dap->apsel;
break; break;
case 1: case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */ if (!is_ap_num_valid(dap, apsel)) {
if (apsel > DP_APSEL_MAX) {
command_print(CMD, "Invalid AP number"); command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID; return ERROR_COMMAND_ARGUMENT_INVALID;
} }
@ -2294,16 +2348,15 @@ COMMAND_HANDLER(dap_memaccess_command)
COMMAND_HANDLER(dap_apsel_command) COMMAND_HANDLER(dap_apsel_command)
{ {
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel; uint64_t apsel;
switch (CMD_ARGC) { switch (CMD_ARGC) {
case 0: case 0:
command_print(CMD, "%" PRIu32, dap->apsel); command_print(CMD, "0x%" PRIx64, dap->apsel);
return ERROR_OK; return ERROR_OK;
case 1: case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */ if (!is_ap_num_valid(dap, apsel)) {
if (apsel > DP_APSEL_MAX) {
command_print(CMD, "Invalid AP number"); command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID; return ERROR_COMMAND_ARGUMENT_INVALID;
} }
@ -2329,7 +2382,7 @@ COMMAND_HANDLER(dap_apcsw_command)
command_print(CMD, "Cannot get AP"); command_print(CMD, "Cannot get AP");
return ERROR_FAIL; return ERROR_FAIL;
} }
command_print(CMD, "ap %" PRIu32 " selected, csw 0x%8.8" PRIx32, command_print(CMD, "AP#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32,
dap->apsel, ap->csw_default); dap->apsel, ap->csw_default);
break; break;
case 1: case 1:
@ -2376,7 +2429,8 @@ COMMAND_HANDLER(dap_apcsw_command)
COMMAND_HANDLER(dap_apid_command) COMMAND_HANDLER(dap_apid_command)
{ {
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, apid; uint64_t apsel;
uint32_t apid;
int retval; int retval;
switch (CMD_ARGC) { switch (CMD_ARGC) {
@ -2384,9 +2438,8 @@ COMMAND_HANDLER(dap_apid_command)
apsel = dap->apsel; apsel = dap->apsel;
break; break;
case 1: case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */ if (!is_ap_num_valid(dap, apsel)) {
if (apsel > DP_APSEL_MAX) {
command_print(CMD, "Invalid AP number"); command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID; return ERROR_COMMAND_ARGUMENT_INVALID;
} }
@ -2418,23 +2471,30 @@ COMMAND_HANDLER(dap_apid_command)
COMMAND_HANDLER(dap_apreg_command) COMMAND_HANDLER(dap_apreg_command)
{ {
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, reg, value; uint64_t apsel;
uint32_t reg, value;
int retval; int retval;
if (CMD_ARGC < 2 || CMD_ARGC > 3) if (CMD_ARGC < 2 || CMD_ARGC > 3)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */ if (!is_ap_num_valid(dap, apsel)) {
if (apsel > DP_APSEL_MAX) {
command_print(CMD, "Invalid AP number"); command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID; return ERROR_COMMAND_ARGUMENT_INVALID;
} }
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg);
if (reg >= 256 || (reg & 3)) { if (is_adiv6(dap)) {
command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); if (reg >= 4096 || (reg & 3)) {
return ERROR_COMMAND_ARGUMENT_INVALID; command_print(CMD, "Invalid reg value (should be less than 4096 and 4 bytes aligned)");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
} else { /* ADI version 5 */
if (reg >= 256 || (reg & 3)) {
command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
} }
struct adiv5_ap *ap = dap_get_ap(dap, apsel); struct adiv5_ap *ap = dap_get_ap(dap, apsel);

View File

@ -110,8 +110,8 @@
#define DP_SELECT_DPBANK 0x0000000F #define DP_SELECT_DPBANK 0x0000000F
#define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */ #define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */
#define DP_APSEL_MAX (255) #define DP_APSEL_MAX (255) /* for ADIv5 only */
#define DP_APSEL_INVALID (-1) #define DP_APSEL_INVALID 0xF00 /* more than DP_APSEL_MAX and not ADIv6 aligned 4k */
#define DP_TARGETSEL_INVALID 0xFFFFFFFFU #define DP_TARGETSEL_INVALID 0xFFFFFFFFU
#define DP_TARGETSEL_DPID_MASK 0x0FFFFFFFU #define DP_TARGETSEL_DPID_MASK 0x0FFFFFFFU
@ -255,9 +255,11 @@ struct adiv5_ap {
struct adiv5_dap *dap; struct adiv5_dap *dap;
/** /**
* Number of this AP. * ADIv5: Number of this AP (0~255)
* ADIv6: Base address of this AP (4k aligned)
* TODO: to be more coherent, it should be renamed apsel
*/ */
uint8_t ap_num; uint64_t ap_num;
/** /**
* Default value for (MEM-AP) AP_REG_CSW register. * Default value for (MEM-AP) AP_REG_CSW register.
@ -342,7 +344,7 @@ struct adiv5_dap {
struct adiv5_ap ap[DP_APSEL_MAX + 1]; struct adiv5_ap ap[DP_APSEL_MAX + 1];
/* The current manually selected AP by the "dap apsel" command */ /* The current manually selected AP by the "dap apsel" command */
uint32_t apsel; uint64_t apsel;
/** /**
* Cache for DP_SELECT register. A value of DP_SELECT_INVALID * Cache for DP_SELECT register. A value of DP_SELECT_INVALID
@ -551,7 +553,7 @@ static inline int dap_queue_ap_read(struct adiv5_ap *ap,
assert(ap->dap->ops); assert(ap->dap->ops);
if (ap->refcount == 0) { if (ap->refcount == 0) {
ap->refcount = 1; ap->refcount = 1;
LOG_ERROR("BUG: refcount AP#%" PRIu8 " used without get", ap->ap_num); LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " used without get", ap->ap_num);
} }
return ap->dap->ops->queue_ap_read(ap, reg, data); return ap->dap->ops->queue_ap_read(ap, reg, data);
} }
@ -571,7 +573,7 @@ static inline int dap_queue_ap_write(struct adiv5_ap *ap,
assert(ap->dap->ops); assert(ap->dap->ops);
if (ap->refcount == 0) { if (ap->refcount == 0) {
ap->refcount = 1; ap->refcount = 1;
LOG_ERROR("BUG: refcount AP#%" PRIu8 " used without get", ap->ap_num); LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " used without get", ap->ap_num);
} }
return ap->dap->ops->queue_ap_write(ap, reg, data); return ap->dap->ops->queue_ap_write(ap, reg, data);
} }
@ -690,16 +692,19 @@ int mem_ap_init(struct adiv5_ap *ap);
/* Invalidate cached DP select and cached TAR and CSW of all APs */ /* Invalidate cached DP select and cached TAR and CSW of all APs */
void dap_invalidate_cache(struct adiv5_dap *dap); void dap_invalidate_cache(struct adiv5_dap *dap);
/* test if ap_num is valid, based on current knowledge of dap */
bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num);
/* Probe Access Ports to find a particular type. Increment AP refcount */ /* Probe Access Ports to find a particular type. Increment AP refcount */
int dap_find_get_ap(struct adiv5_dap *dap, int dap_find_get_ap(struct adiv5_dap *dap,
enum ap_type type_to_find, enum ap_type type_to_find,
struct adiv5_ap **ap_out); struct adiv5_ap **ap_out);
/* Return AP with specified ap_num. Increment AP refcount */ /* Return AP with specified ap_num. Increment AP refcount */
struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, unsigned int ap_num); struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num);
/* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ /* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */
struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, unsigned int ap_num); struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num);
/* Decrement AP refcount and release the AP when refcount reaches zero */ /* Decrement AP refcount and release the AP when refcount reaches zero */
int dap_put_ap(struct adiv5_ap *ap); int dap_put_ap(struct adiv5_ap *ap);
@ -735,7 +740,7 @@ extern const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self);
extern int dap_cleanup_all(void); extern int dap_cleanup_all(void);
struct adiv5_private_config { struct adiv5_private_config {
int ap_num; uint64_t ap_num;
struct adiv5_dap *dap; struct adiv5_dap *dap;
}; };
@ -744,7 +749,7 @@ extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *go
struct adiv5_mem_ap_spot { struct adiv5_mem_ap_spot {
struct adiv5_dap *dap; struct adiv5_dap *dap;
int ap_num; uint64_t ap_num;
uint32_t base; uint32_t base;
}; };

View File

@ -50,7 +50,7 @@ static void dap_instance_init(struct adiv5_dap *dap)
/* Set up with safe defaults */ /* Set up with safe defaults */
for (i = 0; i <= DP_APSEL_MAX; i++) { for (i = 0; i <= DP_APSEL_MAX; i++) {
dap->ap[i].dap = dap; dap->ap[i].dap = dap;
dap->ap[i].ap_num = i; dap->ap[i].ap_num = DP_APSEL_INVALID;
/* memaccess_tck max is 255 */ /* memaccess_tck max is 255 */
dap->ap[i].memaccess_tck = 255; dap->ap[i].memaccess_tck = 255;
/* Number of bits for tar autoincrement, impl. dep. at least 10 */ /* Number of bits for tar autoincrement, impl. dep. at least 10 */
@ -459,7 +459,7 @@ COMMAND_HANDLER(handle_dap_info_command)
struct target *target = get_current_target(CMD_CTX); struct target *target = get_current_target(CMD_CTX);
struct arm *arm = target_to_arm(target); struct arm *arm = target_to_arm(target);
struct adiv5_dap *dap = arm->dap; struct adiv5_dap *dap = arm->dap;
uint32_t apsel; uint64_t apsel;
if (!dap) { if (!dap) {
LOG_ERROR("DAP instance not available. Probably a HLA target..."); LOG_ERROR("DAP instance not available. Probably a HLA target...");
@ -471,8 +471,8 @@ COMMAND_HANDLER(handle_dap_info_command)
apsel = dap->apsel; apsel = dap->apsel;
break; break;
case 1: case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (apsel > DP_APSEL_MAX) if (!is_ap_num_valid(dap, apsel))
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
break; break;
default: default:

View File

@ -617,8 +617,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
if (obj->enabled) if (obj->enabled)
return JIM_OK; return JIM_OK;
if (transport_is_hla() && obj->spot.ap_num > 0) { if (transport_is_hla() && obj->spot.ap_num != 0) {
LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num); LOG_ERROR("Invalid access port 0x%" PRIx64 ". Only AP#0 allowed with hla transport", obj->spot.ap_num);
return JIM_ERR; return JIM_ERR;
} }
@ -650,8 +650,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
if (obj->spot.ap_num == 0) if (obj->spot.ap_num == 0)
LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name); LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name);
else else
LOG_INFO(MSG "Target %s is on AP %d. Revised command is " LOG_INFO(MSG "Target %s is on AP#0x%" PRIx64 ". Revised command is "
"\'tpiu create %s -dap %s -ap-num %d\'", "\'tpiu create %s -dap %s -ap-num 0x%" PRIx64 "\'",
target_name(target), obj->spot.ap_num, target_name(target), obj->spot.ap_num,
obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num); obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num);
} }
@ -1047,7 +1047,7 @@ COMMAND_HANDLER(handle_tpiu_deprecated_config_command)
struct cortex_m_common *cm = target_to_cm(target); struct cortex_m_common *cm = target_to_cm(target);
struct adiv5_private_config *pc = target->private_config; struct adiv5_private_config *pc = target->private_config;
struct adiv5_dap *dap = pc->dap; struct adiv5_dap *dap = pc->dap;
int ap_num = pc->ap_num; uint64_t ap_num = pc->ap_num;
bool set_recheck_ap_cur_target = false; bool set_recheck_ap_cur_target = false;
LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target)); LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target));
@ -1065,10 +1065,10 @@ COMMAND_HANDLER(handle_tpiu_deprecated_config_command)
set_recheck_ap_cur_target = true; set_recheck_ap_cur_target = true;
} }
LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'", LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num 0x%" PRIx64 "\'",
target_name(target), adiv5_dap_name(dap), ap_num); target_name(target), adiv5_dap_name(dap), ap_num);
retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num %d", retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num 0x%" PRIx64,
target_name(target), adiv5_dap_name(dap), ap_num); target_name(target), adiv5_dap_name(dap), ap_num);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;

View File

@ -241,7 +241,7 @@ struct cortex_m_common {
bool slow_register_read; /* A register has not been ready, poll S_REGRDY */ bool slow_register_read; /* A register has not been ready, poll S_REGRDY */
int apsel; uint64_t apsel;
/* Whether this target has the erratum that makes C_MASKINTS not apply to /* Whether this target has the erratum that makes C_MASKINTS not apply to
* already pending interrupts */ * already pending interrupts */

View File

@ -203,7 +203,7 @@ static int adapter_target_create(struct target *target,
{ {
LOG_DEBUG("%s", __func__); LOG_DEBUG("%s", __func__);
struct adiv5_private_config *pc = target->private_config; struct adiv5_private_config *pc = target->private_config;
if (pc && pc->ap_num > 0) { if (pc && pc->ap_num != DP_APSEL_INVALID && pc->ap_num != 0) {
LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)"); LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)");
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
} }

View File

@ -29,7 +29,7 @@ struct mem_ap {
int common_magic; int common_magic;
struct adiv5_dap *dap; struct adiv5_dap *dap;
struct adiv5_ap *ap; struct adiv5_ap *ap;
int ap_num; uint64_t ap_num;
}; };
static int mem_ap_target_create(struct target *target, Jim_Interp *interp) static int mem_ap_target_create(struct target *target, Jim_Interp *interp)