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

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)