target/xtensa: fully initialize buffers for PWRSTAT read
[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 <helper/align.h>
14 #include "xtensa_debug_module.h"
15
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
21
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
28
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;
32
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;
36
37 static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
38 {
39         struct scan_field field;
40         uint8_t t[4] = { 0, 0, 0, 0 };
41
42         memset(&field, 0, sizeof(field));
43         field.num_bits = dm->tap->ir_length;
44         field.out_value = t;
45         buf_set_u32(t, 0, field.num_bits, value);
46         jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
47 }
48
49 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
50         int len,
51         const uint8_t *src,
52         uint8_t *dest,
53         tap_state_t endstate)
54 {
55         struct scan_field field;
56
57         memset(&field, 0, sizeof(field));
58         field.num_bits = len;
59         field.out_value = src;
60         field.in_value = dest;
61         jtag_add_dr_scan(dm->tap, 1, &field, endstate);
62 }
63
64 int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
65 {
66         if (!dm || !cfg)
67                 return ERROR_FAIL;
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);
71                 return ERROR_FAIL;
72         }
73
74         dm->pwr_ops = cfg->pwr_ops;
75         dm->dbg_ops = cfg->dbg_ops;
76         dm->tap = cfg->tap;
77         dm->queue_tdi_idle = cfg->queue_tdi_idle;
78         dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
79         dm->dap = cfg->dap;
80         dm->debug_ap = cfg->debug_ap;
81         dm->debug_apsel = cfg->debug_apsel;
82         dm->ap_offset = cfg->ap_offset;
83         return ERROR_OK;
84 }
85
86 void xtensa_dm_deinit(struct xtensa_debug_module *dm)
87 {
88         if (dm->debug_ap) {
89                 dap_put_ap(dm->debug_ap);
90                 dm->debug_ap = NULL;
91         }
92 }
93
94 int xtensa_dm_poll(struct xtensa_debug_module *dm)
95 {
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.
100          */
101         return (!dm || (dm->dap && !dm->debug_ap)) ? ERROR_FAIL : ERROR_OK;
102 }
103
104 int xtensa_dm_examine(struct xtensa_debug_module *dm)
105 {
106         struct adiv5_dap *swjdp = dm->dap;
107         int retval = ERROR_OK;
108
109         if (swjdp) {
110                 LOG_DEBUG("DM examine: DAP AP select %d", dm->debug_apsel);
111                 if (dm->debug_ap) {
112                         dap_put_ap(dm->debug_ap);
113                         dm->debug_ap = NULL;
114                 }
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");
121                                 return retval;
122                         }
123                 } else {
124                         dm->debug_ap = dap_get_ap(swjdp, dm->debug_apsel);
125                 }
126
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);
130
131                 /* Leave (only) generic DAP stuff for debugport_init(); */
132                 dm->debug_ap->memaccess_tck = 8;
133
134                 retval = mem_ap_init(dm->debug_ap);
135                 if (retval != ERROR_OK) {
136                         LOG_ERROR("MEM-AP init failed: %d", retval);
137                         return retval;
138                 }
139
140                 /* TODO: how to set autoincrement range? Hard-code it to 1024 bytes for now */
141                 dm->debug_ap->tar_autoincr_block = (1 << 10);
142         }
143
144         return retval;
145 }
146
147 int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
148 {
149         return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD);
150 }
151
152 int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value)
153 {
154         if (reg >= XDMREG_NUM) {
155                 LOG_ERROR("Invalid DBG reg ID %d!", reg);
156                 return ERROR_FAIL;
157         }
158         if (dm->dap)
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.
161                  */
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, &regdata, NULL, TAP_IDLE);
167         xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
168         return ERROR_OK;
169 }
170
171 int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value)
172 {
173         if (reg >= XDMREG_NUM) {
174                 LOG_ERROR("Invalid DBG reg ID %d!", reg);
175                 return ERROR_FAIL;
176         }
177         if (dm->dap)
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, &regdata, NULL, TAP_IDLE);
183         xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
184         return ERROR_OK;
185 }
186
187 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm,
188         enum xtensa_dm_pwr_reg reg,
189         uint8_t *data,
190         uint32_t clear)
191 {
192         if (reg >= XDMREG_PWRNUM) {
193                 LOG_ERROR("Invalid PWR reg ID %d!", reg);
194                 return ERROR_FAIL;
195         }
196         if (dm->dap) {
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.
199                  */
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);
204                 return retval;
205         }
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);
211         return ERROR_OK;
212 }
213
214 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
215         enum xtensa_dm_pwr_reg reg,
216         uint32_t data)
217 {
218         if (reg >= XDMREG_PWRNUM) {
219                 LOG_ERROR("Invalid PWR reg ID %d!", reg);
220                 return ERROR_FAIL;
221         }
222         if (dm->dap) {
223                 uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset;
224                 return mem_ap_write_u32(dm->debug_ap, apbreg, data);
225         }
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);
231         return ERROR_OK;
232 }
233
234 int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
235 {
236         uint8_t id_buf[sizeof(uint32_t)];
237
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);
241         if (res != ERROR_OK)
242                 return res;
243         dm->device_id = buf_get_u32(id_buf, 0, 32);
244         return ERROR_OK;
245 }
246
247 int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
248 {
249         uint8_t stat_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 };
250         uint8_t stath_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 };
251
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);
255          *Read reset state */
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);
260         if (res != ERROR_OK)
261                 return res;
262         dm->power_status.stat = buf_get_u32(stat_buf, 0, 32);
263         dm->power_status.stath = buf_get_u32(stath_buf, 0, 32);
264         return res;
265 }
266
267 int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
268 {
269         uint8_t dsr_buf[sizeof(uint32_t)];
270
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);
275         if (res != ERROR_OK)
276                 return res;
277         dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
278         return res;
279 }
280
281 int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
282 {
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);
286 }
287
288 int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
289 {
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);
294         if (res != ERROR_OK)
295                 return res;
296
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);
303         }
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(
307                 dm,
308                 XDMREG_TRAXCTRL,
309                 TRAXCTRL_TREN |
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);
314 }
315
316 int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
317 {
318         uint8_t traxctl_buf[sizeof(uint32_t)];
319         uint32_t traxctl;
320         struct xtensa_trace_status trace_status;
321
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);
325         if (res != ERROR_OK)
326                 return res;
327         traxctl = buf_get_u32(traxctl_buf, 0, 32);
328
329         if (!pto_enable)
330                 traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
331
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);
335         if (res != ERROR_OK)
336                 return res;
337
338         /*Check current status of trace hardware */
339         res = xtensa_dm_trace_status_read(dm, &trace_status);
340         if (res != ERROR_OK)
341                 return res;
342
343         if (trace_status.stat & TRAXSTAT_TRACT) {
344                 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
345                 return ERROR_FAIL;
346         }
347         return ERROR_OK;
348 }
349
350 int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
351 {
352         uint8_t traxstat_buf[sizeof(uint32_t)];
353
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);
359         return res;
360 }
361
362 int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
363 {
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)];
368
369         if (!config)
370                 return ERROR_FAIL;
371
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);
383         }
384         return res;
385 }
386
387 int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
388 {
389         if (!dest)
390                 return ERROR_FAIL;
391
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);
396 }
397
398 int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
399         const struct xtensa_perfmon_config *config)
400 {
401         if (!config)
402                 return ERROR_FAIL;
403
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);
409
410         /* enable performance monitor */
411         dm->dbg_ops->queue_reg_write(dm, XDMREG_PMG, 0x1);
412         /* reset counter */
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);
418 }
419
420 int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
421         struct xtensa_perfmon_result *out_result)
422 {
423         uint8_t pmstat_buf[4];
424         uint8_t pmcount_buf[4];
425
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);
433
434                 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
435                 * high 32 bits of the counter. */
436                 if (out_result) {
437                         out_result->overflow = ((stat & 1) != 0);
438                         out_result->value = result;
439                 }
440         }
441
442         return res;
443 }