jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / espressif / esp32s2.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * ESP32-S2 target for OpenOCD *
5 * Copyright (C) 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 "assert.h"
14 #include <target/target.h>
15 #include <target/target_type.h>
16 #include <target/semihosting_common.h>
17 #include "esp_xtensa.h"
18 #include "esp_xtensa_semihosting.h"
19
20 #define ESP32_S2_RTC_DATA_LOW 0x50000000
21 #define ESP32_S2_RTC_DATA_HIGH 0x50002000
22 #define ESP32_S2_DR_REG_LOW 0x3f400000
23 #define ESP32_S2_DR_REG_HIGH 0x3f4d3FFC
24 #define ESP32_S2_SYS_RAM_LOW 0x60000000UL
25 #define ESP32_S2_SYS_RAM_HIGH (ESP32_S2_SYS_RAM_LOW + 0x20000000UL)
26
27 /* ESP32 WDT */
28 #define ESP32_S2_WDT_WKEY_VALUE 0x50d83aa1
29 #define ESP32_S2_TIMG0_BASE 0x3f41F000
30 #define ESP32_S2_TIMG1_BASE 0x3f420000
31 #define ESP32_S2_TIMGWDT_CFG0_OFF 0x48
32 #define ESP32_S2_TIMGWDT_PROTECT_OFF 0x64
33 #define ESP32_S2_TIMG0WDT_CFG0 (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_CFG0_OFF)
34 #define ESP32_S2_TIMG1WDT_CFG0 (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_CFG0_OFF)
35 #define ESP32_S2_TIMG0WDT_PROTECT (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF)
36 #define ESP32_S2_TIMG1WDT_PROTECT (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF)
37 #define ESP32_S2_RTCCNTL_BASE 0x3f408000
38 #define ESP32_S2_RTCWDT_CFG_OFF 0x94
39 #define ESP32_S2_RTCWDT_PROTECT_OFF 0xAC
40 #define ESP32_S2_SWD_CONF_OFF 0xB0
41 #define ESP32_S2_SWD_WPROTECT_OFF 0xB4
42 #define ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF 0x8C
43 #define ESP32_S2_RTC_CNTL_DIG_PWC_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF)
44 #define ESP32_S2_RTCWDT_CFG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_CFG_OFF)
45 #define ESP32_S2_RTCWDT_PROTECT (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_PROTECT_OFF)
46 #define ESP32_S2_SWD_CONF_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_CONF_OFF)
47 #define ESP32_S2_SWD_WPROTECT_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_WPROTECT_OFF)
48 #define ESP32_S2_SWD_AUTO_FEED_EN_M BIT(31)
49 #define ESP32_S2_SWD_WKEY_VALUE 0x8F1D312AU
50 #define ESP32_S2_OPTIONS0 (ESP32_S2_RTCCNTL_BASE + 0x0000)
51 #define ESP32_S2_SW_SYS_RST_M 0x80000000
52 #define ESP32_S2_SW_SYS_RST_V 0x1
53 #define ESP32_S2_SW_SYS_RST_S 31
54 #define ESP32_S2_SW_STALL_PROCPU_C0_M ((ESP32_S2_SW_STALL_PROCPU_C0_V) << (ESP32_S2_SW_STALL_PROCPU_C0_S))
55 #define ESP32_S2_SW_STALL_PROCPU_C0_V 0x3
56 #define ESP32_S2_SW_STALL_PROCPU_C0_S 2
57 #define ESP32_S2_SW_CPU_STALL (ESP32_S2_RTCCNTL_BASE + 0x00B8)
58 #define ESP32_S2_SW_STALL_PROCPU_C1_M ((ESP32_S2_SW_STALL_PROCPU_C1_V) << (ESP32_S2_SW_STALL_PROCPU_C1_S))
59 #define ESP32_S2_SW_STALL_PROCPU_C1_V 0x3FU
60 #define ESP32_S2_SW_STALL_PROCPU_C1_S 26
61 #define ESP32_S2_CLK_CONF (ESP32_S2_RTCCNTL_BASE + 0x0074)
62 #define ESP32_S2_CLK_CONF_DEF 0x1583218
63 #define ESP32_S2_STORE4 (ESP32_S2_RTCCNTL_BASE + 0x00BC)
64 #define ESP32_S2_STORE5 (ESP32_S2_RTCCNTL_BASE + 0x00C0)
65 #define ESP32_S2_DPORT_PMS_OCCUPY_3 0x3F4C10E0
66
67 #define ESP32_S2_TRACEMEM_BLOCK_SZ 0x4000
68
69 #define ESP32_S2_DR_REG_UART_BASE 0x3f400000
70 #define ESP32_S2_REG_UART_BASE(i) (ESP32_S2_DR_REG_UART_BASE + (i) * 0x10000)
71 #define ESP32_S2_UART_DATE_REG(i) (ESP32_S2_REG_UART_BASE(i) + 0x74)
72 struct esp32s2_common {
73 struct esp_xtensa_common esp_xtensa;
74 };
75
76 static int esp32s2_soc_reset(struct target *target);
77 static int esp32s2_disable_wdts(struct target *target);
78
79 static int esp32s2_assert_reset(struct target *target)
80 {
81 return ERROR_OK;
82 }
83
84 static int esp32s2_deassert_reset(struct target *target)
85 {
86 struct xtensa *xtensa = target_to_xtensa(target);
87
88 LOG_TARGET_DEBUG(target, "begin");
89
90 int res = xtensa_deassert_reset(target);
91 if (res != ERROR_OK)
92 return res;
93
94 /* restore configured value
95 esp32s2_soc_reset() modified it, but can not restore just after SW reset for some reason (???) */
96 res = xtensa_smpbreak_write(xtensa, xtensa->smp_break);
97 if (res != ERROR_OK) {
98 LOG_ERROR("Failed to restore smpbreak (%d)!", res);
99 return res;
100 }
101 return ERROR_OK;
102 }
103
104 static int esp32s2_soft_reset_halt(struct target *target)
105 {
106 LOG_TARGET_DEBUG(target, "begin");
107
108 /* Reset the SoC first */
109 int res = esp32s2_soc_reset(target);
110 if (res != ERROR_OK)
111 return res;
112 return xtensa_soft_reset_halt(target);
113 }
114
115 static int esp32s2_set_peri_reg_mask(struct target *target,
116 target_addr_t addr,
117 uint32_t mask,
118 uint32_t val)
119 {
120 uint32_t reg_val;
121 int res = target_read_u32(target, addr, &reg_val);
122 if (res != ERROR_OK)
123 return res;
124 reg_val = (reg_val & (~mask)) | val;
125 res = target_write_u32(target, addr, reg_val);
126 if (res != ERROR_OK)
127 return res;
128
129 return ERROR_OK;
130 }
131
132 static int esp32s2_stall_set(struct target *target, bool stall)
133 {
134 LOG_TARGET_DEBUG(target, "begin");
135
136 int res = esp32s2_set_peri_reg_mask(target,
137 ESP32_S2_SW_CPU_STALL,
138 ESP32_S2_SW_STALL_PROCPU_C1_M,
139 stall ? 0x21U << ESP32_S2_SW_STALL_PROCPU_C1_S : 0);
140 if (res != ERROR_OK) {
141 LOG_ERROR("Failed to write ESP32_S2_SW_CPU_STALL (%d)!", res);
142 return res;
143 }
144 res = esp32s2_set_peri_reg_mask(target,
145 ESP32_S2_OPTIONS0,
146 ESP32_S2_SW_STALL_PROCPU_C0_M,
147 stall ? 0x2 << ESP32_S2_SW_STALL_PROCPU_C0_S : 0);
148 if (res != ERROR_OK) {
149 LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res);
150 return res;
151 }
152 return ERROR_OK;
153 }
154
155 static inline int esp32s2_stall(struct target *target)
156 {
157 return esp32s2_stall_set(target, true);
158 }
159
160 static inline int esp32s2_unstall(struct target *target)
161 {
162 return esp32s2_stall_set(target, false);
163 }
164
165 /* Reset ESP32-S2's peripherals.
166 Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, APP CPU is in reset
167 How this works:
168 0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt
169 1. Resets clock related registers
170 2. Stalls CPU
171 3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit
172 4. CPU is reset and stalled at the first reset vector instruction
173 5. wait for the OCD to be reset
174 6. halt the target
175 7. Unstalls CPU
176 8. Disables WDTs and trace memory mapping
177 */
178 static int esp32s2_soc_reset(struct target *target)
179 {
180 int res;
181 struct xtensa *xtensa = target_to_xtensa(target);
182
183 LOG_DEBUG("start");
184
185 /* In order to write to peripheral registers, target must be halted first */
186 if (target->state != TARGET_HALTED) {
187 LOG_TARGET_DEBUG(target, "Target not halted before SoC reset, trying to halt it first");
188 xtensa_halt(target);
189 res = target_wait_state(target, TARGET_HALTED, 1000);
190 if (res != ERROR_OK) {
191 LOG_TARGET_DEBUG(target, "Couldn't halt target before SoC reset, trying to do reset-halt");
192 res = xtensa_assert_reset(target);
193 if (res != ERROR_OK) {
194 LOG_TARGET_ERROR(
195 target,
196 "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)",
197 res);
198 return res;
199 }
200 alive_sleep(10);
201 xtensa_poll(target);
202 int reset_halt_save = target->reset_halt;
203 target->reset_halt = 1;
204 res = xtensa_deassert_reset(target);
205 target->reset_halt = reset_halt_save;
206 if (res != ERROR_OK) {
207 LOG_TARGET_ERROR(
208 target,
209 "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)",
210 res);
211 return res;
212 }
213 alive_sleep(10);
214 xtensa_poll(target);
215 xtensa_halt(target);
216 res = target_wait_state(target, TARGET_HALTED, 1000);
217 if (res != ERROR_OK) {
218 LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset");
219 return res;
220 }
221 }
222 }
223
224 assert(target->state == TARGET_HALTED);
225
226 /* Set some clock-related RTC registers to the default values */
227 res = target_write_u32(target, ESP32_S2_STORE4, 0);
228 if (res != ERROR_OK) {
229 LOG_ERROR("Failed to write ESP32_S2_STORE4 (%d)!", res);
230 return res;
231 }
232 res = target_write_u32(target, ESP32_S2_STORE5, 0);
233 if (res != ERROR_OK) {
234 LOG_ERROR("Failed to write ESP32_S2_STORE5 (%d)!", res);
235 return res;
236 }
237 res = target_write_u32(target, ESP32_S2_RTC_CNTL_DIG_PWC_REG, 0);
238 if (res != ERROR_OK) {
239 LOG_ERROR("Failed to write ESP32_S2_RTC_CNTL_DIG_PWC_REG (%d)!", res);
240 return res;
241 }
242 res = target_write_u32(target, ESP32_S2_CLK_CONF, ESP32_S2_CLK_CONF_DEF);
243 if (res != ERROR_OK) {
244 LOG_ERROR("Failed to write ESP32_S2_CLK_CONF (%d)!", res);
245 return res;
246 }
247 /* Stall CPU */
248 res = esp32s2_stall(target);
249 if (res != ERROR_OK)
250 return res;
251 /* enable stall */
252 res = xtensa_smpbreak_write(xtensa, OCDDCR_RUNSTALLINEN);
253 if (res != ERROR_OK) {
254 LOG_ERROR("Failed to set smpbreak (%d)!", res);
255 return res;
256 }
257 /* Reset CPU */
258 xtensa->suppress_dsr_errors = true;
259 res = esp32s2_set_peri_reg_mask(target,
260 ESP32_S2_OPTIONS0,
261 ESP32_S2_SW_SYS_RST_M,
262 BIT(ESP32_S2_SW_SYS_RST_S));
263 xtensa->suppress_dsr_errors = false;
264 if (res != ERROR_OK) {
265 LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res);
266 return res;
267 }
268 /* Wait for SoC to reset */
269 alive_sleep(100);
270 int64_t timeout = timeval_ms() + 100;
271 while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) {
272 alive_sleep(10);
273 xtensa_poll(target);
274 if (timeval_ms() >= timeout) {
275 LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d",
276 target->state);
277 return ERROR_TARGET_TIMEOUT;
278 }
279 }
280
281 xtensa_halt(target);
282 res = target_wait_state(target, TARGET_HALTED, 1000);
283 if (res != ERROR_OK) {
284 LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset");
285 return res;
286 }
287 /* Unstall CPU */
288 res = esp32s2_unstall(target);
289 if (res != ERROR_OK)
290 return res;
291 /* Disable WDTs */
292 res = esp32s2_disable_wdts(target);
293 if (res != ERROR_OK)
294 return res;
295 /* Disable trace memory mapping */
296 res = target_write_u32(target, ESP32_S2_DPORT_PMS_OCCUPY_3, 0);
297 if (res != ERROR_OK) {
298 LOG_ERROR("Failed to write ESP32_S2_DPORT_PMS_OCCUPY_3 (%d)!", res);
299 return res;
300 }
301 return ERROR_OK;
302 }
303
304 static int esp32s2_disable_wdts(struct target *target)
305 {
306 /* TIMG1 WDT */
307 int res = target_write_u32(target, ESP32_S2_TIMG0WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
308 if (res != ERROR_OK) {
309 LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_PROTECT (%d)!", res);
310 return res;
311 }
312 res = target_write_u32(target, ESP32_S2_TIMG0WDT_CFG0, 0);
313 if (res != ERROR_OK) {
314 LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_CFG0 (%d)!", res);
315 return res;
316 }
317 /* TIMG2 WDT */
318 res = target_write_u32(target, ESP32_S2_TIMG1WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
319 if (res != ERROR_OK) {
320 LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_PROTECT (%d)!", res);
321 return res;
322 }
323 res = target_write_u32(target, ESP32_S2_TIMG1WDT_CFG0, 0);
324 if (res != ERROR_OK) {
325 LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_CFG0 (%d)!", res);
326 return res;
327 }
328 /* RTC WDT */
329 res = target_write_u32(target, ESP32_S2_RTCWDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
330 if (res != ERROR_OK) {
331 LOG_ERROR("Failed to write ESP32_S2_RTCWDT_PROTECT (%d)!", res);
332 return res;
333 }
334 res = target_write_u32(target, ESP32_S2_RTCWDT_CFG, 0);
335 if (res != ERROR_OK) {
336 LOG_ERROR("Failed to write ESP32_S2_RTCWDT_CFG (%d)!", res);
337 return res;
338 }
339 /* Enable SWD auto-feed */
340 res = target_write_u32(target, ESP32_S2_SWD_WPROTECT_REG, ESP32_S2_SWD_WKEY_VALUE);
341 if (res != ERROR_OK) {
342 LOG_ERROR("Failed to write ESP32_S2_SWD_WPROTECT_REG (%d)!", res);
343 return res;
344 }
345 uint32_t swd_conf_reg = 0;
346 res = target_read_u32(target, ESP32_S2_SWD_CONF_REG, &swd_conf_reg);
347 if (res != ERROR_OK) {
348 LOG_ERROR("Failed to read ESP32_S2_SWD_CONF_REG (%d)!", res);
349 return res;
350 }
351 swd_conf_reg |= ESP32_S2_SWD_AUTO_FEED_EN_M;
352 res = target_write_u32(target, ESP32_S2_SWD_CONF_REG, swd_conf_reg);
353 if (res != ERROR_OK) {
354 LOG_ERROR("Failed to write ESP32_S2_SWD_CONF_REG (%d)!", res);
355 return res;
356 }
357 return ERROR_OK;
358 }
359
360 static int esp32s2_arch_state(struct target *target)
361 {
362 return ERROR_OK;
363 }
364
365 static int esp32s2_on_halt(struct target *target)
366 {
367 int ret = esp32s2_disable_wdts(target);
368 if (ret == ERROR_OK)
369 ret = esp_xtensa_on_halt(target);
370 return ret;
371 }
372
373 static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
374 {
375 int ret = xtensa_step(target, current, address, handle_breakpoints);
376 if (ret == ERROR_OK) {
377 esp32s2_on_halt(target);
378 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
379 }
380 return ret;
381 }
382
383 static int esp32s2_poll(struct target *target)
384 {
385 enum target_state old_state = target->state;
386 int ret = esp_xtensa_poll(target);
387 if (ret != ERROR_OK)
388 return ret;
389
390 if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
391 /* Call any event callbacks that are applicable */
392 if (old_state == TARGET_DEBUG_RUNNING) {
393 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
394 } else {
395 if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) {
396 struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target);
397 if (ret == ERROR_OK && esp_xtensa->semihost.need_resume) {
398 esp_xtensa->semihost.need_resume = false;
399 /* Resume xtensa_resume will handle BREAK instruction. */
400 ret = target_resume(target, 1, 0, 1, 0);
401 if (ret != ERROR_OK) {
402 LOG_ERROR("Failed to resume target");
403 return ret;
404 }
405 }
406 return ret;
407 }
408 esp32s2_on_halt(target);
409 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
410 }
411 }
412
413 return ret;
414 }
415
416 static int esp32s2_virt2phys(struct target *target,
417 target_addr_t virtual, target_addr_t *physical)
418 {
419 *physical = virtual;
420 return ERROR_OK;
421 }
422
423 static int esp32s2_target_init(struct command_context *cmd_ctx, struct target *target)
424 {
425 int ret = esp_xtensa_target_init(cmd_ctx, target);
426 if (ret != ERROR_OK)
427 return ret;
428
429 return esp_xtensa_semihosting_init(target);
430 }
431
432 static const struct xtensa_debug_ops esp32s2_dbg_ops = {
433 .queue_enable = xtensa_dm_queue_enable,
434 .queue_reg_read = xtensa_dm_queue_reg_read,
435 .queue_reg_write = xtensa_dm_queue_reg_write
436 };
437
438 static const struct xtensa_power_ops esp32s2_pwr_ops = {
439 .queue_reg_read = xtensa_dm_queue_pwr_reg_read,
440 .queue_reg_write = xtensa_dm_queue_pwr_reg_write
441 };
442
443 static const struct esp_semihost_ops esp32s2_semihost_ops = {
444 .prepare = esp32s2_disable_wdts
445 };
446
447 static int esp32s2_target_create(struct target *target, Jim_Interp *interp)
448 {
449 struct xtensa_debug_module_config esp32s2_dm_cfg = {
450 .dbg_ops = &esp32s2_dbg_ops,
451 .pwr_ops = &esp32s2_pwr_ops,
452 .tap = target->tap,
453 .queue_tdi_idle = NULL,
454 .queue_tdi_idle_arg = NULL
455 };
456
457 /* creates xtensa object */
458 struct esp32s2_common *esp32 = calloc(1, sizeof(*esp32));
459 if (!esp32) {
460 LOG_ERROR("Failed to alloc memory for arch info!");
461 return ERROR_FAIL;
462 }
463
464 int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_dm_cfg, &esp32s2_semihost_ops);
465 if (ret != ERROR_OK) {
466 LOG_ERROR("Failed to init arch info!");
467 free(esp32);
468 return ret;
469 }
470
471 /* Assume running target. If different, the first poll will fix this */
472 target->state = TARGET_RUNNING;
473 target->debug_reason = DBG_REASON_NOTHALTED;
474 return ERROR_OK;
475 }
476
477 static const struct command_registration esp32s2_command_handlers[] = {
478 {
479 .chain = xtensa_command_handlers,
480 },
481 {
482 .name = "esp",
483 .usage = "",
484 .chain = esp32_apptrace_command_handlers,
485 },
486 {
487 .name = "arm",
488 .mode = COMMAND_ANY,
489 .help = "ARM Command Group",
490 .usage = "",
491 .chain = semihosting_common_handlers
492 },
493 COMMAND_REGISTRATION_DONE
494 };
495
496 /* Holds methods for Xtensa targets. */
497 struct target_type esp32s2_target = {
498 .name = "esp32s2",
499
500 .poll = esp32s2_poll,
501 .arch_state = esp32s2_arch_state,
502
503 .halt = xtensa_halt,
504 .resume = xtensa_resume,
505 .step = esp32s2_step,
506
507 .assert_reset = esp32s2_assert_reset,
508 .deassert_reset = esp32s2_deassert_reset,
509 .soft_reset_halt = esp32s2_soft_reset_halt,
510
511 .virt2phys = esp32s2_virt2phys,
512 .mmu = xtensa_mmu_is_enabled,
513 .read_memory = xtensa_read_memory,
514 .write_memory = xtensa_write_memory,
515
516 .read_buffer = xtensa_read_buffer,
517 .write_buffer = xtensa_write_buffer,
518
519 .checksum_memory = xtensa_checksum_memory,
520
521 .get_gdb_arch = xtensa_get_gdb_arch,
522 .get_gdb_reg_list = xtensa_get_gdb_reg_list,
523
524 .run_algorithm = xtensa_run_algorithm,
525 .start_algorithm = xtensa_start_algorithm,
526 .wait_algorithm = xtensa_wait_algorithm,
527
528 .add_breakpoint = esp_xtensa_breakpoint_add,
529 .remove_breakpoint = esp_xtensa_breakpoint_remove,
530
531 .add_watchpoint = xtensa_watchpoint_add,
532 .remove_watchpoint = xtensa_watchpoint_remove,
533
534 .target_create = esp32s2_target_create,
535 .init_target = esp32s2_target_init,
536 .examine = xtensa_examine,
537 .deinit_target = esp_xtensa_target_deinit,
538
539 .commands = esp32s2_command_handlers,
540 };

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)