target/xtensa: enable DAP/SWD for generic xtensa

- Enable ADIv5 DAP systems via JTAG or SWD transport
- Select correct PWRCTL/PWRSTAT bits for XDM/APB

Signed-off-by: Ian Thompson <ianst@cadence.com>
Change-Id: I5894210c804f85075da868d0cfc6fb20b589d99f
Reviewed-on: https://review.openocd.org/c/openocd/+/7144
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Ian Thompson 2022-08-25 08:45:14 -07:00 committed by Antonio Borneo
parent ca52cfb2b3
commit b2b514be5b
4 changed files with 190 additions and 36 deletions

View File

@ -776,7 +776,7 @@ static inline bool xtensa_is_stopped(struct target *target)
int xtensa_examine(struct target *target) int xtensa_examine(struct target *target)
{ {
struct xtensa *xtensa = target_to_xtensa(target); struct xtensa *xtensa = target_to_xtensa(target);
unsigned int cmd = PWRCTL_DEBUGWAKEUP | PWRCTL_MEMWAKEUP | PWRCTL_COREWAKEUP; unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa);
LOG_DEBUG("coreid = %d", target->coreid); LOG_DEBUG("coreid = %d", target->coreid);
@ -786,7 +786,7 @@ int xtensa_examine(struct target *target)
} }
xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd);
xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE(xtensa));
xtensa_dm_queue_enable(&xtensa->dbg_mod); xtensa_dm_queue_enable(&xtensa->dbg_mod);
xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
@ -806,13 +806,13 @@ int xtensa_examine(struct target *target)
int xtensa_wakeup(struct target *target) int xtensa_wakeup(struct target *target)
{ {
struct xtensa *xtensa = target_to_xtensa(target); struct xtensa *xtensa = target_to_xtensa(target);
unsigned int cmd = PWRCTL_DEBUGWAKEUP | PWRCTL_MEMWAKEUP | PWRCTL_COREWAKEUP; unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa);
if (xtensa->reset_asserted) if (xtensa->reset_asserted)
cmd |= PWRCTL_CORERESET; cmd |= PWRCTL_CORERESET(xtensa);
xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd);
/* TODO: can we join this with the write above? */ /* TODO: can we join this with the write above? */
xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE(xtensa));
xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
return xtensa_dm_queue_execute(&xtensa->dbg_mod); return xtensa_dm_queue_execute(&xtensa->dbg_mod);
} }
@ -959,8 +959,8 @@ int xtensa_assert_reset(struct target *target)
target->state = TARGET_RESET; target->state = TARGET_RESET;
xtensa_queue_pwr_reg_write(xtensa, xtensa_queue_pwr_reg_write(xtensa,
XDMREG_PWRCTL, XDMREG_PWRCTL,
PWRCTL_JTAGDEBUGUSE | PWRCTL_DEBUGWAKEUP | PWRCTL_MEMWAKEUP | PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) |
PWRCTL_COREWAKEUP | PWRCTL_CORERESET); PWRCTL_COREWAKEUP(xtensa) | PWRCTL_CORERESET(xtensa));
xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
if (res != ERROR_OK) if (res != ERROR_OK)
@ -980,8 +980,8 @@ int xtensa_deassert_reset(struct target *target)
OCDDCR_ENABLEOCD | OCDDCR_DEBUGINTERRUPT); OCDDCR_ENABLEOCD | OCDDCR_DEBUGINTERRUPT);
xtensa_queue_pwr_reg_write(xtensa, xtensa_queue_pwr_reg_write(xtensa,
XDMREG_PWRCTL, XDMREG_PWRCTL,
PWRCTL_JTAGDEBUGUSE | PWRCTL_DEBUGWAKEUP | PWRCTL_MEMWAKEUP | PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) |
PWRCTL_COREWAKEUP); PWRCTL_COREWAKEUP(xtensa));
xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
if (res != ERROR_OK) if (res != ERROR_OK)
@ -2013,13 +2013,17 @@ int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_
int xtensa_poll(struct target *target) int xtensa_poll(struct target *target)
{ {
struct xtensa *xtensa = target_to_xtensa(target); struct xtensa *xtensa = target_to_xtensa(target);
if (xtensa_dm_poll(&xtensa->dbg_mod) != ERROR_OK) {
target->state = TARGET_UNKNOWN;
return ERROR_TARGET_NOT_EXAMINED;
}
int res = xtensa_dm_power_status_read(&xtensa->dbg_mod, PWRSTAT_DEBUGWASRESET | int res = xtensa_dm_power_status_read(&xtensa->dbg_mod, PWRSTAT_DEBUGWASRESET(xtensa) |
PWRSTAT_COREWASRESET); PWRSTAT_COREWASRESET(xtensa));
if (xtensa->dbg_mod.power_status.stat != xtensa->dbg_mod.power_status.stath) if (xtensa->dbg_mod.power_status.stat != xtensa->dbg_mod.power_status.stath)
LOG_TARGET_DEBUG(target, "PWRSTAT: read 0x%08" PRIx32 ", clear 0x%08lx, reread 0x%08" PRIx32, LOG_TARGET_DEBUG(target, "PWRSTAT: read 0x%08" PRIx32 ", clear 0x%08lx, reread 0x%08" PRIx32,
xtensa->dbg_mod.power_status.stat, xtensa->dbg_mod.power_status.stat,
PWRSTAT_DEBUGWASRESET | PWRSTAT_COREWASRESET, PWRSTAT_DEBUGWASRESET(xtensa) | PWRSTAT_COREWASRESET(xtensa),
xtensa->dbg_mod.power_status.stath); xtensa->dbg_mod.power_status.stath);
if (res != ERROR_OK) if (res != ERROR_OK)
return res; return res;
@ -2047,7 +2051,7 @@ int xtensa_poll(struct target *target)
"DSR has changed: was 0x%08" PRIx32 " now 0x%08" PRIx32, "DSR has changed: was 0x%08" PRIx32 " now 0x%08" PRIx32,
prev_dsr, prev_dsr,
xtensa->dbg_mod.core_status.dsr); xtensa->dbg_mod.core_status.dsr);
if (xtensa->dbg_mod.power_status.stath & PWRSTAT_COREWASRESET) { if (xtensa->dbg_mod.power_status.stath & PWRSTAT_COREWASRESET(xtensa)) {
/* if RESET state is persitent */ /* if RESET state is persitent */
target->state = TARGET_RESET; target->state = TARGET_RESET;
} else if (!xtensa_dm_is_powered(&xtensa->dbg_mod)) { } else if (!xtensa_dm_is_powered(&xtensa->dbg_mod)) {
@ -2957,6 +2961,7 @@ void xtensa_target_deinit(struct target *target)
LOG_ERROR("Failed to clear OCDDCR_ENABLEOCD!"); LOG_ERROR("Failed to clear OCDDCR_ENABLEOCD!");
return; return;
} }
xtensa_dm_deinit(&xtensa->dbg_mod);
} }
xtensa_free_reg_cache(target); xtensa_free_reg_cache(target);
free(xtensa->hw_brps); free(xtensa->hw_brps);

