target: add Espressif ESP32-S2 basic support
[fw/openocd] / 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 }