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

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)