View File

@ -83,10 +83,23 @@ static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp)
.tap = NULL, .tap = NULL,
.queue_tdi_idle = NULL, .queue_tdi_idle = NULL,
.queue_tdi_idle_arg = NULL, .queue_tdi_idle_arg = NULL,
.dap = NULL,
.debug_ap = NULL,
.debug_apsel = DP_APSEL_INVALID,
.ap_offset = 0,
}; };
xtensa_chip_dm_cfg.tap = target->tap; struct adiv5_private_config *pc = target->private_config;
LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname, target->tap->abs_chain_position); if (adiv5_verify_config(pc) == ERROR_OK) {
xtensa_chip_dm_cfg.dap = pc->dap;
xtensa_chip_dm_cfg.debug_apsel = pc->ap_num;
xtensa_chip_dm_cfg.ap_offset = target->dbgbase;
LOG_DEBUG("DAP: ap_num %" PRId64 " DAP %p\n", pc->ap_num, pc->dap);
} else {
xtensa_chip_dm_cfg.tap = target->tap;
LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname,
target->tap->abs_chain_position);
}
struct xtensa_chip_common *xtensa_chip = calloc(1, sizeof(struct xtensa_chip_common)); struct xtensa_chip_common *xtensa_chip = calloc(1, sizeof(struct xtensa_chip_common));
if (!xtensa_chip) { if (!xtensa_chip) {
@ -116,13 +129,26 @@ void xtensa_chip_target_deinit(struct target *target)
static int xtensa_chip_examine(struct target *target) static int xtensa_chip_examine(struct target *target)
{ {
return xtensa_examine(target); struct xtensa *xtensa = target_to_xtensa(target);
int retval = xtensa_dm_examine(&xtensa->dbg_mod);
if (retval == ERROR_OK)
retval = xtensa_examine(target);
return retval;
} }
int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi) int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi)
{ {
target->has_dap = false; static bool dap_configured;
return JIM_CONTINUE; int ret = adiv5_jim_configure(target, goi);
if (ret == JIM_OK) {
LOG_DEBUG("xtensa '-dap' target option found");
dap_configured = true;
}
if (!dap_configured) {
LOG_DEBUG("xtensa '-dap' target option not yet found, assuming JTAG...");
target->has_dap = false;
}
return ret;
} }
/** Methods for generic example of Xtensa-based chip-level targets. */ /** Methods for generic example of Xtensa-based chip-level targets. */

