0f8de8caeb128bc965b098d26420c832621988c8
[openocd.git] / src / flash / nor / fm4.c
1 /*
2 * Spansion FM4 flash
3 *
4 * Copyright (c) 2015 Andreas Färber
5 *
6 * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series
7 * Based on MB9B560R_MN709-00005 for MB9BFx66/x67/x68 series
8 * Based on MB9B560L_MN709-00006 for MB9BFx64/x65/x66 series
9 */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include "imp.h"
16 #include <helper/binarybuffer.h>
17 #include <target/algorithm.h>
18 #include <target/armv7m.h>
19
20 #define FLASH_BASE 0x40000000
21 #define FASZR (FLASH_BASE + 0x000)
22 #define DFCTRLR (FLASH_BASE + 0x030)
23 #define DFCTRLR_DFE (1UL << 0)
24
25 #define WDG_BASE 0x40011000
26 #define WDG_CTL (WDG_BASE + 0x008)
27 #define WDG_LCK (WDG_BASE + 0xC00)
28
29 enum fm4_variant {
30 mb9bfx64,
31 mb9bfx65,
32 mb9bfx66,
33 mb9bfx67,
34 mb9bfx68,
35
36 s6e2cx8,
37 s6e2cx9,
38 s6e2cxa,
39 };
40
41 struct fm4_flash_bank {
42 enum fm4_variant variant;
43 int macro_nr;
44 bool probed;
45 };
46
47 static int fm4_disable_hw_watchdog(struct target *target)
48 {
49 int retval;
50
51 retval = target_write_u32(target, WDG_LCK, 0x1ACCE551);
52 if (retval != ERROR_OK)
53 return retval;
54
55 retval = target_write_u32(target, WDG_LCK, 0xE5331AAE);
56 if (retval != ERROR_OK)
57 return retval;
58
59 retval = target_write_u32(target, WDG_CTL, 0);
60 if (retval != ERROR_OK)
61 return retval;
62
63 return ERROR_OK;
64 }
65
66 static int fm4_enter_flash_cpu_programming_mode(struct target *target)
67 {
68 uint32_t u32_value;
69 int retval;
70
71 /* FASZR ASZ = CPU programming mode */
72 retval = target_write_u32(target, FASZR, 0x00000001);
73 if (retval != ERROR_OK)
74 return retval;
75 retval = target_read_u32(target, FASZR, &u32_value);
76 if (retval != ERROR_OK)
77 return retval;
78
79 return ERROR_OK;
80 }
81
82 static int fm4_enter_flash_cpu_rom_mode(struct target *target)
83 {
84 uint32_t u32_value;
85 int retval;
86
87 /* FASZR ASZ = CPU ROM mode */
88 retval = target_write_u32(target, FASZR, 0x00000002);
89 if (retval != ERROR_OK)
90 return retval;
91 retval = target_read_u32(target, FASZR, &u32_value);
92 if (retval != ERROR_OK)
93 return retval;
94
95 return ERROR_OK;
96 }
97
98 static int fm4_flash_erase(struct flash_bank *bank, int first, int last)
99 {
100 struct target *target = bank->target;
101 struct working_area *workarea;
102 struct reg_param reg_params[4];
103 struct armv7m_algorithm armv7m_algo;
104 unsigned i;
105 int retval, sector;
106 const uint8_t erase_sector_code[] = {
107 #include "../../../contrib/loaders/flash/fm4/erase.inc"
108 };
109
110 if (target->state != TARGET_HALTED) {
111 LOG_WARNING("Cannot communicate... target not halted.");
112 return ERROR_TARGET_NOT_HALTED;
113 }
114
115 LOG_DEBUG("Spansion FM4 erase sectors %d to %d", first, last);
116
117 retval = fm4_disable_hw_watchdog(target);
118 if (retval != ERROR_OK)
119 return retval;
120
121 retval = fm4_enter_flash_cpu_programming_mode(target);
122 if (retval != ERROR_OK)
123 return retval;
124
125 retval = target_alloc_working_area(target, sizeof(erase_sector_code),
126 &workarea);
127 if (retval != ERROR_OK) {
128 LOG_ERROR("No working area available.");
129 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
130 goto err_alloc_code;
131 }
132 retval = target_write_buffer(target, workarea->address,
133 sizeof(erase_sector_code), erase_sector_code);
134 if (retval != ERROR_OK)
135 goto err_write_code;
136
137 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
138 armv7m_algo.core_mode = ARM_MODE_THREAD;
139
140 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
141 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
142 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
143 init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
144
145 for (sector = first; sector <= last; sector++) {
146 uint32_t addr = bank->base + bank->sectors[sector].offset;
147 uint32_t result;
148
149 buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
150 buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
151 buf_set_u32(reg_params[2].value, 0, 32, addr);
152
153 retval = target_run_algorithm(target,
154 0, NULL,
155 ARRAY_SIZE(reg_params), reg_params,
156 workarea->address, 0,
157 1000, &armv7m_algo);
158 if (retval != ERROR_OK) {
159 LOG_ERROR("Error executing flash sector erase "
160 "programming algorithm");
161 retval = ERROR_FLASH_OPERATION_FAILED;
162 goto err_run;
163 }
164
165 result = buf_get_u32(reg_params[3].value, 0, 32);
166 if (result == 2) {
167 LOG_ERROR("Timeout error from flash sector erase programming algorithm");
168 retval = ERROR_FLASH_OPERATION_FAILED;
169 goto err_run_ret;
170 } else if (result != 0) {
171 LOG_ERROR("Unexpected error %d from flash sector erase programming algorithm", result);
172 retval = ERROR_FLASH_OPERATION_FAILED;
173 goto err_run_ret;
174 } else
175 retval = ERROR_OK;
176
177 bank->sectors[sector].is_erased = 1;
178 }
179
180 err_run_ret:
181 err_run:
182 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
183 destroy_reg_param(&reg_params[i]);
184
185 err_write_code:
186 target_free_working_area(target, workarea);
187
188 err_alloc_code:
189 if (retval != ERROR_OK)
190 fm4_enter_flash_cpu_rom_mode(target);
191 else
192 retval = fm4_enter_flash_cpu_rom_mode(target);
193
194 return retval;
195 }
196
197 static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
198 uint32_t offset, uint32_t byte_count)
199 {
200 struct target *target = bank->target;
201 struct working_area *code_workarea, *data_workarea;
202 struct reg_param reg_params[6];
203 struct armv7m_algorithm armv7m_algo;
204 uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
205 uint32_t result;
206 unsigned i;
207 int retval;
208 const uint8_t write_block_code[] = {
209 #include "../../../contrib/loaders/flash/fm4/write.inc"
210 };
211
212 LOG_DEBUG("Spansion FM4 write at 0x%08" PRIx32 " (%" PRId32 " bytes)",
213 offset, byte_count);
214
215 if (offset & 0x1) {
216 LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment",
217 offset);
218 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
219 }
220 if (byte_count & 0x1) {
221 LOG_WARNING("length %" PRId32 " is not 2-byte aligned, rounding up",
222 byte_count);
223 }
224
225 if (target->state != TARGET_HALTED) {
226 LOG_WARNING("Cannot communicate... target not halted.");
227 return ERROR_TARGET_NOT_HALTED;
228 }
229
230 retval = fm4_disable_hw_watchdog(target);
231 if (retval != ERROR_OK)
232 return retval;
233
234 retval = target_alloc_working_area(target, sizeof(write_block_code),
235 &code_workarea);
236 if (retval != ERROR_OK) {
237 LOG_ERROR("No working area available for write code.");
238 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
239 }
240 retval = target_write_buffer(target, code_workarea->address,
241 sizeof(write_block_code), write_block_code);
242 if (retval != ERROR_OK)
243 goto err_write_code;
244
245 retval = target_alloc_working_area(target,
246 MIN(halfword_count * 2, target_get_working_area_avail(target)),
247 &data_workarea);
248 if (retval != ERROR_OK) {
249 LOG_ERROR("No working area available for write data.");
250 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
251 goto err_alloc_data;
252 }
253
254 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
255 armv7m_algo.core_mode = ARM_MODE_THREAD;
256
257 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
258 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
259 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
260 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
261 init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
262 init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);
263
264 retval = fm4_enter_flash_cpu_programming_mode(target);
265 if (retval != ERROR_OK)
266 goto err_flash_mode;
267
268 while (byte_count > 0) {
269 uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2);
270 uint32_t addr = bank->base + offset;
271
272 LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
273 MIN(halfwords * 2, byte_count), data_workarea->address);
274
275 retval = target_write_buffer(target, data_workarea->address,
276 MIN(halfwords * 2, byte_count), buffer);
277 if (retval != ERROR_OK) {
278 LOG_ERROR("Error writing data buffer");
279 retval = ERROR_FLASH_OPERATION_FAILED;
280 goto err_write_data;
281 }
282
283 LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRId32 "x)",
284 addr, addr + halfwords * 2 - 1, halfwords);
285
286 buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
287 buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
288 buf_set_u32(reg_params[2].value, 0, 32, addr);
289 buf_set_u32(reg_params[3].value, 0, 32, data_workarea->address);
290 buf_set_u32(reg_params[4].value, 0, 32, halfwords);
291
292 retval = target_run_algorithm(target,
293 0, NULL,
294 ARRAY_SIZE(reg_params), reg_params,
295 code_workarea->address, 0,
296 5 * 60 * 1000, &armv7m_algo);
297 if (retval != ERROR_OK) {
298 LOG_ERROR("Error executing flash sector erase "
299 "programming algorithm");
300 retval = ERROR_FLASH_OPERATION_FAILED;
301 goto err_run;
302 }
303
304 result = buf_get_u32(reg_params[5].value, 0, 32);
305 if (result == 2) {
306 LOG_ERROR("Timeout error from flash write "
307 "programming algorithm");
308 retval = ERROR_FLASH_OPERATION_FAILED;
309 goto err_run_ret;
310 } else if (result != 0) {
311 LOG_ERROR("Unexpected error %d from flash write "
312 "programming algorithm", result);
313 retval = ERROR_FLASH_OPERATION_FAILED;
314 goto err_run_ret;
315 } else
316 retval = ERROR_OK;
317
318 halfword_count -= halfwords;
319 offset += halfwords * 2;
320 buffer += halfwords * 2;
321 byte_count -= MIN(halfwords * 2, byte_count);
322 }
323
324 err_run_ret:
325 err_run:
326 err_write_data:
327 retval = fm4_enter_flash_cpu_rom_mode(target);
328
329 err_flash_mode:
330 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
331 destroy_reg_param(&reg_params[i]);
332
333 target_free_working_area(target, data_workarea);
334 err_alloc_data:
335 err_write_code:
336 target_free_working_area(target, code_workarea);
337
338 return retval;
339 }
340
341 static int mb9bf_probe(struct flash_bank *bank)
342 {
343 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
344 uint32_t flash_addr = bank->base;
345 int i;
346
347 switch (fm4_bank->variant) {
348 case mb9bfx64:
349 bank->num_sectors = 8;
350 break;
351 case mb9bfx65:
352 bank->num_sectors = 10;
353 break;
354 case mb9bfx66:
355 bank->num_sectors = 12;
356 break;
357 case mb9bfx67:
358 bank->num_sectors = 16;
359 break;
360 case mb9bfx68:
361 bank->num_sectors = 20;
362 break;
363 default:
364 return ERROR_FLASH_OPER_UNSUPPORTED;
365 }
366
367 LOG_DEBUG("%d sectors", bank->num_sectors);
368 bank->sectors = calloc(bank->num_sectors,
369 sizeof(struct flash_sector));
370 for (i = 0; i < bank->num_sectors; i++) {
371 if (i < 4)
372 bank->sectors[i].size = 8 * 1024;
373 else if (i == 4)
374 bank->sectors[i].size = 32 * 1024;
375 else
376 bank->sectors[i].size = 64 * 1024;
377 bank->sectors[i].offset = flash_addr - bank->base;
378 bank->sectors[i].is_erased = -1;
379 bank->sectors[i].is_protected = -1;
380
381 bank->size += bank->sectors[i].size;
382 flash_addr += bank->sectors[i].size;
383 }
384
385 return ERROR_OK;
386 }
387
388 static void s6e2cc_init_sector(struct flash_sector *sector, int sa)
389 {
390 if (sa < 8)
391 sector->size = 8 * 1024;
392 else if (sa == 8)
393 sector->size = 32 * 1024;
394 else
395 sector->size = 64 * 1024;
396
397 sector->is_erased = -1;
398 sector->is_protected = -1;
399 }
400
401 static int s6e2cc_probe(struct flash_bank *bank)
402 {
403 struct target *target = bank->target;
404 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
405 uint32_t u32_value;
406 uint32_t flash_addr = bank->base;
407 int i, retval, num_sectors, num_extra_sectors;
408
409 retval = target_read_u32(target, DFCTRLR, &u32_value);
410 if (retval != ERROR_OK)
411 return retval;
412 if (u32_value & DFCTRLR_DFE) {
413 LOG_WARNING("Dual Flash mode is not implemented.");
414 return ERROR_FLASH_OPER_UNSUPPORTED;
415 }
416
417 switch (fm4_bank->variant) {
418 case s6e2cx8:
419 num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 0;
420 break;
421 case s6e2cx9:
422 num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 12;
423 break;
424 case s6e2cxa:
425 num_sectors = 20;
426 break;
427 default:
428 return ERROR_FLASH_OPER_UNSUPPORTED;
429 }
430 num_extra_sectors = (fm4_bank->macro_nr == 0) ? 1 : 4;
431 bank->num_sectors = num_sectors + num_extra_sectors;
432
433 LOG_DEBUG("%d sectors", bank->num_sectors);
434 bank->sectors = calloc(bank->num_sectors,
435 sizeof(struct flash_sector));
436 for (i = 0; i < num_sectors; i++) {
437 int sa = 4 + i;
438 bank->sectors[i].offset = flash_addr - bank->base;
439 s6e2cc_init_sector(&bank->sectors[i], sa);
440
441 bank->size += bank->sectors[i].size;
442 flash_addr += bank->sectors[i].size;
443 }
444
445 flash_addr = (fm4_bank->macro_nr == 0) ? 0x00406000 : 0x00408000;
446 for (; i < bank->num_sectors; i++) {
447 int sa = 4 - num_extra_sectors + (i - num_sectors);
448 bank->sectors[i].offset = flash_addr - bank->base;
449 s6e2cc_init_sector(&bank->sectors[i], sa);
450
451 /*
452 * Don't increase bank->size for these sectors
453 * to avoid an overlap between Flash Macros #0 and #1.
454 */
455 flash_addr += bank->sectors[i].size;
456 }
457
458 return ERROR_OK;
459 }
460
461 static int fm4_probe(struct flash_bank *bank)
462 {
463 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
464 int retval;
465
466 if (fm4_bank->probed)
467 return ERROR_OK;
468
469 if (bank->target->state != TARGET_HALTED) {
470 LOG_WARNING("Cannot communicate... target not halted.");
471 return ERROR_TARGET_NOT_HALTED;
472 }
473
474 switch (fm4_bank->variant) {
475 case mb9bfx64:
476 case mb9bfx65:
477 case mb9bfx66:
478 case mb9bfx67:
479 case mb9bfx68:
480 retval = mb9bf_probe(bank);
481 break;
482 case s6e2cx8:
483 case s6e2cx9:
484 case s6e2cxa:
485 retval = s6e2cc_probe(bank);
486 break;
487 default:
488 return ERROR_FLASH_OPER_UNSUPPORTED;
489 }
490 if (retval != ERROR_OK)
491 return retval;
492
493 fm4_bank->probed = true;
494
495 return ERROR_OK;
496 }
497
498 static int fm4_auto_probe(struct flash_bank *bank)
499 {
500 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
501
502 if (fm4_bank->probed)
503 return ERROR_OK;
504
505 return fm4_probe(bank);
506 }
507
508 static int fm4_protect_check(struct flash_bank *bank)
509 {
510 return ERROR_OK;
511 }
512
513 static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
514 {
515 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
516 const char *name;
517
518 if (bank->target->state != TARGET_HALTED) {
519 LOG_WARNING("Cannot communicate... target not halted.");
520 return ERROR_TARGET_NOT_HALTED;
521 }
522
523 switch (fm4_bank->variant) {
524 case mb9bfx64:
525 name = "MB9BFx64";
526 break;
527 case mb9bfx65:
528 name = "MB9BFx65";
529 break;
530 case mb9bfx66:
531 name = "MB9BFx66";
532 break;
533 case mb9bfx67:
534 name = "MB9BFx67";
535 break;
536 case mb9bfx68:
537 name = "MB9BFx68";
538 break;
539 case s6e2cx8:
540 name = "S6E2Cx8";
541 break;
542 case s6e2cx9:
543 name = "S6E2Cx9";
544 break;
545 case s6e2cxa:
546 name = "S6E2CxA";
547 break;
548 default:
549 name = "unknown";
550 break;
551 }
552
553 switch (fm4_bank->variant) {
554 case s6e2cx8:
555 case s6e2cx9:
556 case s6e2cxa:
557 snprintf(buf, buf_size, "%s MainFlash Macro #%i",
558 name, fm4_bank->macro_nr);
559 break;
560 default:
561 snprintf(buf, buf_size, "%s MainFlash", name);
562 break;
563 }
564
565 return ERROR_OK;
566 }
567
568 static bool fm4_name_match(const char *s, const char *pattern)
569 {
570 int i = 0;
571
572 while (s[i]) {
573 /* If the match string is shorter, ignore excess */
574 if (!pattern[i])
575 return true;
576 /* Use x as wildcard */
577 if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i]))
578 return false;
579 i++;
580 }
581 return true;
582 }
583
584 static int mb9bf_bank_setup(struct flash_bank *bank, const char *variant)
585 {
586 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
587
588 if (fm4_name_match(variant, "MB9BFx64")) {
589 fm4_bank->variant = mb9bfx64;
590 } else if (fm4_name_match(variant, "MB9BFx65")) {
591 fm4_bank->variant = mb9bfx65;
592 } else if (fm4_name_match(variant, "MB9BFx66")) {
593 fm4_bank->variant = mb9bfx66;
594 } else if (fm4_name_match(variant, "MB9BFx67")) {
595 fm4_bank->variant = mb9bfx67;
596 } else if (fm4_name_match(variant, "MB9BFx68")) {
597 fm4_bank->variant = mb9bfx68;
598 } else {
599 LOG_WARNING("MB9BF variant %s not recognized.", variant);
600 return ERROR_FLASH_OPER_UNSUPPORTED;
601 }
602
603 return ERROR_OK;
604 }
605
606 static int s6e2cc_bank_setup(struct flash_bank *bank, const char *variant)
607 {
608 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
609
610 if (fm4_name_match(variant, "S6E2Cx8")) {
611 fm4_bank->variant = s6e2cx8;
612 } else if (fm4_name_match(variant, "S6E2Cx9")) {
613 fm4_bank->variant = s6e2cx9;
614 } else if (fm4_name_match(variant, "S6E2CxA")) {
615 fm4_bank->variant = s6e2cxa;
616 } else {
617 LOG_WARNING("S6E2CC variant %s not recognized.", variant);
618 return ERROR_FLASH_OPER_UNSUPPORTED;
619 }
620
621 return ERROR_OK;
622 }
623
624 FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command)
625 {
626 struct fm4_flash_bank *fm4_bank;
627 const char *variant;
628 int ret;
629
630 if (CMD_ARGC < 7)
631 return ERROR_COMMAND_SYNTAX_ERROR;
632
633 variant = CMD_ARGV[6];
634
635 fm4_bank = malloc(sizeof(struct fm4_flash_bank));
636 if (!fm4_bank)
637 return ERROR_FLASH_OPERATION_FAILED;
638
639 fm4_bank->probed = false;
640 fm4_bank->macro_nr = (bank->base == 0x00000000) ? 0 : 1;
641
642 bank->driver_priv = fm4_bank;
643
644 if (fm4_name_match(variant, "MB9BF"))
645 ret = mb9bf_bank_setup(bank, variant);
646 else if (fm4_name_match(variant, "S6E2Cx"))
647 ret = s6e2cc_bank_setup(bank, variant);
648 else {
649 LOG_WARNING("Family %s not recognized.", variant);
650 ret = ERROR_FLASH_OPER_UNSUPPORTED;
651 }
652 if (ret != ERROR_OK)
653 free(fm4_bank);
654 return ret;
655 }
656
657 static const struct command_registration fm4_exec_command_handlers[] = {
658 COMMAND_REGISTRATION_DONE
659 };
660
661 static const struct command_registration fm4_command_handlers[] = {
662 {
663 .name = "fm4",
664 .mode = COMMAND_ANY,
665 .help = "fm4 flash command group",
666 .usage = "",
667 .chain = fm4_exec_command_handlers,
668 },
669 COMMAND_REGISTRATION_DONE
670 };
671
672 struct flash_driver fm4_flash = {
673 .name = "fm4",
674 .commands = fm4_command_handlers,
675 .flash_bank_command = fm4_flash_bank_command,
676 .info = fm4_get_info_command,
677 .probe = fm4_probe,
678 .auto_probe = fm4_auto_probe,
679 .protect_check = fm4_protect_check,
680 .erase = fm4_flash_erase,
681 .erase_check = default_flash_blank_check,
682 .write = fm4_flash_write,
683 };

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)