a7de1ad5c9550a39b130a8f6b7cff0318c8b434e
[openocd.git] / src / target / xtensa / xtensa_debug_module.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4 * Generic Xtensa debug module API for OpenOCD *
5 * Copyright (C) 2019 Espressif Systems Ltd. *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include "xtensa_debug_module.h"
13
14 #define TAPINS_PWRCTL 0x08
15 #define TAPINS_PWRSTAT 0x09
16 #define TAPINS_NARSEL 0x1C
17 #define TAPINS_IDCODE 0x1E
18 #define TAPINS_BYPASS 0x1F
19
20 #define TAPINS_PWRCTL_LEN 8
21 #define TAPINS_PWRSTAT_LEN 8
22 #define TAPINS_NARSEL_ADRLEN 8
23 #define TAPINS_NARSEL_DATALEN 32
24 #define TAPINS_IDCODE_LEN 32
25 #define TAPINS_BYPASS_LEN 1
26
27
28 static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
29 {
30 struct scan_field field;
31 uint8_t t[4] = { 0 };
32
33 memset(&field, 0, sizeof(field));
34 field.num_bits = dm->tap->ir_length;
35 field.out_value = t;
36 buf_set_u32(t, 0, field.num_bits, value);
37 jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
38 }
39
40 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
41 int len,
42 const uint8_t *src,
43 uint8_t *dest,
44 tap_state_t endstate)
45 {
46 struct scan_field field;
47
48 memset(&field, 0, sizeof(field));
49 field.num_bits = len;
50 field.out_value = src;
51 field.in_value = dest;
52 jtag_add_dr_scan(dm->tap, 1, &field, endstate);
53 }
54
55 int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
56 {
57 if (!dm || !cfg)
58 return ERROR_FAIL;
59
60 dm->pwr_ops = cfg->pwr_ops;
61 dm->dbg_ops = cfg->dbg_ops;
62 dm->tap = cfg->tap;
63 dm->queue_tdi_idle = cfg->queue_tdi_idle;
64 dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
65 return ERROR_OK;
66 }
67
68 int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
69 {
70 return dm->dbg_ops->queue_reg_write(dm, NARADR_DCRSET, OCDDCR_ENABLEOCD);
71 }
72
73 int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *value)
74 {
75 uint8_t regdata = (reg << 1) | 0;
76 uint8_t dummy[4] = { 0, 0, 0, 0 };
77
78 if (reg > NARADR_MAX) {
79 LOG_ERROR("Invalid DBG reg ID %d!", reg);
80 return ERROR_FAIL;
81 }
82 xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
83 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, &regdata, NULL, TAP_IDLE);
84 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
85 return ERROR_OK;
86 }
87
88 int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint32_t value)
89 {
90 uint8_t regdata = (reg << 1) | 1;
91 uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
92
93 if (reg > NARADR_MAX) {
94 LOG_ERROR("Invalid DBG reg ID %d!", reg);
95 return ERROR_FAIL;
96 }
97 xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
98 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, &regdata, NULL, TAP_IDLE);
99 xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
100 return ERROR_OK;
101 }
102
103 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data, uint8_t clear)
104 {
105 uint8_t value_clr = clear;
106 uint8_t tap_insn;
107 int tap_insn_sz;
108
109 if (reg == DMREG_PWRCTL) {
110 tap_insn = TAPINS_PWRCTL;
111 tap_insn_sz = TAPINS_PWRCTL_LEN;
112 } else if (reg == DMREG_PWRSTAT) {
113 tap_insn = TAPINS_PWRSTAT;
114 tap_insn_sz = TAPINS_PWRSTAT_LEN;
115 } else {
116 LOG_ERROR("Invalid PWR reg ID %d!", reg);
117 return ERROR_FAIL;
118 }
119 xtensa_dm_add_set_ir(dm, tap_insn);
120 xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE);
121 return ERROR_OK;
122 }
123
124 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data)
125 {
126 uint8_t value = data;
127 uint8_t tap_insn;
128 int tap_insn_sz;
129
130 if (reg == DMREG_PWRCTL) {
131 tap_insn = TAPINS_PWRCTL;
132 tap_insn_sz = TAPINS_PWRCTL_LEN;
133 } else if (reg == DMREG_PWRSTAT) {
134 tap_insn = TAPINS_PWRSTAT;
135 tap_insn_sz = TAPINS_PWRSTAT_LEN;
136 } else {
137 LOG_ERROR("Invalid PWR reg ID %d!", reg);
138 return ERROR_FAIL;
139 }
140 xtensa_dm_add_set_ir(dm, tap_insn);
141 xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE);
142 return ERROR_OK;
143 }
144
145 int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
146 {
147 uint8_t id_buf[sizeof(uint32_t)];
148
149 dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
150 xtensa_dm_queue_tdi_idle(dm);
151 int res = jtag_execute_queue();
152 if (res != ERROR_OK)
153 return res;
154 dm->device_id = buf_get_u32(id_buf, 0, 32);
155 return ERROR_OK;
156 }
157
158 int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
159 {
160 /* uint8_t id_buf[sizeof(uint32_t)]; */
161
162 /* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set.
163 * It is set in xtensa_examine(), need to move reading of NARADR_OCDID out of this function */
164 /* dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
165 *Read reset state */
166 dm->pwr_ops->queue_reg_read(dm, DMREG_PWRSTAT, &dm->power_status.stat, clear);
167 dm->pwr_ops->queue_reg_read(dm, DMREG_PWRSTAT, &dm->power_status.stath, clear);
168 xtensa_dm_queue_tdi_idle(dm);
169 return jtag_execute_queue();
170 }
171
172 int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
173 {
174 uint8_t dsr_buf[sizeof(uint32_t)];
175
176 xtensa_dm_queue_enable(dm);
177 dm->dbg_ops->queue_reg_read(dm, NARADR_DSR, dsr_buf);
178 xtensa_dm_queue_tdi_idle(dm);
179 int res = jtag_execute_queue();
180 if (res != ERROR_OK)
181 return res;
182 dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
183 return res;
184 }
185
186 int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
187 {
188 dm->dbg_ops->queue_reg_write(dm, NARADR_DSR, bits);
189 xtensa_dm_queue_tdi_idle(dm);
190 return jtag_execute_queue();
191 }
192
193 int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
194 {
195 /*Turn off trace unit so we can start a new trace. */
196 dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, 0);
197 xtensa_dm_queue_tdi_idle(dm);
198 int res = jtag_execute_queue();
199 if (res != ERROR_OK)
200 return res;
201
202 /*Set up parameters */
203 dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXADDR, 0);
204 if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) {
205 dm->dbg_ops->queue_reg_write(dm, NARADR_PCMATCHCTRL,
206 (cfg->stopmask << PCMATCHCTRL_PCML_SHIFT));
207 dm->dbg_ops->queue_reg_write(dm, NARADR_TRIGGERPC, cfg->stoppc);
208 }
209 dm->dbg_ops->queue_reg_write(dm, NARADR_DELAYCNT, cfg->after);
210 /*Options are mostly hardcoded for now. ToDo: make this more configurable. */
211 dm->dbg_ops->queue_reg_write(
212 dm,
213 NARADR_TRAXCTRL,
214 TRAXCTRL_TREN |
215 ((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN |
216 (cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS);
217 xtensa_dm_queue_tdi_idle(dm);
218 return jtag_execute_queue();
219 }
220
221 int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
222 {
223 uint8_t traxctl_buf[sizeof(uint32_t)];
224 uint32_t traxctl;
225 struct xtensa_trace_status trace_status;
226
227 dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
228 xtensa_dm_queue_tdi_idle(dm);
229 int res = jtag_execute_queue();
230 if (res != ERROR_OK)
231 return res;
232 traxctl = buf_get_u32(traxctl_buf, 0, 32);
233
234 if (!pto_enable)
235 traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
236
237 dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
238 xtensa_dm_queue_tdi_idle(dm);
239 res = jtag_execute_queue();
240 if (res != ERROR_OK)
241 return res;
242
243 /*Check current status of trace hardware */
244 res = xtensa_dm_trace_status_read(dm, &trace_status);
245 if (res != ERROR_OK)
246 return res;
247
248 if (trace_status.stat & TRAXSTAT_TRACT) {
249 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
250 return ERROR_FAIL;
251 }
252 return ERROR_OK;
253 }
254
255 int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
256 {
257 uint8_t traxstat_buf[sizeof(uint32_t)];
258
259 dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXSTAT, traxstat_buf);
260 xtensa_dm_queue_tdi_idle(dm);
261 int res = jtag_execute_queue();
262 if (res == ERROR_OK && status)
263 status->stat = buf_get_u32(traxstat_buf, 0, 32);
264 return res;
265 }
266
267 int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
268 {
269 uint8_t traxctl_buf[sizeof(uint32_t)];
270 uint8_t memadrstart_buf[sizeof(uint32_t)];
271 uint8_t memadrend_buf[sizeof(uint32_t)];
272 uint8_t adr_buf[sizeof(uint32_t)];
273
274 if (!config)
275 return ERROR_FAIL;
276
277 dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
278 dm->dbg_ops->queue_reg_read(dm, NARADR_MEMADDRSTART, memadrstart_buf);
279 dm->dbg_ops->queue_reg_read(dm, NARADR_MEMADDREND, memadrend_buf);
280 dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXADDR, adr_buf);
281 xtensa_dm_queue_tdi_idle(dm);
282 int res = jtag_execute_queue();
283 if (res == ERROR_OK) {
284 config->ctrl = buf_get_u32(traxctl_buf, 0, 32);
285 config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32);
286 config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32);
287 config->addr = buf_get_u32(adr_buf, 0, 32);
288 }
289 return res;
290 }
291
292 int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
293 {
294 if (!dest)
295 return ERROR_FAIL;
296
297 for (unsigned int i = 0; i < size / 4; i++)
298 dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXDATA, &dest[i * 4]);
299 xtensa_dm_queue_tdi_idle(dm);
300 return jtag_execute_queue();
301 }
302
303 int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
304 const struct xtensa_perfmon_config *config)
305 {
306 if (!config)
307 return ERROR_FAIL;
308
309 uint8_t pmstat_buf[4];
310 uint32_t pmctrl = ((config->tracelevel) << 4) +
311 (config->select << 8) +
312 (config->mask << 16) +
313 (config->kernelcnt << 3);
314
315 /* enable performance monitor */
316 dm->dbg_ops->queue_reg_write(dm, NARADR_PMG, 0x1);
317 /* reset counter */
318 dm->dbg_ops->queue_reg_write(dm, NARADR_PM0 + counter_id, 0);
319 dm->dbg_ops->queue_reg_write(dm, NARADR_PMCTRL0 + counter_id, pmctrl);
320 dm->dbg_ops->queue_reg_read(dm, NARADR_PMSTAT0 + counter_id, pmstat_buf);
321 xtensa_dm_queue_tdi_idle(dm);
322 return jtag_execute_queue();
323 }
324
325 int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
326 struct xtensa_perfmon_result *out_result)
327 {
328 uint8_t pmstat_buf[4];
329 uint8_t pmcount_buf[4];
330
331 dm->dbg_ops->queue_reg_read(dm, NARADR_PMSTAT0 + counter_id, pmstat_buf);
332 dm->dbg_ops->queue_reg_read(dm, NARADR_PM0 + counter_id, pmcount_buf);
333 xtensa_dm_queue_tdi_idle(dm);
334 int res = jtag_execute_queue();
335 if (res == ERROR_OK) {
336 uint32_t stat = buf_get_u32(pmstat_buf, 0, 32);
337 uint64_t result = buf_get_u32(pmcount_buf, 0, 32);
338
339 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
340 * high 32 bits of the counter. */
341 if (out_result) {
342 out_result->overflow = ((stat & 1) != 0);
343 out_result->value = result;
344 }
345 }
346
347 return res;
348 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)