View File

@ -10,6 +10,7 @@
#include <config.h> #include <config.h>
#endif #endif
#include <helper/align.h>
#include "xtensa_debug_module.h" #include "xtensa_debug_module.h"
#define TAPINS_PWRCTL 0x08 #define TAPINS_PWRCTL 0x08
@ -25,6 +26,10 @@
#define TAPINS_IDCODE_LEN 32 #define TAPINS_IDCODE_LEN 32
#define TAPINS_BYPASS_LEN 1 #define TAPINS_BYPASS_LEN 1
/* Table of power register offsets for APB space */
static const struct xtensa_dm_pwr_reg_offsets xdm_pwr_regs[XDMREG_PWRNUM] =
XTENSA_DM_PWR_REG_OFFSETS;
/* Table of debug register offsets for Nexus and APB space */ /* Table of debug register offsets for Nexus and APB space */
static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] = static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] =
XTENSA_DM_REG_OFFSETS; XTENSA_DM_REG_OFFSETS;
@ -60,15 +65,85 @@ int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_mod
{ {
if (!dm || !cfg) if (!dm || !cfg)
return ERROR_FAIL; return ERROR_FAIL;
if (!IS_ALIGNED(cfg->ap_offset, XTENSA_DM_APB_ALIGN)) {
LOG_ERROR("Xtensa DM APB offset must be aligned to a %dKB multiple",
XTENSA_DM_APB_ALIGN / 1024);
return ERROR_FAIL;
}
dm->pwr_ops = cfg->pwr_ops; dm->pwr_ops = cfg->pwr_ops;
dm->dbg_ops = cfg->dbg_ops; dm->dbg_ops = cfg->dbg_ops;
dm->tap = cfg->tap; dm->tap = cfg->tap;
dm->queue_tdi_idle = cfg->queue_tdi_idle; dm->queue_tdi_idle = cfg->queue_tdi_idle;
dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg; dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
dm->dap = cfg->dap;
dm->debug_ap = cfg->debug_ap;
dm->debug_apsel = cfg->debug_apsel;
dm->ap_offset = cfg->ap_offset;
return ERROR_OK; return ERROR_OK;
} }
void xtensa_dm_deinit(struct xtensa_debug_module *dm)
{
if (dm->debug_ap) {
dap_put_ap(dm->debug_ap);
dm->debug_ap = NULL;
}
}
int xtensa_dm_poll(struct xtensa_debug_module *dm)
{
/* Check if debug_ap is available to prevent segmentation fault.
* If the re-examination after an error does not find a MEM-AP
* (e.g. the target stopped communicating), debug_ap pointer
* can suddenly become NULL.
*/
return (!dm || (dm->dap && !dm->debug_ap)) ? ERROR_FAIL : ERROR_OK;
}
int xtensa_dm_examine(struct xtensa_debug_module *dm)
{
struct adiv5_dap *swjdp = dm->dap;
int retval = ERROR_OK;
if (swjdp) {
LOG_DEBUG("DM examine: DAP AP select %d", dm->debug_apsel);
if (dm->debug_ap) {
dap_put_ap(dm->debug_ap);
dm->debug_ap = NULL;
}
if (dm->debug_apsel == DP_APSEL_INVALID) {
LOG_DEBUG("DM examine: search for APB-type MEM-AP...");
/* TODO: Determine whether AP_TYPE_AXI_AP APs can be supported... */
retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &dm->debug_ap);
if (retval != ERROR_OK) {
LOG_ERROR("Could not find MEM-AP to control the core");
return retval;
}
} else {
dm->debug_ap = dap_get_ap(swjdp, dm->debug_apsel);
}
/* TODO: Allow a user-specified AP instead of relying on AP_TYPE_APB_AP */
dm->debug_apsel = dm->debug_ap->ap_num;
LOG_DEBUG("DM examine: Setting apsel to %d", dm->debug_apsel);
/* Leave (only) generic DAP stuff for debugport_init(); */
dm->debug_ap->memaccess_tck = 8;
retval = mem_ap_init(dm->debug_ap);
if (retval != ERROR_OK) {
LOG_ERROR("MEM-AP init failed: %d", retval);
return retval;
}
/* TODO: how to set autoincrement range? Hard-code it to 1024 bytes for now */
dm->debug_ap->tar_autoincr_block = (1 << 10);
}
return retval;
}
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm) int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
{ {
return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD); return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD);
@ -80,6 +155,11 @@ int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg
LOG_ERROR("Invalid DBG reg ID %d!", reg); LOG_ERROR("Invalid DBG reg ID %d!", reg);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (dm->dap)
/* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with
* queued reads, but requires an API change to pass value as a 32-bit pointer.
*/
return mem_ap_read_buf(dm->debug_ap, value, 4, 1, xdm_regs[reg].apb + dm->ap_offset);
uint8_t regdata = (xdm_regs[reg].nar << 1) | 0; uint8_t regdata = (xdm_regs[reg].nar << 1) | 0;
uint8_t dummy[4] = { 0, 0, 0, 0 }; uint8_t dummy[4] = { 0, 0, 0, 0 };
xtensa_dm_add_set_ir(dm, TAPINS_NARSEL); xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
@ -94,6 +174,8 @@ int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg
LOG_ERROR("Invalid DBG reg ID %d!", reg); LOG_ERROR("Invalid DBG reg ID %d!", reg);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (dm->dap)
return mem_ap_write_u32(dm->debug_ap, xdm_regs[reg].apb + dm->ap_offset, value);
uint8_t regdata = (xdm_regs[reg].nar << 1) | 1; uint8_t regdata = (xdm_regs[reg].nar << 1) | 1;
uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 }; uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
xtensa_dm_add_set_ir(dm, TAPINS_NARSEL); xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
@ -111,6 +193,16 @@ int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm,
LOG_ERROR("Invalid PWR reg ID %d!", reg); LOG_ERROR("Invalid PWR reg ID %d!", reg);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (dm->dap) {
/* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with
* queued reads, but requires an API change to pass value as a 32-bit pointer.
*/
uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset;
int retval = mem_ap_read_buf(dm->debug_ap, data, 4, 1, apbreg);
if (retval == ERROR_OK)
retval = mem_ap_write_u32(dm->debug_ap, apbreg, clear);
return retval;
}
uint8_t value_clr = (uint8_t)clear; uint8_t value_clr = (uint8_t)clear;
uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT; uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN; int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
@ -127,6 +219,10 @@ int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
LOG_ERROR("Invalid PWR reg ID %d!", reg); LOG_ERROR("Invalid PWR reg ID %d!", reg);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (dm->dap) {
uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset;
return mem_ap_write_u32(dm->debug_ap, apbreg, data);
}
uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT; uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN; int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
uint8_t value = (uint8_t)data; uint8_t value = (uint8_t)data;

