target: add generic Xtensa LX support
[openocd.git] / src / target / espressif / esp32.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4 * ESP32 target API for OpenOCD *
5 * Copyright (C) 2016-2019 Espressif Systems Ltd. *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/time_support.h>
13 #include <target/target.h>
14 #include <target/target_type.h>
15 #include <target/smp.h>
16 #include "assert.h"
17 #include "esp_xtensa_smp.h"
18
19 /*
20 This is a JTAG driver for the ESP32, the are two Tensilica cores inside
21 the ESP32 chip. For more information please have a look into ESP32 target
22 implementation.
23 */
24
25 /* ESP32 memory map */
26 #define ESP32_DRAM_LOW 0x3ffae000
27 #define ESP32_DRAM_HIGH 0x40000000
28 #define ESP32_IROM_MASK_LOW 0x40000000
29 #define ESP32_IROM_MASK_HIGH 0x40064f00
30 #define ESP32_IRAM_LOW 0x40070000
31 #define ESP32_IRAM_HIGH 0x400a0000
32 #define ESP32_RTC_IRAM_LOW 0x400c0000
33 #define ESP32_RTC_IRAM_HIGH 0x400c2000
34 #define ESP32_RTC_DRAM_LOW 0x3ff80000
35 #define ESP32_RTC_DRAM_HIGH 0x3ff82000
36 #define ESP32_RTC_DATA_LOW 0x50000000
37 #define ESP32_RTC_DATA_HIGH 0x50002000
38 #define ESP32_EXTRAM_DATA_LOW 0x3f800000
39 #define ESP32_EXTRAM_DATA_HIGH 0x3fc00000
40 #define ESP32_DR_REG_LOW 0x3ff00000
41 #define ESP32_DR_REG_HIGH 0x3ff71000
42 #define ESP32_SYS_RAM_LOW 0x60000000UL
43 #define ESP32_SYS_RAM_HIGH (ESP32_SYS_RAM_LOW + 0x20000000UL)
44 #define ESP32_RTC_SLOW_MEM_BASE ESP32_RTC_DATA_LOW
45
46 /* ESP32 WDT */
47 #define ESP32_WDT_WKEY_VALUE 0x50d83aa1
48 #define ESP32_TIMG0_BASE 0x3ff5f000
49 #define ESP32_TIMG1_BASE 0x3ff60000
50 #define ESP32_TIMGWDT_CFG0_OFF 0x48
51 #define ESP32_TIMGWDT_PROTECT_OFF 0x64
52 #define ESP32_TIMG0WDT_CFG0 (ESP32_TIMG0_BASE + ESP32_TIMGWDT_CFG0_OFF)
53 #define ESP32_TIMG1WDT_CFG0 (ESP32_TIMG1_BASE + ESP32_TIMGWDT_CFG0_OFF)
54 #define ESP32_TIMG0WDT_PROTECT (ESP32_TIMG0_BASE + ESP32_TIMGWDT_PROTECT_OFF)
55 #define ESP32_TIMG1WDT_PROTECT (ESP32_TIMG1_BASE + ESP32_TIMGWDT_PROTECT_OFF)
56 #define ESP32_RTCCNTL_BASE 0x3ff48000
57 #define ESP32_RTCWDT_CFG_OFF 0x8C
58 #define ESP32_RTCWDT_PROTECT_OFF 0xA4
59 #define ESP32_RTCWDT_CFG (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_CFG_OFF)
60 #define ESP32_RTCWDT_PROTECT (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_PROTECT_OFF)
61
62 #define ESP32_TRACEMEM_BLOCK_SZ 0x4000
63
64 /* ESP32 dport regs */
65 #define ESP32_DR_REG_DPORT_BASE ESP32_DR_REG_LOW
66 #define ESP32_DPORT_APPCPU_CTRL_B_REG (ESP32_DR_REG_DPORT_BASE + 0x030)
67 #define ESP32_DPORT_APPCPU_CLKGATE_EN BIT(0)
68 /* ESP32 RTC regs */
69 #define ESP32_RTC_CNTL_SW_CPU_STALL_REG (ESP32_RTCCNTL_BASE + 0xac)
70 #define ESP32_RTC_CNTL_SW_CPU_STALL_DEF 0x0
71
72 /* 0 - don't care, 1 - TMS low, 2 - TMS high */
73 enum esp32_flash_bootstrap {
74 FBS_DONTCARE = 0,
75 FBS_TMSLOW,
76 FBS_TMSHIGH,
77 };
78
79 struct esp32_common {
80 struct esp_xtensa_smp_common esp_xtensa_smp;
81 enum esp32_flash_bootstrap flash_bootstrap;
82 };
83
84 static inline struct esp32_common *target_to_esp32(struct target *target)
85 {
86 return container_of(target->arch_info, struct esp32_common, esp_xtensa_smp);
87 }
88
89 /* Reset ESP32 peripherals.
90 * Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted,
91 * APP CPU is in reset
92 * How this works:
93 * 0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt
94 * 1. set CPU initial PC to 0x50000000 (ESP32_SMP_RTC_DATA_LOW) by clearing RTC_CNTL_{PRO,APP}CPU_STAT_VECTOR_SEL
95 * 2. load stub code into ESP32_SMP_RTC_DATA_LOW; once executed, stub code will disable watchdogs and
96 * make CPU spin in an idle loop.
97 * 3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit
98 * 4. wait for the OCD to be reset
99 * 5. halt the target and wait for it to be halted (at this point CPU is in the idle loop)
100 * 6. restore initial PC and the contents of ESP32_SMP_RTC_DATA_LOW
101 * TODO: some state of RTC_CNTL is not reset during SW_SYS_RST. Need to reset that manually. */
102
103 const uint8_t esp32_reset_stub_code[] = {
104 #include "../../../contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc"
105 };
106
107 static int esp32_soc_reset(struct target *target)
108 {
109 int res;
110 struct target_list *head;
111 struct xtensa *xtensa;
112
113 LOG_DEBUG("start");
114 /* In order to write to peripheral registers, target must be halted first */
115 if (target->state != TARGET_HALTED) {
116 LOG_DEBUG("Target not halted before SoC reset, trying to halt it first");
117 xtensa_halt(target);
118 res = target_wait_state(target, TARGET_HALTED, 1000);
119 if (res != ERROR_OK) {
120 LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt");
121 res = xtensa_assert_reset(target);
122 if (res != ERROR_OK) {
123 LOG_ERROR(
124 "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)",
125 res);
126 return res;
127 }
128 alive_sleep(10);
129 xtensa_poll(target);
130 bool reset_halt_save = target->reset_halt;
131 target->reset_halt = true;
132 res = xtensa_deassert_reset(target);
133 target->reset_halt = reset_halt_save;
134 if (res != ERROR_OK) {
135 LOG_ERROR(
136 "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)",
137 res);
138 return res;
139 }
140 alive_sleep(10);
141 xtensa_poll(target);
142 xtensa_halt(target);
143 res = target_wait_state(target, TARGET_HALTED, 1000);
144 if (res != ERROR_OK) {
145 LOG_ERROR("Couldn't halt target before SoC reset");
146 return res;
147 }
148 }
149 }
150
151 if (target->smp) {
152 foreach_smp_target(head, target->smp_targets) {
153 xtensa = target_to_xtensa(head->target);
154 /* if any of the cores is stalled unstall them */
155 if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) {
156 LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!");
157 res = target_write_u32(target,
158 ESP32_RTC_CNTL_SW_CPU_STALL_REG,
159 ESP32_RTC_CNTL_SW_CPU_STALL_DEF);
160 if (res != ERROR_OK) {
161 LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!");
162 return res;
163 }
164 break; /* both cores are unstalled now, so exit the loop */
165 }
166 }
167 }
168
169 LOG_DEBUG("Loading stub code into RTC RAM");
170 uint8_t slow_mem_save[sizeof(esp32_reset_stub_code)];
171
172 /* Save contents of RTC_SLOW_MEM which we are about to overwrite */
173 res = target_read_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save);
174 if (res != ERROR_OK) {
175 LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res);
176 return res;
177 }
178
179 /* Write stub code into RTC_SLOW_MEM */
180 res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(esp32_reset_stub_code), esp32_reset_stub_code);
181 if (res != ERROR_OK) {
182 LOG_ERROR("Failed to write stub (%d)!", res);
183 return res;
184 }
185
186 LOG_DEBUG("Resuming the target");
187 xtensa = target_to_xtensa(target);
188 xtensa->suppress_dsr_errors = true;
189 res = xtensa_resume(target, 0, ESP32_RTC_SLOW_MEM_BASE + 4, 0, 0);
190 xtensa->suppress_dsr_errors = false;
191 if (res != ERROR_OK) {
192 LOG_ERROR("Failed to run stub (%d)!", res);
193 return res;
194 }
195 LOG_DEBUG("resume done, waiting for the target to come alive");
196
197 /* Wait for SoC to reset */
198 alive_sleep(100);
199 int64_t timeout = timeval_ms() + 100;
200 bool get_timeout = false;
201 while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) {
202 alive_sleep(10);
203 xtensa_poll(target);
204 if (timeval_ms() >= timeout) {
205 LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d",
206 target->state);
207 get_timeout = true;
208 break;
209 }
210 }
211
212 /* Halt the CPU again */
213 LOG_DEBUG("halting the target");
214 xtensa_halt(target);
215 res = target_wait_state(target, TARGET_HALTED, 1000);
216 if (res == ERROR_OK) {
217 LOG_DEBUG("restoring RTC_SLOW_MEM");
218 res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save);
219 if (res != ERROR_OK)
220 LOG_TARGET_ERROR(target, "Failed to restore contents of RTC_SLOW_MEM (%d)!", res);
221 } else {
222 LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be halted after SoC reset");
223 }
224
225 return get_timeout ? ERROR_TARGET_TIMEOUT : res;
226 }
227
228 static int esp32_disable_wdts(struct target *target)
229 {
230 /* TIMG1 WDT */
231 int res = target_write_u32(target, ESP32_TIMG0WDT_PROTECT, ESP32_WDT_WKEY_VALUE);
232 if (res != ERROR_OK) {
233 LOG_ERROR("Failed to write ESP32_TIMG0WDT_PROTECT (%d)!", res);
234 return res;
235 }
236 res = target_write_u32(target, ESP32_TIMG0WDT_CFG0, 0);
237 if (res != ERROR_OK) {
238 LOG_ERROR("Failed to write ESP32_TIMG0WDT_CFG0 (%d)!", res);
239 return res;
240 }
241 /* TIMG2 WDT */
242 res = target_write_u32(target, ESP32_TIMG1WDT_PROTECT, ESP32_WDT_WKEY_VALUE);
243 if (res != ERROR_OK) {
244 LOG_ERROR("Failed to write ESP32_TIMG1WDT_PROTECT (%d)!", res);
245 return res;
246 }
247 res = target_write_u32(target, ESP32_TIMG1WDT_CFG0, 0);
248 if (res != ERROR_OK) {
249 LOG_ERROR("Failed to write ESP32_TIMG1WDT_CFG0 (%d)!", res);
250 return res;
251 }
252 /* RTC WDT */
253 res = target_write_u32(target, ESP32_RTCWDT_PROTECT, ESP32_WDT_WKEY_VALUE);
254 if (res != ERROR_OK) {
255 LOG_ERROR("Failed to write ESP32_RTCWDT_PROTECT (%d)!", res);
256 return res;
257 }
258 res = target_write_u32(target, ESP32_RTCWDT_CFG, 0);
259 if (res != ERROR_OK) {
260 LOG_ERROR("Failed to write ESP32_RTCWDT_CFG (%d)!", res);
261 return res;
262 }
263 return ERROR_OK;
264 }
265
266 static int esp32_on_halt(struct target *target)
267 {
268 return esp32_disable_wdts(target);
269 }
270
271 static int esp32_arch_state(struct target *target)
272 {
273 return ERROR_OK;
274 }
275
276 static int esp32_virt2phys(struct target *target,
277 target_addr_t virtual, target_addr_t *physical)
278 {
279 if (physical) {
280 *physical = virtual;
281 return ERROR_OK;
282 }
283 return ERROR_FAIL;
284 }
285
286 /* The TDI pin is also used as a flash Vcc bootstrap pin. If we reset the CPU externally, the last state of the TDI pin
287 * can allow the power to an 1.8V flash chip to be raised to 3.3V, or the other way around. Users can use the
288 * esp32 flashbootstrap command to set a level, and this routine will make sure the tdi line will return to
289 * that when the jtag port is idle. */
290
291 static void esp32_queue_tdi_idle(struct target *target)
292 {
293 struct esp32_common *esp32 = target_to_esp32(target);
294 static uint32_t value;
295 uint8_t t[4] = { 0, 0, 0, 0 };
296
297 if (esp32->flash_bootstrap == FBS_TMSLOW)
298 /* Make sure tdi is 0 at the exit of queue execution */
299 value = 0;
300 else if (esp32->flash_bootstrap == FBS_TMSHIGH)
301 /* Make sure tdi is 1 at the exit of queue execution */
302 value = 1;
303 else
304 return;
305
306 /* Scan out 1 bit, do not move from IRPAUSE after we're done. */
307 buf_set_u32(t, 0, 1, value);
308 jtag_add_plain_ir_scan(1, t, NULL, TAP_IRPAUSE);
309 }
310
311 static int esp32_target_init(struct command_context *cmd_ctx, struct target *target)
312 {
313 return esp_xtensa_smp_target_init(cmd_ctx, target);
314 }
315
316 static const struct xtensa_debug_ops esp32_dbg_ops = {
317 .queue_enable = xtensa_dm_queue_enable,
318 .queue_reg_read = xtensa_dm_queue_reg_read,
319 .queue_reg_write = xtensa_dm_queue_reg_write
320 };
321
322 static const struct xtensa_power_ops esp32_pwr_ops = {
323 .queue_reg_read = xtensa_dm_queue_pwr_reg_read,
324 .queue_reg_write = xtensa_dm_queue_pwr_reg_write
325 };
326
327 static const struct esp_xtensa_smp_chip_ops esp32_chip_ops = {
328 .reset = esp32_soc_reset,
329 .on_halt = esp32_on_halt
330 };
331
332 static int esp32_target_create(struct target *target, Jim_Interp *interp)
333 {
334 struct xtensa_debug_module_config esp32_dm_cfg = {
335 .dbg_ops = &esp32_dbg_ops,
336 .pwr_ops = &esp32_pwr_ops,
337 .tap = target->tap,
338 .queue_tdi_idle = esp32_queue_tdi_idle,
339 .queue_tdi_idle_arg = target
340 };
341
342 struct esp32_common *esp32 = calloc(1, sizeof(struct esp32_common));
343 if (!esp32) {
344 LOG_ERROR("Failed to alloc memory for arch info!");
345 return ERROR_FAIL;
346 }
347
348 int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp,
349 &esp32_dm_cfg, &esp32_chip_ops);
350 if (ret != ERROR_OK) {
351 LOG_ERROR("Failed to init arch info!");
352 free(esp32);
353 return ret;
354 }
355 esp32->flash_bootstrap = FBS_DONTCARE;
356
357 /* Assume running target. If different, the first poll will fix this. */
358 target->state = TARGET_RUNNING;
359 target->debug_reason = DBG_REASON_NOTHALTED;
360 return ERROR_OK;
361 }
362
363 COMMAND_HELPER(esp32_cmd_flashbootstrap_do, struct esp32_common *esp32)
364 {
365 int state = -1;
366
367 if (CMD_ARGC < 1) {
368 const char *st;
369 state = esp32->flash_bootstrap;
370 if (state == FBS_DONTCARE)
371 st = "Don't care";
372 else if (state == FBS_TMSLOW)
373 st = "Low (3.3V)";
374 else if (state == FBS_TMSHIGH)
375 st = "High (1.8V)";
376 else
377 st = "None";
378 command_print(CMD, "Current idle tms state: %s", st);
379 return ERROR_OK;
380 }
381
382 if (!strcasecmp(CMD_ARGV[0], "none"))
383 state = FBS_DONTCARE;
384 else if (!strcasecmp(CMD_ARGV[0], "1.8"))
385 state = FBS_TMSHIGH;
386 else if (!strcasecmp(CMD_ARGV[0], "3.3"))
387 state = FBS_TMSLOW;
388 else if (!strcasecmp(CMD_ARGV[0], "high"))
389 state = FBS_TMSHIGH;
390 else if (!strcasecmp(CMD_ARGV[0], "low"))
391 state = FBS_TMSLOW;
392
393 if (state == -1) {
394 command_print(CMD,
395 "Argument unknown. Please pick one of none, high, low, 1.8 or 3.3");
396 return ERROR_FAIL;
397 }
398 esp32->flash_bootstrap = state;
399 return ERROR_OK;
400 }
401
402 COMMAND_HANDLER(esp32_cmd_flashbootstrap)
403 {
404 struct target *target = get_current_target(CMD_CTX);
405
406 if (target->smp) {
407 struct target_list *head;
408 struct target *curr;
409 foreach_smp_target(head, target->smp_targets) {
410 curr = head->target;
411 int ret = CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do,
412 target_to_esp32(curr));
413 if (ret != ERROR_OK)
414 return ret;
415 }
416 return ERROR_OK;
417 }
418 return CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do,
419 target_to_esp32(target));
420 }
421
422 static const struct command_registration esp32_any_command_handlers[] = {
423 {
424 .name = "flashbootstrap",
425 .handler = esp32_cmd_flashbootstrap,
426 .mode = COMMAND_ANY,
427 .help =
428 "Set the idle state of the TMS pin, which at reset also is the voltage selector for the flash chip.",
429 .usage = "none|1.8|3.3|high|low",
430 },
431 COMMAND_REGISTRATION_DONE
432 };
433
434 static const struct command_registration esp32_command_handlers[] = {
435 {
436 .chain = esp_xtensa_smp_command_handlers,
437 },
438 {
439 .name = "esp32",
440 .usage = "",
441 .chain = smp_command_handlers,
442 },
443 {
444 .name = "esp32",
445 .usage = "",
446 .chain = esp32_any_command_handlers,
447 },
448 COMMAND_REGISTRATION_DONE
449 };
450
451 /** Holds methods for Xtensa targets. */
452 struct target_type esp32_target = {
453 .name = "esp32",
454
455 .poll = esp_xtensa_smp_poll,
456 .arch_state = esp32_arch_state,
457
458 .halt = xtensa_halt,
459 .resume = esp_xtensa_smp_resume,
460 .step = esp_xtensa_smp_step,
461
462 .assert_reset = esp_xtensa_smp_assert_reset,
463 .deassert_reset = esp_xtensa_smp_deassert_reset,
464 .soft_reset_halt = esp_xtensa_smp_soft_reset_halt,
465
466 .virt2phys = esp32_virt2phys,
467 .mmu = xtensa_mmu_is_enabled,
468 .read_memory = xtensa_read_memory,
469 .write_memory = xtensa_write_memory,
470
471 .read_buffer = xtensa_read_buffer,
472 .write_buffer = xtensa_write_buffer,
473
474 .checksum_memory = xtensa_checksum_memory,
475
476 .get_gdb_arch = xtensa_get_gdb_arch,
477 .get_gdb_reg_list = xtensa_get_gdb_reg_list,
478
479 .add_breakpoint = esp_xtensa_breakpoint_add,
480 .remove_breakpoint = esp_xtensa_breakpoint_remove,
481
482 .add_watchpoint = esp_xtensa_smp_watchpoint_add,
483 .remove_watchpoint = esp_xtensa_smp_watchpoint_remove,
484
485 .target_create = esp32_target_create,
486 .init_target = esp32_target_init,
487 .examine = xtensa_examine,
488 .deinit_target = esp_xtensa_target_deinit,
489
490 .commands = esp32_command_handlers,
491 };

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)