target/esp_xtensa: add xtensa on_halt handler
[openocd.git] / src / target / espressif / esp32s3.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * ESP32-S3 target API for OpenOCD *
5 * Copyright (C) 2020 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 <target/semihosting_common.h>
17 #include "assert.h"
18 #include "esp_xtensa_smp.h"
19
20 /*
21 This is a JTAG driver for the ESP32_S3, the are two Tensilica cores inside
22 the ESP32_S3 chip. For more information please have a look into ESP32_S3 target
23 implementation.
24 */
25
26 /* ESP32_S3 memory map */
27 #define ESP32_S3_IRAM_LOW 0x40370000
28 #define ESP32_S3_IRAM_HIGH 0x403E0000
29 #define ESP32_S3_IROM_MASK_LOW 0x40000000
30 #define ESP32_S3_IROM_MASK_HIGH 0x40060000
31 #define ESP32_S3_DRAM_LOW 0x3FC88000
32 #define ESP32_S3_DRAM_HIGH 0x3FD00000
33 #define ESP32_S3_RTC_IRAM_LOW 0x600FE000
34 #define ESP32_S3_RTC_IRAM_HIGH 0x60100000
35 #define ESP32_S3_RTC_DRAM_LOW 0x600FE000
36 #define ESP32_S3_RTC_DRAM_HIGH 0x60100000
37 #define ESP32_S3_RTC_DATA_LOW 0x50000000
38 #define ESP32_S3_RTC_DATA_HIGH 0x50002000
39 #define ESP32_S3_EXTRAM_DATA_LOW 0x3D000000
40 #define ESP32_S3_EXTRAM_DATA_HIGH 0x3E000000
41 #define ESP32_S3_SYS_RAM_LOW 0x60000000UL
42 #define ESP32_S3_SYS_RAM_HIGH (ESP32_S3_SYS_RAM_LOW + 0x10000000UL)
43 #define ESP32_S3_RTC_SLOW_MEM_BASE ESP32_S3_RTC_DATA_LOW
44
45 /* ESP32_S3 WDT */
46 #define ESP32_S3_WDT_WKEY_VALUE 0x50D83AA1
47 #define ESP32_S3_TIMG0_BASE 0x6001F000
48 #define ESP32_S3_TIMG1_BASE 0x60020000
49 #define ESP32_S3_TIMGWDT_CFG0_OFF 0x48
50 #define ESP32_S3_TIMGWDT_PROTECT_OFF 0x64
51 #define ESP32_S3_TIMG0WDT_CFG0 (ESP32_S3_TIMG0_BASE + ESP32_S3_TIMGWDT_CFG0_OFF)
52 #define ESP32_S3_TIMG1WDT_CFG0 (ESP32_S3_TIMG1_BASE + ESP32_S3_TIMGWDT_CFG0_OFF)
53 #define ESP32_S3_TIMG0WDT_PROTECT (ESP32_S3_TIMG0_BASE + ESP32_S3_TIMGWDT_PROTECT_OFF)
54 #define ESP32_S3_TIMG1WDT_PROTECT (ESP32_S3_TIMG1_BASE + ESP32_S3_TIMGWDT_PROTECT_OFF)
55 #define ESP32_S3_RTCCNTL_BASE 0x60008000
56 #define ESP32_S3_RTCWDT_CFG_OFF 0x98
57 #define ESP32_S3_RTCWDT_PROTECT_OFF 0xB0
58 #define ESP32_S3_SWD_CONF_OFF 0xB0
59 #define ESP32_S3_SWD_WPROTECT_OFF 0xB4
60 #define ESP32_S3_RTCWDT_CFG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_RTCWDT_CFG_OFF)
61 #define ESP32_S3_RTCWDT_PROTECT (ESP32_S3_RTCCNTL_BASE + ESP32_S3_RTCWDT_PROTECT_OFF)
62 #define ESP32_S3_SWD_CONF_REG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_SWD_CONF_OFF)
63 #define ESP32_S3_SWD_WPROTECT_REG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_SWD_WPROTECT_OFF)
64 #define ESP32_S3_SWD_AUTO_FEED_EN_M BIT(31)
65 #define ESP32_S3_SWD_WKEY_VALUE 0x8F1D312AU
66
67 #define ESP32_S3_TRACEMEM_BLOCK_SZ 0x4000
68
69 /* ESP32_S3 dport regs */
70 #define ESP32_S3_DR_REG_SYSTEM_BASE 0x600c0000
71 #define ESP32_S3_SYSTEM_CORE_1_CONTROL_0_REG (ESP32_S3_DR_REG_SYSTEM_BASE + 0x014)
72 #define ESP32_S3_SYSTEM_CONTROL_CORE_1_CLKGATE_EN BIT(1)
73
74 /* ESP32_S3 RTC regs */
75 #define ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG (ESP32_S3_RTCCNTL_BASE + 0xBC)
76 #define ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF 0x0
77
78 struct esp32s3_common {
79 struct esp_xtensa_smp_common esp_xtensa_smp;
80 };
81
82 /* Reset ESP32-S3's peripherals.
83 * 1. OpenOCD makes sure the target is halted; if not, tries to halt it.
84 * If that fails, tries to reset it (via OCD) and then halt.
85 * 2. OpenOCD loads the stub code into RTC_SLOW_MEM.
86 * 3. Executes the stub code from address 0x50000004.
87 * 4. The stub code changes the reset vector to 0x50000000, and triggers
88 * a system reset using RTC_CNTL_SW_SYS_RST bit.
89 * 5. Once the PRO CPU is out of reset, it executes the stub code from address 0x50000000.
90 * The stub code disables the watchdog, re-enables JTAG and the APP CPU,
91 * restores the reset vector, and enters an infinite loop.
92 * 6. OpenOCD waits until it can talk to the OCD module again, then halts the target.
93 * 7. OpenOCD restores the contents of RTC_SLOW_MEM.
94 *
95 * End result: all the peripherals except RTC_CNTL are reset, CPU's PC is undefined,
96 * PRO CPU is halted, APP CPU is in reset.
97 */
98
99 static const uint8_t esp32s3_reset_stub_code[] = {
100 #include "../../../contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc"
101 };
102
103 static int esp32s3_soc_reset(struct target *target)
104 {
105 int res;
106 struct target_list *head;
107 struct xtensa *xtensa;
108
109 LOG_DEBUG("start");
110 /* In order to write to peripheral registers, target must be halted first */
111 if (target->state != TARGET_HALTED) {
112 LOG_DEBUG("Target not halted before SoC reset, trying to halt it first");
113 xtensa_halt(target);
114 res = target_wait_state(target, TARGET_HALTED, 1000);
115 if (res != ERROR_OK) {
116 LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt");
117 res = xtensa_assert_reset(target);
118 if (res != ERROR_OK) {
119 LOG_ERROR(
120 "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)",
121 res);
122 return res;
123 }
124 alive_sleep(10);
125 xtensa_poll(target);
126 bool reset_halt_save = target->reset_halt;
127 target->reset_halt = true;
128 res = xtensa_deassert_reset(target);
129 target->reset_halt = reset_halt_save;
130 if (res != ERROR_OK) {
131 LOG_ERROR(
132 "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)",
133 res);
134 return res;
135 }
136 alive_sleep(10);
137 xtensa_poll(target);
138 xtensa_halt(target);
139 res = target_wait_state(target, TARGET_HALTED, 1000);
140 if (res != ERROR_OK) {
141 LOG_ERROR("Couldn't halt target before SoC reset");
142 return res;
143 }
144 }
145 }
146
147 if (target->smp) {
148 foreach_smp_target(head, target->smp_targets) {
149 xtensa = target_to_xtensa(head->target);
150 /* if any of the cores is stalled unstall them */
151 if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) {
152 LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!");
153 res = target_write_u32(target,
154 ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG,
155 ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF);
156 if (res != ERROR_OK) {
157 LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!");
158 return res;
159 }
160 break; /* both cores are unstalled now, so exit the loop */
161 }
162 }
163 }
164
165 LOG_DEBUG("Loading stub code into RTC RAM");
166 uint8_t slow_mem_save[sizeof(esp32s3_reset_stub_code)];
167
168 /* Save contents of RTC_SLOW_MEM which we are about to overwrite */
169 res = target_read_buffer(target, ESP32_S3_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save);
170 if (res != ERROR_OK) {
171 LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res);
172 return res;
173 }
174
175 /* Write stub code into RTC_SLOW_MEM */
176 res = target_write_buffer(target,
177 ESP32_S3_RTC_SLOW_MEM_BASE,
178 sizeof(esp32s3_reset_stub_code),
179 esp32s3_reset_stub_code);
180 if (res != ERROR_OK) {
181 LOG_ERROR("Failed to write stub (%d)!", res);
182 return res;
183 }
184
185 LOG_DEBUG("Resuming the target");
186 xtensa = target_to_xtensa(target);
187 xtensa->suppress_dsr_errors = true;
188 res = xtensa_resume(target, 0, ESP32_S3_RTC_SLOW_MEM_BASE + 4, 0, 0);
189 xtensa->suppress_dsr_errors = false;
190 if (res != ERROR_OK) {
191 LOG_ERROR("Failed to run stub (%d)!", res);
192 return res;
193 }
194 LOG_DEBUG("resume done, waiting for the target to come alive");
195
196 /* Wait for SoC to reset */
197 alive_sleep(100);
198 int64_t timeout = timeval_ms() + 100;
199 bool get_timeout = false;
200 while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) {
201 alive_sleep(10);
202 xtensa_poll(target);
203 if (timeval_ms() >= timeout) {
204 LOG_TARGET_ERROR(target,
205 "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_S3_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 esp32s3_disable_wdts(struct target *target)
229 {
230 /* TIMG1 WDT */
231 int res = target_write_u32(target, ESP32_S3_TIMG0WDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE);
232 if (res != ERROR_OK) {
233 LOG_ERROR("Failed to write ESP32_S3_TIMG0WDT_PROTECT (%d)!", res);
234 return res;
235 }
236 res = target_write_u32(target, ESP32_S3_TIMG0WDT_CFG0, 0);
237 if (res != ERROR_OK) {
238 LOG_ERROR("Failed to write ESP32_S3_TIMG0WDT_CFG0 (%d)!", res);
239 return res;
240 }
241 /* TIMG2 WDT */
242 res = target_write_u32(target, ESP32_S3_TIMG1WDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE);
243 if (res != ERROR_OK) {
244 LOG_ERROR("Failed to write ESP32_S3_TIMG1WDT_PROTECT (%d)!", res);
245 return res;
246 }
247 res = target_write_u32(target, ESP32_S3_TIMG1WDT_CFG0, 0);
248 if (res != ERROR_OK) {
249 LOG_ERROR("Failed to write ESP32_S3_TIMG1WDT_CFG0 (%d)!", res);
250 return res;
251 }
252 /* RTC WDT */
253 res = target_write_u32(target, ESP32_S3_RTCWDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE);
254 if (res != ERROR_OK) {
255 LOG_ERROR("Failed to write ESP32_S3_RTCWDT_PROTECT (%d)!", res);
256 return res;
257 }
258 res = target_write_u32(target, ESP32_S3_RTCWDT_CFG, 0);
259 if (res != ERROR_OK) {
260 LOG_ERROR("Failed to write ESP32_S3_RTCWDT_CFG (%d)!", res);
261 return res;
262 }
263 /* Enable SWD auto-feed */
264 res = target_write_u32(target, ESP32_S3_SWD_WPROTECT_REG, ESP32_S3_SWD_WKEY_VALUE);
265 if (res != ERROR_OK) {
266 LOG_ERROR("Failed to write ESP32_S3_SWD_WPROTECT_REG (%d)!", res);
267 return res;
268 }
269 uint32_t swd_conf_reg = 0;
270 res = target_read_u32(target, ESP32_S3_SWD_CONF_REG, &swd_conf_reg);
271 if (res != ERROR_OK) {
272 LOG_ERROR("Failed to read ESP32_S3_SWD_CONF_REG (%d)!", res);
273 return res;
274 }
275 swd_conf_reg |= ESP32_S3_SWD_AUTO_FEED_EN_M;
276 res = target_write_u32(target, ESP32_S3_SWD_CONF_REG, swd_conf_reg);
277 if (res != ERROR_OK) {
278 LOG_ERROR("Failed to write ESP32_S3_SWD_CONF_REG (%d)!", res);
279 return res;
280 }
281 return ERROR_OK;
282 }
283
284 static int esp32s3_on_halt(struct target *target)
285 {
286 int ret = esp32s3_disable_wdts(target);
287 if (ret == ERROR_OK)
288 ret = esp_xtensa_smp_on_halt(target);
289 return ret;
290 }
291
292 static int esp32s3_arch_state(struct target *target)
293 {
294 return ERROR_OK;
295 }
296
297 static int esp32s3_virt2phys(struct target *target,
298 target_addr_t virtual, target_addr_t *physical)
299 {
300 if (physical) {
301 *physical = virtual;
302 return ERROR_OK;
303 }
304 return ERROR_FAIL;
305 }
306
307 static int esp32s3_target_init(struct command_context *cmd_ctx, struct target *target)
308 {
309 return esp_xtensa_smp_target_init(cmd_ctx, target);
310 }
311
312 static const struct xtensa_debug_ops esp32s3_dbg_ops = {
313 .queue_enable = xtensa_dm_queue_enable,
314 .queue_reg_read = xtensa_dm_queue_reg_read,
315 .queue_reg_write = xtensa_dm_queue_reg_write
316 };
317
318 static const struct xtensa_power_ops esp32s3_pwr_ops = {
319 .queue_reg_read = xtensa_dm_queue_pwr_reg_read,
320 .queue_reg_write = xtensa_dm_queue_pwr_reg_write
321 };
322
323 static const struct esp_xtensa_smp_chip_ops esp32s3_chip_ops = {
324 .reset = esp32s3_soc_reset,
325 .on_halt = esp32s3_on_halt
326 };
327
328 static const struct esp_semihost_ops esp32s3_semihost_ops = {
329 .prepare = esp32s3_disable_wdts
330 };
331
332 static int esp32s3_target_create(struct target *target, Jim_Interp *interp)
333 {
334 struct xtensa_debug_module_config esp32s3_dm_cfg = {
335 .dbg_ops = &esp32s3_dbg_ops,
336 .pwr_ops = &esp32s3_pwr_ops,
337 .tap = target->tap,
338 .queue_tdi_idle = NULL,
339 .queue_tdi_idle_arg = NULL
340 };
341
342 struct esp32s3_common *esp32s3 = calloc(1, sizeof(struct esp32s3_common));
343 if (!esp32s3) {
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,
349 &esp32s3->esp_xtensa_smp,
350 &esp32s3_dm_cfg,
351 &esp32s3_chip_ops,
352 &esp32s3_semihost_ops);
353 if (ret != ERROR_OK) {
354 LOG_ERROR("Failed to init arch info!");
355 free(esp32s3);
356 return ret;
357 }
358
359 /* Assume running target. If different, the first poll will fix this. */
360 target->state = TARGET_RUNNING;
361 target->debug_reason = DBG_REASON_NOTHALTED;
362 return ERROR_OK;
363 }
364
365 static const struct command_registration esp32s3_command_handlers[] = {
366 {
367 .usage = "",
368 .chain = esp_xtensa_smp_command_handlers,
369 },
370 {
371 .name = "esp",
372 .usage = "",
373 .chain = esp32_apptrace_command_handlers,
374 },
375 {
376 .name = "esp32",
377 .usage = "",
378 .chain = smp_command_handlers,
379 },
380 {
381 .name = "arm",
382 .mode = COMMAND_ANY,
383 .help = "ARM Command Group",
384 .usage = "",
385 .chain = semihosting_common_handlers
386 },
387 COMMAND_REGISTRATION_DONE
388 };
389
390 /** Holds methods for Xtensa targets. */
391 struct target_type esp32s3_target = {
392 .name = "esp32s3",
393
394 .poll = esp_xtensa_smp_poll,
395 .arch_state = esp32s3_arch_state,
396
397 .halt = xtensa_halt,
398 .resume = esp_xtensa_smp_resume,
399 .step = esp_xtensa_smp_step,
400
401 .assert_reset = esp_xtensa_smp_assert_reset,
402 .deassert_reset = esp_xtensa_smp_deassert_reset,
403 .soft_reset_halt = esp_xtensa_smp_soft_reset_halt,
404
405 .virt2phys = esp32s3_virt2phys,
406 .mmu = xtensa_mmu_is_enabled,
407 .read_memory = xtensa_read_memory,
408 .write_memory = xtensa_write_memory,
409
410 .read_buffer = xtensa_read_buffer,
411 .write_buffer = xtensa_write_buffer,
412
413 .checksum_memory = xtensa_checksum_memory,
414
415 .get_gdb_arch = xtensa_get_gdb_arch,
416 .get_gdb_reg_list = xtensa_get_gdb_reg_list,
417
418 .add_breakpoint = esp_xtensa_breakpoint_add,
419 .remove_breakpoint = esp_xtensa_breakpoint_remove,
420
421 .add_watchpoint = esp_xtensa_smp_watchpoint_add,
422 .remove_watchpoint = esp_xtensa_smp_watchpoint_remove,
423
424 .target_create = esp32s3_target_create,
425 .init_target = esp32s3_target_init,
426 .examine = xtensa_examine,
427 .deinit_target = esp_xtensa_target_deinit,
428
429 .commands = esp32s3_command_handlers,
430 };

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)