View File

@ -12,6 +12,7 @@
#define OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H #define OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H
#include <jtag/jtag.h> #include <jtag/jtag.h>
#include <target/arm_adi_v5.h>
#include <helper/bits.h> #include <helper/bits.h>
#include <target/target.h> #include <target/target.h>
@ -45,19 +46,22 @@ struct xtensa_dm_pwr_reg_offsets {
Module to happen correctly. When it is set, any write to this bit clears it. Module to happen correctly. When it is set, any write to this bit clears it.
Either don't access it, or re-write it to 1 so JTAG accesses continue. Either don't access it, or re-write it to 1 so JTAG accesses continue.
*/ */
#define PWRCTL_JTAGDEBUGUSE BIT(7) #define PWRCTL_JTAGDEBUGUSE(x) (((x)->dbg_mod.dap) ? (0) : BIT(7))
#define PWRCTL_DEBUGRESET BIT(6) #define PWRCTL_DEBUGRESET(x) (((x)->dbg_mod.dap) ? BIT(28) : BIT(6))
#define PWRCTL_CORERESET BIT(4) #define PWRCTL_CORERESET(x) (((x)->dbg_mod.dap) ? BIT(16) : BIT(4))
#define PWRCTL_DEBUGWAKEUP BIT(2) #define PWRCTL_DEBUGWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(12) : BIT(2))
#define PWRCTL_MEMWAKEUP BIT(1) #define PWRCTL_MEMWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(8) : BIT(1))
#define PWRCTL_COREWAKEUP BIT(0) #define PWRCTL_COREWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(0) : BIT(0))
#define PWRSTAT_DEBUGWASRESET_DM(d) (((d)->dap) ? BIT(28) : BIT(6))
#define PWRSTAT_COREWASRESET_DM(d) (((d)->dap) ? BIT(16) : BIT(4))
#define PWRSTAT_DEBUGWASRESET(x) (PWRSTAT_DEBUGWASRESET_DM(&((x)->dbg_mod)))
#define PWRSTAT_COREWASRESET(x) (PWRSTAT_COREWASRESET_DM(&((x)->dbg_mod)))
#define PWRSTAT_CORESTILLNEEDED(x) (((x)->dbg_mod.dap) ? BIT(4) : BIT(3))
#define PWRSTAT_DEBUGDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(12) : BIT(2))
#define PWRSTAT_MEMDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(8) : BIT(1))
#define PWRSTAT_COREDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(0) : BIT(0))
#define PWRSTAT_DEBUGWASRESET BIT(6)
#define PWRSTAT_COREWASRESET BIT(4)
#define PWRSTAT_CORESTILLNEEDED BIT(3)
#define PWRSTAT_DEBUGDOMAINON BIT(2)
#define PWRSTAT_MEMDOMAINON BIT(1)
#define PWRSTAT_COREDOMAINON BIT(0)
/* Virtual IDs for using with xtensa_debug_ops API */ /* Virtual IDs for using with xtensa_debug_ops API */
enum xtensa_dm_reg { enum xtensa_dm_reg {
/* TRAX Registers */ /* TRAX Registers */
@ -236,7 +240,7 @@ struct xtensa_dm_reg_offsets {
{ .nar = 0x7f, .apb = 0x3ffc }, /* XDMREG_COMPID3 */ \ { .nar = 0x7f, .apb = 0x3ffc }, /* XDMREG_COMPID3 */ \
} }
#define XTENSA_DM_APB_MASK (0x3fff) #define XTENSA_DM_APB_ALIGN 0x4000
/* OCD registers, bit definitions */ /* OCD registers, bit definitions */
#define OCDDCR_ENABLEOCD BIT(0) #define OCDDCR_ENABLEOCD BIT(0)
@ -408,24 +412,47 @@ struct xtensa_perfmon_result {
struct xtensa_debug_module_config { struct xtensa_debug_module_config {
const struct xtensa_power_ops *pwr_ops; const struct xtensa_power_ops *pwr_ops;
const struct xtensa_debug_ops *dbg_ops; const struct xtensa_debug_ops *dbg_ops;
/* Either JTAG or DAP structures will be populated */
struct jtag_tap *tap; struct jtag_tap *tap;
void (*queue_tdi_idle)(struct target *target); void (*queue_tdi_idle)(struct target *target);
void *queue_tdi_idle_arg; void *queue_tdi_idle_arg;
/* For targets conforming to ARM Debug Interface v5,
* "dap" references the Debug Access Port (DAP)
* used to make requests to the target;
* "debug_ap" is AP instance connected to processor
*/
struct adiv5_dap *dap;
struct adiv5_ap *debug_ap;
int debug_apsel;
uint32_t ap_offset;
}; };
struct xtensa_debug_module { struct xtensa_debug_module {
const struct xtensa_power_ops *pwr_ops; const struct xtensa_power_ops *pwr_ops;
const struct xtensa_debug_ops *dbg_ops; const struct xtensa_debug_ops *dbg_ops;
/* Either JTAG or DAP structures will be populated */
struct jtag_tap *tap; struct jtag_tap *tap;
void (*queue_tdi_idle)(struct target *target); void (*queue_tdi_idle)(struct target *target);
void *queue_tdi_idle_arg; void *queue_tdi_idle_arg;
/* DAP struct; AP instance connected to processor */
struct adiv5_dap *dap;
struct adiv5_ap *debug_ap;
int debug_apsel;
struct xtensa_power_status power_status; struct xtensa_power_status power_status;
struct xtensa_core_status core_status; struct xtensa_core_status core_status;
xtensa_ocdid_t device_id; xtensa_ocdid_t device_id;
uint32_t ap_offset;
}; };
int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg); int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg);
void xtensa_dm_deinit(struct xtensa_debug_module *dm);
int xtensa_dm_poll(struct xtensa_debug_module *dm);
int xtensa_dm_examine(struct xtensa_debug_module *dm);
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm); int xtensa_dm_queue_enable(struct xtensa_debug_module *dm);
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value); int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value);
int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value); int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value);
@ -439,7 +466,7 @@ int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
static inline int xtensa_dm_queue_execute(struct xtensa_debug_module *dm) static inline int xtensa_dm_queue_execute(struct xtensa_debug_module *dm)
{ {
return jtag_execute_queue(); return dm->dap ? dap_run(dm->dap) : jtag_execute_queue();
} }
static inline void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm) static inline void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm)
@ -492,14 +519,14 @@ static inline bool xtensa_dm_is_online(struct xtensa_debug_module *dm)
static inline bool xtensa_dm_tap_was_reset(struct xtensa_debug_module *dm) static inline bool xtensa_dm_tap_was_reset(struct xtensa_debug_module *dm)
{ {
return !(dm->power_status.prev_stat & PWRSTAT_DEBUGWASRESET) && return !(dm->power_status.prev_stat & PWRSTAT_DEBUGWASRESET_DM(dm)) &&
dm->power_status.stat & PWRSTAT_DEBUGWASRESET; dm->power_status.stat & PWRSTAT_DEBUGWASRESET_DM(dm);
} }
static inline bool xtensa_dm_core_was_reset(struct xtensa_debug_module *dm) static inline bool xtensa_dm_core_was_reset(struct xtensa_debug_module *dm)
{ {
return !(dm->power_status.prev_stat & PWRSTAT_COREWASRESET) && return !(dm->power_status.prev_stat & PWRSTAT_COREWASRESET_DM(dm)) &&
dm->power_status.stat & PWRSTAT_COREWASRESET; dm->power_status.stat & PWRSTAT_COREWASRESET_DM(dm);
} }
static inline bool xtensa_dm_core_is_stalled(struct xtensa_debug_module *dm) static inline bool xtensa_dm_core_is_stalled(struct xtensa_debug_module *dm)