1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Xtensa Debug Module (XDM) Support for OpenOCD *
5 * Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
6 * Copyright (C) 2019 Espressif Systems Ltd. *
7 ***************************************************************************/
13 #include <helper/align.h>
14 #include "xtensa_debug_module.h"
16 #define TAPINS_PWRCTL 0x08
17 #define TAPINS_PWRSTAT 0x09
18 #define TAPINS_NARSEL 0x1C
19 #define TAPINS_IDCODE 0x1E
20 #define TAPINS_BYPASS 0x1F
22 #define TAPINS_PWRCTL_LEN 8
23 #define TAPINS_PWRSTAT_LEN 8
24 #define TAPINS_NARSEL_ADRLEN 8
25 #define TAPINS_NARSEL_DATALEN 32
26 #define TAPINS_IDCODE_LEN 32
27 #define TAPINS_BYPASS_LEN 1
29 /* Table of power register offsets for APB space */
30 static const struct xtensa_dm_pwr_reg_offsets xdm_pwr_regs[XDMREG_PWRNUM] =
31 XTENSA_DM_PWR_REG_OFFSETS;
33 /* Table of debug register offsets for Nexus and APB space */
34 static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] =
35 XTENSA_DM_REG_OFFSETS;
37 static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
39 struct scan_field field;
40 uint8_t t[4] = { 0, 0, 0, 0 };
42 memset(&field, 0, sizeof(field));
43 field.num_bits = dm->tap->ir_length;
45 buf_set_u32(t, 0, field.num_bits, value);
46 jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
49 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
55 struct scan_field field;
57 memset(&field, 0, sizeof(field));
59 field.out_value = src;
60 field.in_value = dest;
61 jtag_add_dr_scan(dm->tap, 1, &field, endstate);
64 int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
68 if (!IS_ALIGNED(cfg->ap_offset, XTENSA_DM_APB_ALIGN)) {
69 LOG_ERROR("Xtensa DM APB offset must be aligned to a %dKB multiple",
70 XTENSA_DM_APB_ALIGN / 1024);
74 dm->pwr_ops = cfg->pwr_ops;
75 dm->dbg_ops = cfg->dbg_ops;
77 dm->queue_tdi_idle = cfg->queue_tdi_idle;
78 dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
80 dm->debug_ap = cfg->debug_ap;
81 dm->debug_apsel = cfg->debug_apsel;
82 dm->ap_offset = cfg->ap_offset;
86 void xtensa_dm_deinit(struct xtensa_debug_module *dm)
89 dap_put_ap(dm->debug_ap);
94 int xtensa_dm_poll(struct xtensa_debug_module *dm)
96 /* Check if debug_ap is available to prevent segmentation fault.
97 * If the re-examination after an error does not find a MEM-AP
98 * (e.g. the target stopped communicating), debug_ap pointer
99 * can suddenly become NULL.
101 return (!dm || (dm->dap && !dm->debug_ap)) ? ERROR_FAIL : ERROR_OK;
104 int xtensa_dm_examine(struct xtensa_debug_module *dm)
106 struct adiv5_dap *swjdp = dm->dap;
107 int retval = ERROR_OK;
110 LOG_DEBUG("DM examine: DAP AP select %d", dm->debug_apsel);
112 dap_put_ap(dm->debug_ap);
115 if (dm->debug_apsel == DP_APSEL_INVALID) {
116 LOG_DEBUG("DM examine: search for APB-type MEM-AP...");
117 /* TODO: Determine whether AP_TYPE_AXI_AP APs can be supported... */
118 retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &dm->debug_ap);
119 if (retval != ERROR_OK) {
120 LOG_ERROR("Could not find MEM-AP to control the core");
124 dm->debug_ap = dap_get_ap(swjdp, dm->debug_apsel);
127 /* TODO: Allow a user-specified AP instead of relying on AP_TYPE_APB_AP */
128 dm->debug_apsel = dm->debug_ap->ap_num;
129 LOG_DEBUG("DM examine: Setting apsel to %d", dm->debug_apsel);
131 /* Leave (only) generic DAP stuff for debugport_init(); */
132 dm->debug_ap->memaccess_tck = 8;
134 retval = mem_ap_init(dm->debug_ap);
135 if (retval != ERROR_OK) {
136 LOG_ERROR("MEM-AP init failed: %d", retval);
140 /* TODO: how to set autoincrement range? Hard-code it to 1024 bytes for now */
141 dm->debug_ap->tar_autoincr_block = (1 << 10);
147 int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
149 return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD);
152 int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value)
154 if (reg >= XDMREG_NUM) {
155 LOG_ERROR("Invalid DBG reg ID %d!", reg);
159 /* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with
160 * queued reads, but requires an API change to pass value as a 32-bit pointer.
162 return mem_ap_read_buf(dm->debug_ap, value, 4, 1, xdm_regs[reg].apb + dm->ap_offset);
163 uint8_t regdata = (xdm_regs[reg].nar << 1) | 0;
164 uint8_t dummy[4] = { 0, 0, 0, 0 };
165 xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
166 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE);
167 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
171 int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value)
173 if (reg >= XDMREG_NUM) {
174 LOG_ERROR("Invalid DBG reg ID %d!", reg);
178 return mem_ap_write_u32(dm->debug_ap, xdm_regs[reg].apb + dm->ap_offset, value);
179 uint8_t regdata = (xdm_regs[reg].nar << 1) | 1;
180 uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
181 xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
182 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE);
183 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
187 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm,
188 enum xtensa_dm_pwr_reg reg,
192 if (reg >= XDMREG_PWRNUM) {
193 LOG_ERROR("Invalid PWR reg ID %d!", reg);
197 /* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with
198 * queued reads, but requires an API change to pass value as a 32-bit pointer.
200 uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset;
201 int retval = mem_ap_read_buf(dm->debug_ap, data, 4, 1, apbreg);
202 if (retval == ERROR_OK)
203 retval = mem_ap_write_u32(dm->debug_ap, apbreg, clear);
206 uint8_t value_clr = (uint8_t)clear;
207 uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
208 int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
209 xtensa_dm_add_set_ir(dm, tap_insn);
210 xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE);
214 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
215 enum xtensa_dm_pwr_reg reg,
218 if (reg >= XDMREG_PWRNUM) {
219 LOG_ERROR("Invalid PWR reg ID %d!", reg);
223 uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset;
224 return mem_ap_write_u32(dm->debug_ap, apbreg, data);
226 uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
227 int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
228 uint8_t value = (uint8_t)data;
229 xtensa_dm_add_set_ir(dm, tap_insn);
230 xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE);
234 int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
236 uint8_t id_buf[sizeof(uint32_t)];
238 dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf);
239 xtensa_dm_queue_tdi_idle(dm);
240 int res = xtensa_dm_queue_execute(dm);
243 dm->device_id = buf_get_u32(id_buf, 0, 32);
247 int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
249 uint8_t stat_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 };
250 uint8_t stath_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 };
252 /* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set.
253 * It is set in xtensa_examine(), need to move reading of XDMREG_OCDID out of this function */
254 /* dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf);
256 dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stat_buf, clear);
257 dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stath_buf, clear);
258 xtensa_dm_queue_tdi_idle(dm);
259 int res = xtensa_dm_queue_execute(dm);
262 dm->power_status.stat = buf_get_u32(stat_buf, 0, 32);
263 dm->power_status.stath = buf_get_u32(stath_buf, 0, 32);
267 int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
269 uint8_t dsr_buf[sizeof(uint32_t)];
271 xtensa_dm_queue_enable(dm);
272 dm->dbg_ops->queue_reg_read(dm, XDMREG_DSR, dsr_buf);
273 xtensa_dm_queue_tdi_idle(dm);
274 int res = xtensa_dm_queue_execute(dm);
277 dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
281 int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
283 dm->dbg_ops->queue_reg_write(dm, XDMREG_DSR, bits);
284 xtensa_dm_queue_tdi_idle(dm);
285 return xtensa_dm_queue_execute(dm);
288 int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
290 /*Turn off trace unit so we can start a new trace. */
291 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, 0);
292 xtensa_dm_queue_tdi_idle(dm);
293 int res = xtensa_dm_queue_execute(dm);
297 /*Set up parameters */
298 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXADDR, 0);
299 if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) {
300 dm->dbg_ops->queue_reg_write(dm, XDMREG_PCMATCHCTRL,
301 (cfg->stopmask << PCMATCHCTRL_PCML_SHIFT));
302 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRIGGERPC, cfg->stoppc);
304 dm->dbg_ops->queue_reg_write(dm, XDMREG_DELAYCNT, cfg->after);
305 /*Options are mostly hardcoded for now. ToDo: make this more configurable. */
306 dm->dbg_ops->queue_reg_write(
310 ((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN |
311 (cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS);
312 xtensa_dm_queue_tdi_idle(dm);
313 return xtensa_dm_queue_execute(dm);
316 int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
318 uint8_t traxctl_buf[sizeof(uint32_t)];
320 struct xtensa_trace_status trace_status;
322 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf);
323 xtensa_dm_queue_tdi_idle(dm);
324 int res = xtensa_dm_queue_execute(dm);
327 traxctl = buf_get_u32(traxctl_buf, 0, 32);
330 traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
332 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
333 xtensa_dm_queue_tdi_idle(dm);
334 res = xtensa_dm_queue_execute(dm);
338 /*Check current status of trace hardware */
339 res = xtensa_dm_trace_status_read(dm, &trace_status);
343 if (trace_status.stat & TRAXSTAT_TRACT) {
344 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
350 int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
352 uint8_t traxstat_buf[sizeof(uint32_t)];
354 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXSTAT, traxstat_buf);
355 xtensa_dm_queue_tdi_idle(dm);
356 int res = xtensa_dm_queue_execute(dm);
357 if (res == ERROR_OK && status)
358 status->stat = buf_get_u32(traxstat_buf, 0, 32);
362 int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
364 uint8_t traxctl_buf[sizeof(uint32_t)];
365 uint8_t memadrstart_buf[sizeof(uint32_t)];
366 uint8_t memadrend_buf[sizeof(uint32_t)];
367 uint8_t adr_buf[sizeof(uint32_t)];
372 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf);
373 dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDRSTART, memadrstart_buf);
374 dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDREND, memadrend_buf);
375 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXADDR, adr_buf);
376 xtensa_dm_queue_tdi_idle(dm);
377 int res = xtensa_dm_queue_execute(dm);
378 if (res == ERROR_OK) {
379 config->ctrl = buf_get_u32(traxctl_buf, 0, 32);
380 config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32);
381 config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32);
382 config->addr = buf_get_u32(adr_buf, 0, 32);
387 int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
392 for (unsigned int i = 0; i < size / 4; i++)
393 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXDATA, &dest[i * 4]);
394 xtensa_dm_queue_tdi_idle(dm);
395 return xtensa_dm_queue_execute(dm);
398 int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
399 const struct xtensa_perfmon_config *config)
404 uint8_t pmstat_buf[4];
405 uint32_t pmctrl = ((config->tracelevel) << 4) +
406 (config->select << 8) +
407 (config->mask << 16) +
408 (config->kernelcnt << 3);
410 /* enable performance monitor */
411 dm->dbg_ops->queue_reg_write(dm, XDMREG_PMG, 0x1);
413 dm->dbg_ops->queue_reg_write(dm, XDMREG_PM0 + counter_id, 0);
414 dm->dbg_ops->queue_reg_write(dm, XDMREG_PMCTRL0 + counter_id, pmctrl);
415 dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf);
416 xtensa_dm_queue_tdi_idle(dm);
417 return xtensa_dm_queue_execute(dm);
420 int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
421 struct xtensa_perfmon_result *out_result)
423 uint8_t pmstat_buf[4];
424 uint8_t pmcount_buf[4];
426 dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf);
427 dm->dbg_ops->queue_reg_read(dm, XDMREG_PM0 + counter_id, pmcount_buf);
428 xtensa_dm_queue_tdi_idle(dm);
429 int res = xtensa_dm_queue_execute(dm);
430 if (res == ERROR_OK) {
431 uint32_t stat = buf_get_u32(pmstat_buf, 0, 32);
432 uint64_t result = buf_get_u32(pmcount_buf, 0, 32);
434 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
435 * high 32 bits of the counter. */
437 out_result->overflow = ((stat & 1) != 0);
438 out_result->value = result;