1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Generic Xtensa debug module API for OpenOCD *
5 * Copyright (C) 2019 Espressif Systems Ltd. *
6 ***************************************************************************/
12 #include "xtensa_debug_module.h"
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
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
28 static void xtensa_dm_add_set_ir(struct xtensa_debug_module
*dm
, uint8_t value
)
30 struct scan_field field
;
33 memset(&field
, 0, sizeof(field
));
34 field
.num_bits
= dm
->tap
->ir_length
;
36 buf_set_u32(t
, 0, field
.num_bits
, value
);
37 jtag_add_ir_scan(dm
->tap
, &field
, TAP_IDLE
);
40 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module
*dm
,
46 struct scan_field field
;
48 memset(&field
, 0, sizeof(field
));
50 field
.out_value
= src
;
51 field
.in_value
= dest
;
52 jtag_add_dr_scan(dm
->tap
, 1, &field
, endstate
);
55 int xtensa_dm_init(struct xtensa_debug_module
*dm
, const struct xtensa_debug_module_config
*cfg
)
60 dm
->pwr_ops
= cfg
->pwr_ops
;
61 dm
->dbg_ops
= cfg
->dbg_ops
;
63 dm
->queue_tdi_idle
= cfg
->queue_tdi_idle
;
64 dm
->queue_tdi_idle_arg
= cfg
->queue_tdi_idle_arg
;
68 int xtensa_dm_queue_enable(struct xtensa_debug_module
*dm
)
70 return dm
->dbg_ops
->queue_reg_write(dm
, NARADR_DCRSET
, OCDDCR_ENABLEOCD
);
73 int xtensa_dm_queue_reg_read(struct xtensa_debug_module
*dm
, unsigned int reg
, uint8_t *value
)
75 uint8_t regdata
= (reg
<< 1) | 0;
76 uint8_t dummy
[4] = { 0, 0, 0, 0 };
78 if (reg
> NARADR_MAX
) {
79 LOG_ERROR("Invalid DBG reg ID %d!", reg
);
82 xtensa_dm_add_set_ir(dm
, TAPINS_NARSEL
);
83 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_ADRLEN
, ®data
, NULL
, TAP_IDLE
);
84 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_DATALEN
, dummy
, value
, TAP_IDLE
);
88 int xtensa_dm_queue_reg_write(struct xtensa_debug_module
*dm
, unsigned int reg
, uint32_t value
)
90 uint8_t regdata
= (reg
<< 1) | 1;
91 uint8_t valdata
[] = { value
, value
>> 8, value
>> 16, value
>> 24 };
93 if (reg
> NARADR_MAX
) {
94 LOG_ERROR("Invalid DBG reg ID %d!", reg
);
97 xtensa_dm_add_set_ir(dm
, TAPINS_NARSEL
);
98 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_ADRLEN
, ®data
, NULL
, TAP_IDLE
);
99 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_DATALEN
, valdata
, NULL
, TAP_IDLE
);
103 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module
*dm
, unsigned int reg
, uint8_t *data
, uint8_t clear
)
105 uint8_t value_clr
= clear
;
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
;
116 LOG_ERROR("Invalid PWR reg ID %d!", reg
);
119 xtensa_dm_add_set_ir(dm
, tap_insn
);
120 xtensa_dm_add_dr_scan(dm
, tap_insn_sz
, &value_clr
, data
, TAP_IDLE
);
124 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module
*dm
, unsigned int reg
, uint8_t data
)
126 uint8_t value
= data
;
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
;
137 LOG_ERROR("Invalid PWR reg ID %d!", reg
);
140 xtensa_dm_add_set_ir(dm
, tap_insn
);
141 xtensa_dm_add_dr_scan(dm
, tap_insn_sz
, &value
, NULL
, TAP_IDLE
);
145 int xtensa_dm_device_id_read(struct xtensa_debug_module
*dm
)
147 uint8_t id_buf
[sizeof(uint32_t)];
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();
154 dm
->device_id
= buf_get_u32(id_buf
, 0, 32);
158 int xtensa_dm_power_status_read(struct xtensa_debug_module
*dm
, uint32_t clear
)
160 /* uint8_t id_buf[sizeof(uint32_t)]; */
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);
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();
172 int xtensa_dm_core_status_read(struct xtensa_debug_module
*dm
)
174 uint8_t dsr_buf
[sizeof(uint32_t)];
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();
182 dm
->core_status
.dsr
= buf_get_u32(dsr_buf
, 0, 32);
186 int xtensa_dm_core_status_clear(struct xtensa_debug_module
*dm
, xtensa_dsr_t bits
)
188 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_DSR
, bits
);
189 xtensa_dm_queue_tdi_idle(dm
);
190 return jtag_execute_queue();
193 int xtensa_dm_trace_start(struct xtensa_debug_module
*dm
, struct xtensa_trace_start_config
*cfg
)
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();
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
);
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(
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();
221 int xtensa_dm_trace_stop(struct xtensa_debug_module
*dm
, bool pto_enable
)
223 uint8_t traxctl_buf
[sizeof(uint32_t)];
225 struct xtensa_trace_status trace_status
;
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();
232 traxctl
= buf_get_u32(traxctl_buf
, 0, 32);
235 traxctl
&= ~(TRAXCTRL_PTOWS
| TRAXCTRL_PTOWT
);
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();
243 /*Check current status of trace hardware */
244 res
= xtensa_dm_trace_status_read(dm
, &trace_status
);
248 if (trace_status
.stat
& TRAXSTAT_TRACT
) {
249 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status
.stat
);
255 int xtensa_dm_trace_status_read(struct xtensa_debug_module
*dm
, struct xtensa_trace_status
*status
)
257 uint8_t traxstat_buf
[sizeof(uint32_t)];
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);
267 int xtensa_dm_trace_config_read(struct xtensa_debug_module
*dm
, struct xtensa_trace_config
*config
)
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)];
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);
292 int xtensa_dm_trace_data_read(struct xtensa_debug_module
*dm
, uint8_t *dest
, uint32_t size
)
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();
303 int xtensa_dm_perfmon_enable(struct xtensa_debug_module
*dm
, int counter_id
,
304 const struct xtensa_perfmon_config
*config
)
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);
315 /* enable performance monitor */
316 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_PMG
, 0x1);
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();
325 int xtensa_dm_perfmon_dump(struct xtensa_debug_module
*dm
, int counter_id
,
326 struct xtensa_perfmon_result
*out_result
)
328 uint8_t pmstat_buf
[4];
329 uint8_t pmcount_buf
[4];
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);
339 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
340 * high 32 bits of the counter. */
342 out_result
->overflow
= ((stat
& 1) != 0);
343 out_result
->value
= result
;
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)