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 "xtensa_debug_module.h"
15 #define TAPINS_PWRCTL 0x08
16 #define TAPINS_PWRSTAT 0x09
17 #define TAPINS_NARSEL 0x1C
18 #define TAPINS_IDCODE 0x1E
19 #define TAPINS_BYPASS 0x1F
21 #define TAPINS_PWRCTL_LEN 8
22 #define TAPINS_PWRSTAT_LEN 8
23 #define TAPINS_NARSEL_ADRLEN 8
24 #define TAPINS_NARSEL_DATALEN 32
25 #define TAPINS_IDCODE_LEN 32
26 #define TAPINS_BYPASS_LEN 1
28 /* Table of debug register offsets for Nexus and APB space */
29 static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] =
30 XTENSA_DM_REG_OFFSETS;
32 static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
34 struct scan_field field;
35 uint8_t t[4] = { 0, 0, 0, 0 };
37 memset(&field, 0, sizeof(field));
38 field.num_bits = dm->tap->ir_length;
40 buf_set_u32(t, 0, field.num_bits, value);
41 jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
44 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
50 struct scan_field field;
52 memset(&field, 0, sizeof(field));
54 field.out_value = src;
55 field.in_value = dest;
56 jtag_add_dr_scan(dm->tap, 1, &field, endstate);
59 int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
64 dm->pwr_ops = cfg->pwr_ops;
65 dm->dbg_ops = cfg->dbg_ops;
67 dm->queue_tdi_idle = cfg->queue_tdi_idle;
68 dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
72 int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
74 return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD);
77 int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value)
79 if (reg >= XDMREG_NUM) {
80 LOG_ERROR("Invalid DBG reg ID %d!", reg);
83 uint8_t regdata = (xdm_regs[reg].nar << 1) | 0;
84 uint8_t dummy[4] = { 0, 0, 0, 0 };
85 xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
86 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE);
87 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
91 int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value)
93 if (reg >= XDMREG_NUM) {
94 LOG_ERROR("Invalid DBG reg ID %d!", reg);
97 uint8_t regdata = (xdm_regs[reg].nar << 1) | 1;
98 uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
99 xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
100 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE);
101 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
105 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm,
106 enum xtensa_dm_pwr_reg reg,
110 if (reg >= XDMREG_PWRNUM) {
111 LOG_ERROR("Invalid PWR reg ID %d!", reg);
114 uint8_t value_clr = (uint8_t)clear;
115 uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
116 int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
117 xtensa_dm_add_set_ir(dm, tap_insn);
118 xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE);
122 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
123 enum xtensa_dm_pwr_reg reg,
126 if (reg >= XDMREG_PWRNUM) {
127 LOG_ERROR("Invalid PWR reg ID %d!", reg);
130 uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
131 int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
132 uint8_t value = (uint8_t)data;
133 xtensa_dm_add_set_ir(dm, tap_insn);
134 xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE);
138 int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
140 uint8_t id_buf[sizeof(uint32_t)];
142 dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf);
143 xtensa_dm_queue_tdi_idle(dm);
144 int res = xtensa_dm_queue_execute(dm);
147 dm->device_id = buf_get_u32(id_buf, 0, 32);
151 int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
153 uint8_t stat_buf[sizeof(uint32_t)];
154 uint8_t stath_buf[sizeof(uint32_t)];
156 /* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set.
157 * It is set in xtensa_examine(), need to move reading of XDMREG_OCDID out of this function */
158 /* dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf);
160 dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stat_buf, clear);
161 dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stath_buf, clear);
162 xtensa_dm_queue_tdi_idle(dm);
163 int res = xtensa_dm_queue_execute(dm);
166 dm->power_status.stat = buf_get_u32(stat_buf, 0, 32);
167 dm->power_status.stath = buf_get_u32(stath_buf, 0, 32);
171 int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
173 uint8_t dsr_buf[sizeof(uint32_t)];
175 xtensa_dm_queue_enable(dm);
176 dm->dbg_ops->queue_reg_read(dm, XDMREG_DSR, dsr_buf);
177 xtensa_dm_queue_tdi_idle(dm);
178 int res = xtensa_dm_queue_execute(dm);
181 dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
185 int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
187 dm->dbg_ops->queue_reg_write(dm, XDMREG_DSR, bits);
188 xtensa_dm_queue_tdi_idle(dm);
189 return xtensa_dm_queue_execute(dm);
192 int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
194 /*Turn off trace unit so we can start a new trace. */
195 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, 0);
196 xtensa_dm_queue_tdi_idle(dm);
197 int res = xtensa_dm_queue_execute(dm);
201 /*Set up parameters */
202 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXADDR, 0);
203 if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) {
204 dm->dbg_ops->queue_reg_write(dm, XDMREG_PCMATCHCTRL,
205 (cfg->stopmask << PCMATCHCTRL_PCML_SHIFT));
206 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRIGGERPC, cfg->stoppc);
208 dm->dbg_ops->queue_reg_write(dm, XDMREG_DELAYCNT, cfg->after);
209 /*Options are mostly hardcoded for now. ToDo: make this more configurable. */
210 dm->dbg_ops->queue_reg_write(
214 ((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN |
215 (cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS);
216 xtensa_dm_queue_tdi_idle(dm);
217 return xtensa_dm_queue_execute(dm);
220 int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
222 uint8_t traxctl_buf[sizeof(uint32_t)];
224 struct xtensa_trace_status trace_status;
226 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf);
227 xtensa_dm_queue_tdi_idle(dm);
228 int res = xtensa_dm_queue_execute(dm);
231 traxctl = buf_get_u32(traxctl_buf, 0, 32);
234 traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
236 dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
237 xtensa_dm_queue_tdi_idle(dm);
238 res = xtensa_dm_queue_execute(dm);
242 /*Check current status of trace hardware */
243 res = xtensa_dm_trace_status_read(dm, &trace_status);
247 if (trace_status.stat & TRAXSTAT_TRACT) {
248 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
254 int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
256 uint8_t traxstat_buf[sizeof(uint32_t)];
258 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXSTAT, traxstat_buf);
259 xtensa_dm_queue_tdi_idle(dm);
260 int res = xtensa_dm_queue_execute(dm);
261 if (res == ERROR_OK && status)
262 status->stat = buf_get_u32(traxstat_buf, 0, 32);
266 int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
268 uint8_t traxctl_buf[sizeof(uint32_t)];
269 uint8_t memadrstart_buf[sizeof(uint32_t)];
270 uint8_t memadrend_buf[sizeof(uint32_t)];
271 uint8_t adr_buf[sizeof(uint32_t)];
276 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf);
277 dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDRSTART, memadrstart_buf);
278 dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDREND, memadrend_buf);
279 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXADDR, adr_buf);
280 xtensa_dm_queue_tdi_idle(dm);
281 int res = xtensa_dm_queue_execute(dm);
282 if (res == ERROR_OK) {
283 config->ctrl = buf_get_u32(traxctl_buf, 0, 32);
284 config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32);
285 config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32);
286 config->addr = buf_get_u32(adr_buf, 0, 32);
291 int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
296 for (unsigned int i = 0; i < size / 4; i++)
297 dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXDATA, &dest[i * 4]);
298 xtensa_dm_queue_tdi_idle(dm);
299 return xtensa_dm_queue_execute(dm);
302 int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
303 const struct xtensa_perfmon_config *config)
308 uint8_t pmstat_buf[4];
309 uint32_t pmctrl = ((config->tracelevel) << 4) +
310 (config->select << 8) +
311 (config->mask << 16) +
312 (config->kernelcnt << 3);
314 /* enable performance monitor */
315 dm->dbg_ops->queue_reg_write(dm, XDMREG_PMG, 0x1);
317 dm->dbg_ops->queue_reg_write(dm, XDMREG_PM0 + counter_id, 0);
318 dm->dbg_ops->queue_reg_write(dm, XDMREG_PMCTRL0 + counter_id, pmctrl);
319 dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf);
320 xtensa_dm_queue_tdi_idle(dm);
321 return xtensa_dm_queue_execute(dm);
324 int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
325 struct xtensa_perfmon_result *out_result)
327 uint8_t pmstat_buf[4];
328 uint8_t pmcount_buf[4];
330 dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf);
331 dm->dbg_ops->queue_reg_read(dm, XDMREG_PM0 + counter_id, pmcount_buf);
332 xtensa_dm_queue_tdi_idle(dm);
333 int res = xtensa_dm_queue_execute(dm);
334 if (res == ERROR_OK) {
335 uint32_t stat = buf_get_u32(pmstat_buf, 0, 32);
336 uint64_t result = buf_get_u32(pmcount_buf, 0, 32);
338 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
339 * high 32 bits of the counter. */
341 out_result->overflow = ((stat & 1) != 0);
342 out_result->value = result;