7f8a75bc66b78e96cf234f126afaf61a38fbea80
[fw/openocd] / src / target / xtensa / xtensa_debug_module.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
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  ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include "xtensa_debug_module.h"
14
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
20
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
27
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;
31
32 static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
33 {
34         struct scan_field field;
35         uint8_t t[4] = { 0, 0, 0, 0 };
36
37         memset(&field, 0, sizeof(field));
38         field.num_bits = dm->tap->ir_length;
39         field.out_value = t;
40         buf_set_u32(t, 0, field.num_bits, value);
41         jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
42 }
43
44 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
45         int len,
46         const uint8_t *src,
47         uint8_t *dest,
48         tap_state_t endstate)
49 {
50         struct scan_field field;
51
52         memset(&field, 0, sizeof(field));
53         field.num_bits = len;
54         field.out_value = src;
55         field.in_value = dest;
56         jtag_add_dr_scan(dm->tap, 1, &field, endstate);
57 }
58
59 int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
60 {
61         if (!dm || !cfg)
62                 return ERROR_FAIL;
63
64         dm->pwr_ops = cfg->pwr_ops;
65         dm->dbg_ops = cfg->dbg_ops;
66         dm->tap = cfg->tap;
67         dm->queue_tdi_idle = cfg->queue_tdi_idle;
68         dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
69         return ERROR_OK;
70 }
71
72 int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
73 {
74         return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD);
75 }
76
77 int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value)
78 {
79         if (reg >= XDMREG_NUM) {
80                 LOG_ERROR("Invalid DBG reg ID %d!", reg);
81                 return ERROR_FAIL;
82         }
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, &regdata, NULL, TAP_IDLE);
87         xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
88         return ERROR_OK;
89 }
90
91 int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value)
92 {
93         if (reg >= XDMREG_NUM) {
94                 LOG_ERROR("Invalid DBG reg ID %d!", reg);
95                 return ERROR_FAIL;
96         }
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, &regdata, NULL, TAP_IDLE);
101         xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
102         return ERROR_OK;
103 }
104
105 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm,
106         enum xtensa_dm_pwr_reg reg,
107         uint8_t *data,
108         uint32_t clear)
109 {
110         if (reg >= XDMREG_PWRNUM) {
111                 LOG_ERROR("Invalid PWR reg ID %d!", reg);
112                 return ERROR_FAIL;
113         }
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);
119         return ERROR_OK;
120 }
121
122 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
123         enum xtensa_dm_pwr_reg reg,
124         uint32_t data)
125 {
126         if (reg >= XDMREG_PWRNUM) {
127                 LOG_ERROR("Invalid PWR reg ID %d!", reg);
128                 return ERROR_FAIL;
129         }
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);
135         return ERROR_OK;
136 }
137
138 int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
139 {
140         uint8_t id_buf[sizeof(uint32_t)];
141
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);
145         if (res != ERROR_OK)
146                 return res;
147         dm->device_id = buf_get_u32(id_buf, 0, 32);
148         return ERROR_OK;
149 }
150
151 int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
152 {
153         uint8_t stat_buf[sizeof(uint32_t)];
154         uint8_t stath_buf[sizeof(uint32_t)];
155
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);
159          *Read reset state */
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);
164         if (res != ERROR_OK)
165                 return res;
166         dm->power_status.stat = buf_get_u32(stat_buf, 0, 32);
167         dm->power_status.stath = buf_get_u32(stath_buf, 0, 32);
168         return res;
169 }
170
171 int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
172 {
173         uint8_t dsr_buf[sizeof(uint32_t)];
174
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);
179         if (res != ERROR_OK)
180                 return res;
181         dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
182         return res;
183 }
184
185 int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
186 {
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);
190 }
191
192 int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
193 {
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);
198         if (res != ERROR_OK)
199                 return res;
200
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);
207         }
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(
211                 dm,
212                 XDMREG_TRAXCTRL,
213                 TRAXCTRL_TREN |
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);
218 }
219
220 int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
221 {
222         uint8_t traxctl_buf[sizeof(uint32_t)];
223         uint32_t traxctl;
224         struct xtensa_trace_status trace_status;
225
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);
229         if (res != ERROR_OK)
230                 return res;
231         traxctl = buf_get_u32(traxctl_buf, 0, 32);
232
233         if (!pto_enable)
234                 traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
235
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);
239         if (res != ERROR_OK)
240                 return res;
241
242         /*Check current status of trace hardware */
243         res = xtensa_dm_trace_status_read(dm, &trace_status);
244         if (res != ERROR_OK)
245                 return res;
246
247         if (trace_status.stat & TRAXSTAT_TRACT) {
248                 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
249                 return ERROR_FAIL;
250         }
251         return ERROR_OK;
252 }
253
254 int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
255 {
256         uint8_t traxstat_buf[sizeof(uint32_t)];
257
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);
263         return res;
264 }
265
266 int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
267 {
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)];
272
273         if (!config)
274                 return ERROR_FAIL;
275
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);
287         }
288         return res;
289 }
290
291 int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
292 {
293         if (!dest)
294                 return ERROR_FAIL;
295
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);
300 }
301
302 int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
303         const struct xtensa_perfmon_config *config)
304 {
305         if (!config)
306                 return ERROR_FAIL;
307
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);
313
314         /* enable performance monitor */
315         dm->dbg_ops->queue_reg_write(dm, XDMREG_PMG, 0x1);
316         /* reset counter */
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);
322 }
323
324 int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
325         struct xtensa_perfmon_result *out_result)
326 {
327         uint8_t pmstat_buf[4];
328         uint8_t pmcount_buf[4];
329
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);
337
338                 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
339                 * high 32 bits of the counter. */
340                 if (out_result) {
341                         out_result->overflow = ((stat & 1) != 0);
342                         out_result->value = result;
343                 }
344         }
345
346         return res;
347 }