1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
4 * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
5 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
26 #include <helper/time_support.h>
27 #include <target/image.h>
29 COMMAND_HELPER(flash_command_get_bank
, unsigned name_index
,
30 struct flash_bank
**bank
)
32 const char *name
= CMD_ARGV
[name_index
];
33 *bank
= get_flash_bank_by_name(name
);
38 COMMAND_PARSE_NUMBER(uint
, name
, bank_num
);
40 *bank
= get_flash_bank_by_num(bank_num
);
43 command_print(CMD_CTX
, "flash bank '%s' not found", name
);
44 return ERROR_INVALID_ARGUMENTS
;
50 COMMAND_HANDLER(handle_flash_info_command
)
58 return ERROR_COMMAND_SYNTAX_ERROR
;
61 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
63 for (p
= flash_bank_list(); p
; p
= p
->next
, i
++)
70 /* attempt auto probe */
71 if ((retval
= p
->driver
->auto_probe(p
)) != ERROR_OK
)
74 command_print(CMD_CTX
,
75 "#%" PRIi32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", buswidth %i, chipwidth %i",
82 for (j
= 0; j
< p
->num_sectors
; j
++)
86 if (p
->sectors
[j
].is_protected
== 0)
87 protect_state
= "not protected";
88 else if (p
->sectors
[j
].is_protected
== 1)
89 protect_state
= "protected";
91 protect_state
= "protection state unknown";
93 command_print(CMD_CTX
,
94 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
98 p
->sectors
[j
].size
>> 10,
102 *buf
= '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
103 retval
= p
->driver
->info(p
, buf
, sizeof(buf
));
104 command_print(CMD_CTX
, "%s", buf
);
105 if (retval
!= ERROR_OK
)
106 LOG_ERROR("error retrieving flash info (%d)", retval
);
112 COMMAND_HANDLER(handle_flash_probe_command
)
118 return ERROR_COMMAND_SYNTAX_ERROR
;
122 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
123 struct flash_bank
*p
= get_flash_bank_by_num_noprobe(bank_nr
);
126 if ((retval
= p
->driver
->probe(p
)) == ERROR_OK
)
128 command_print(CMD_CTX
, "flash '%s' found at 0x%8.8" PRIx32
, p
->driver
->name
, p
->base
);
130 else if (retval
== ERROR_FLASH_BANK_INVALID
)
132 command_print(CMD_CTX
, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32
,
133 CMD_ARGV
[0], p
->base
);
137 command_print(CMD_CTX
, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32
,
138 CMD_ARGV
[0], p
->base
);
143 command_print(CMD_CTX
, "flash bank '#%s' is out of bounds", CMD_ARGV
[0]);
149 COMMAND_HANDLER(handle_flash_erase_check_command
)
153 return ERROR_COMMAND_SYNTAX_ERROR
;
156 struct flash_bank
*p
;
157 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
158 if (ERROR_OK
!= retval
)
162 if ((retval
= p
->driver
->erase_check(p
)) == ERROR_OK
)
164 command_print(CMD_CTX
, "successfully checked erase state");
168 command_print(CMD_CTX
, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32
,
169 CMD_ARGV
[0], p
->base
);
172 for (j
= 0; j
< p
->num_sectors
; j
++)
176 if (p
->sectors
[j
].is_erased
== 0)
177 erase_state
= "not erased";
178 else if (p
->sectors
[j
].is_erased
== 1)
179 erase_state
= "erased";
181 erase_state
= "erase state unknown";
183 command_print(CMD_CTX
,
184 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
186 p
->sectors
[j
].offset
,
188 p
->sectors
[j
].size
>> 10,
195 COMMAND_HANDLER(handle_flash_erase_address_command
)
197 struct flash_bank
*p
;
202 struct target
*target
= get_current_target(CMD_CTX
);
205 return ERROR_COMMAND_SYNTAX_ERROR
;
207 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], address
);
208 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], length
);
211 command_print(CMD_CTX
, "Length must be >0");
212 return ERROR_COMMAND_SYNTAX_ERROR
;
215 p
= get_flash_bank_by_addr(target
, address
);
221 /* We can't know if we did a resume + halt, in which case we no longer know the erased state */
224 struct duration bench
;
225 duration_start(&bench
);
227 retval
= flash_erase_address_range(target
, address
, length
);
229 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
231 command_print(CMD_CTX
, "erased address 0x%8.8x (length %i)"
232 " in %fs (%0.3f kb/s)", address
, length
,
233 duration_elapsed(&bench
), duration_kbps(&bench
, length
));
239 COMMAND_HANDLER(handle_flash_protect_check_command
)
242 return ERROR_COMMAND_SYNTAX_ERROR
;
244 struct flash_bank
*p
;
245 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
246 if (ERROR_OK
!= retval
)
249 if ((retval
= p
->driver
->protect_check(p
)) == ERROR_OK
)
251 command_print(CMD_CTX
, "successfully checked protect state");
253 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
255 command_print(CMD_CTX
, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8" PRIx32
, CMD_ARGV
[0], p
->base
);
259 command_print(CMD_CTX
, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8" PRIx32
, CMD_ARGV
[0], p
->base
);
265 static int flash_check_sector_parameters(struct command_context
*cmd_ctx
,
266 uint32_t first
, uint32_t last
, uint32_t num_sectors
)
268 if (!(first
<= last
)) {
269 command_print(cmd_ctx
, "ERROR: "
270 "first sector must be <= last sector");
274 if (!(last
<= (num_sectors
- 1))) {
275 command_print(cmd_ctx
, "ERROR: last sector must be <= %d",
276 (int) num_sectors
- 1);
283 COMMAND_HANDLER(handle_flash_erase_command
)
286 return ERROR_COMMAND_SYNTAX_ERROR
;
292 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
293 struct flash_bank
*p
= get_flash_bank_by_num(bank_nr
);
297 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
298 if (strcmp(CMD_ARGV
[2], "last") == 0)
299 last
= p
->num_sectors
- 1;
301 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
304 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
305 first
, last
, p
->num_sectors
)) != ERROR_OK
)
308 struct duration bench
;
309 duration_start(&bench
);
311 retval
= flash_driver_erase(p
, first
, last
);
313 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
315 command_print(CMD_CTX
, "erased sectors %" PRIu32
" "
316 "through %" PRIu32
" on flash bank %" PRIu32
" "
317 "in %fs", first
, last
, bank_nr
, duration_elapsed(&bench
));
323 COMMAND_HANDLER(handle_flash_protect_command
)
326 return ERROR_COMMAND_SYNTAX_ERROR
;
332 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
333 struct flash_bank
*p
= get_flash_bank_by_num(bank_nr
);
337 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
338 if (strcmp(CMD_ARGV
[2], "last") == 0)
339 last
= p
->num_sectors
- 1;
341 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
344 COMMAND_PARSE_ON_OFF(CMD_ARGV
[3], set
);
347 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
348 first
, last
, p
->num_sectors
)) != ERROR_OK
)
351 retval
= flash_driver_protect(p
, set
, first
, last
);
352 if (retval
== ERROR_OK
) {
353 command_print(CMD_CTX
, "%s protection for sectors %i "
354 "through %i on flash bank %i",
355 (set
) ? "set" : "cleared", (int) first
,
356 (int) last
, (int) bank_nr
);
362 COMMAND_HANDLER(handle_flash_write_image_command
)
364 struct target
*target
= get_current_target(CMD_CTX
);
373 return ERROR_COMMAND_SYNTAX_ERROR
;
376 /* flash auto-erase is disabled by default*/
378 bool auto_unlock
= false;
382 if (strcmp(CMD_ARGV
[0], "erase") == 0)
387 command_print(CMD_CTX
, "auto erase enabled");
388 } else if (strcmp(CMD_ARGV
[0], "unlock") == 0)
393 command_print(CMD_CTX
, "auto unlock enabled");
402 return ERROR_COMMAND_SYNTAX_ERROR
;
407 LOG_ERROR("no target selected");
411 struct duration bench
;
412 duration_start(&bench
);
416 image
.base_address_set
= 1;
417 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], image
.base_address
);
421 image
.base_address_set
= 0;
422 image
.base_address
= 0x0;
425 image
.start_address_set
= 0;
427 retval
= image_open(&image
, CMD_ARGV
[0], (CMD_ARGC
== 3) ? CMD_ARGV
[2] : NULL
);
428 if (retval
!= ERROR_OK
)
433 retval
= flash_write_unlock(target
, &image
, &written
, auto_erase
, auto_unlock
);
434 if (retval
!= ERROR_OK
)
440 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
442 command_print(CMD_CTX
, "wrote %" PRIu32
" byte from file %s "
443 "in %fs (%0.3f kb/s)", written
, CMD_ARGV
[0],
444 duration_elapsed(&bench
), duration_kbps(&bench
, written
));
452 COMMAND_HANDLER(handle_flash_fill_command
)
459 uint32_t cur_size
= 0;
460 uint32_t chunk_count
;
461 struct target
*target
= get_current_target(CMD_CTX
);
464 int retval
= ERROR_OK
;
466 static size_t const chunksize
= 1024;
467 uint8_t *chunk
= malloc(chunksize
);
471 uint8_t *readback
= malloc(chunksize
);
472 if (readback
== NULL
)
481 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
486 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
487 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], pattern
);
488 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], count
);
505 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
509 chunk_count
= MIN(count
, (chunksize
/ wordsize
));
513 for (i
= 0; i
< chunk_count
; i
++)
515 target_buffer_set_u32(target
, chunk
+ i
* wordsize
, pattern
);
519 for (i
= 0; i
< chunk_count
; i
++)
521 target_buffer_set_u16(target
, chunk
+ i
* wordsize
, pattern
);
525 memset(chunk
, pattern
, chunk_count
);
528 LOG_ERROR("BUG: can't happen");
532 struct duration bench
;
533 duration_start(&bench
);
535 for (wrote
= 0; wrote
< (count
*wordsize
); wrote
+= cur_size
)
537 cur_size
= MIN((count
*wordsize
- wrote
), sizeof(chunk
));
538 struct flash_bank
*bank
;
539 bank
= get_flash_bank_by_addr(target
, address
);
545 err
= flash_driver_write(bank
, chunk
, address
- bank
->base
+ wrote
, cur_size
);
552 err
= target_read_buffer(target
, address
+ wrote
, cur_size
, readback
);
560 for (i
= 0; i
< cur_size
; i
++)
562 if (readback
[i
]!=chunk
[i
])
564 LOG_ERROR("Verfication error address 0x%08" PRIx32
", read back 0x%02x, expected 0x%02x",
565 address
+ wrote
+ i
, readback
[i
], chunk
[i
]);
572 if (duration_measure(&bench
) == ERROR_OK
)
574 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes to 0x%8.8" PRIx32
575 " in %fs (%0.3f kb/s)", wrote
, address
,
576 duration_elapsed(&bench
), duration_kbps(&bench
, wrote
));
586 COMMAND_HANDLER(handle_flash_write_bank_command
)
590 struct fileio fileio
;
593 return ERROR_COMMAND_SYNTAX_ERROR
;
595 struct duration bench
;
596 duration_start(&bench
);
598 struct flash_bank
*p
;
599 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
600 if (ERROR_OK
!= retval
)
603 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], offset
);
605 if (fileio_open(&fileio
, CMD_ARGV
[1], FILEIO_READ
, FILEIO_BINARY
) != ERROR_OK
)
610 buffer
= malloc(fileio
.size
);
612 if (fileio_read(&fileio
, fileio
.size
, buffer
, &buf_cnt
) != ERROR_OK
)
615 fileio_close(&fileio
);
619 retval
= flash_driver_write(p
, buffer
, offset
, buf_cnt
);
624 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
626 command_print(CMD_CTX
, "wrote %zu byte from file %s to flash bank %u"
627 " at offset 0x%8.8" PRIx32
" in %fs (%0.3f kb/s)",
628 fileio
.size
, CMD_ARGV
[1], p
->bank_number
, offset
,
629 duration_elapsed(&bench
), duration_kbps(&bench
, fileio
.size
));
632 fileio_close(&fileio
);
637 void flash_set_dirty(void)
639 struct flash_bank
*c
;
642 /* set all flash to require erasing */
643 for (c
= flash_bank_list(); c
; c
= c
->next
)
645 for (i
= 0; i
< c
->num_sectors
; i
++)
647 c
->sectors
[i
].is_erased
= 0;
652 static const struct command_registration flash_exec_command_handlers
[] = {
655 .handler
= &handle_flash_probe_command
,
656 .mode
= COMMAND_EXEC
,
658 .help
= "identify flash bank",
662 .handler
= &handle_flash_info_command
,
663 .mode
= COMMAND_EXEC
,
665 .help
= "print bank information",
668 .name
= "erase_check",
669 .handler
= &handle_flash_erase_check_command
,
670 .mode
= COMMAND_EXEC
,
672 .help
= "check erase state of sectors",
675 .name
= "protect_check",
676 .handler
= &handle_flash_protect_check_command
,
677 .mode
= COMMAND_EXEC
,
679 .help
= "check protection state of sectors",
682 .name
= "erase_sector",
683 .handler
= &handle_flash_erase_command
,
684 .mode
= COMMAND_EXEC
,
685 .usage
= "<bank> <first> <last>",
686 .help
= "erase sectors",
689 .name
= "erase_address",
690 .handler
= &handle_flash_erase_address_command
,
691 .mode
= COMMAND_EXEC
,
692 .usage
= "<address> <length>",
693 .help
= "erase address range",
698 .handler
= &handle_flash_fill_command
,
699 .mode
= COMMAND_EXEC
,
700 .usage
= "<bank> <address> <word_pattern> <count>",
701 .help
= "fill with pattern (no autoerase)",
705 .handler
= &handle_flash_fill_command
,
706 .mode
= COMMAND_EXEC
,
707 .usage
= "<bank> <address> <halfword_pattern> <count>",
708 .help
= "fill with pattern",
712 .handler
= &handle_flash_fill_command
,
713 .mode
= COMMAND_EXEC
,
714 .usage
= "<bank> <address> <byte_pattern> <count>",
715 .help
= "fill with pattern",
719 .name
= "write_bank",
720 .handler
= &handle_flash_write_bank_command
,
721 .mode
= COMMAND_EXEC
,
722 .usage
= "<bank> <file> <offset>",
723 .help
= "write binary data",
726 .name
= "write_image",
727 .handler
= &handle_flash_write_image_command
,
728 .mode
= COMMAND_EXEC
,
729 .usage
= "<bank> [erase] [unlock] <file> [offset] [type]",
730 .help
= "write an image to flash"
734 .handler
= &handle_flash_protect_command
,
735 .mode
= COMMAND_EXEC
,
736 .usage
= "<bank> <first> <last> <on | off>",
737 .help
= "set protection of sectors",
739 COMMAND_REGISTRATION_DONE
742 int flash_init_drivers(struct command_context
*cmd_ctx
)
744 if (!flash_bank_list())
747 struct command
*parent
= command_find_in_context(cmd_ctx
, "flash");
748 return register_commands(cmd_ctx
, parent
, flash_exec_command_handlers
);
752 COMMAND_HANDLER(handle_flash_bank_command
)
756 LOG_ERROR("usage: flash bank <name> <driver> "
757 "<base> <size> <chip_width> <bus_width>");
758 return ERROR_COMMAND_SYNTAX_ERROR
;
760 // save bank name and advance arguments for compatibility
761 const char *bank_name
= *CMD_ARGV
++;
764 struct target
*target
;
765 if ((target
= get_target(CMD_ARGV
[5])) == NULL
)
767 LOG_ERROR("target '%s' not defined", CMD_ARGV
[5]);
771 const char *driver_name
= CMD_ARGV
[0];
772 struct flash_driver
*driver
= flash_driver_find_by_name(driver_name
);
775 /* no matching flash driver found */
776 LOG_ERROR("flash driver '%s' not found", driver_name
);
780 /* register flash specific commands */
781 if (NULL
!= driver
->commands
)
783 int retval
= register_commands(CMD_CTX
, NULL
,
785 if (ERROR_OK
!= retval
)
787 LOG_ERROR("couldn't register '%s' commands",
793 struct flash_bank
*c
= malloc(sizeof(*c
));
794 c
->name
= strdup(bank_name
);
797 c
->driver_priv
= NULL
;
798 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], c
->base
);
799 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], c
->size
);
800 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], c
->chip_width
);
801 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[4], c
->bus_width
);
807 retval
= CALL_COMMAND_HANDLER(driver
->flash_bank_command
, c
);
808 if (ERROR_OK
!= retval
)
810 LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32
,
811 driver_name
, c
->base
);
821 static int jim_flash_banks(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
824 Jim_WrongNumArgs(interp
, 1, argv
, "no arguments to flash_banks command");
828 Jim_Obj
*list
= Jim_NewListObj(interp
, NULL
, 0);
830 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
)
832 Jim_Obj
*elem
= Jim_NewListObj(interp
, NULL
, 0);
834 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "name", -1));
835 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, p
->driver
->name
, -1));
836 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "base", -1));
837 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->base
));
838 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "size", -1));
839 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->size
));
840 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "bus_width", -1));
841 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->bus_width
));
842 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "chip_width", -1));
843 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->chip_width
));
845 Jim_ListAppendElement(interp
, list
, elem
);
848 Jim_SetResult(interp
, list
);
854 COMMAND_HANDLER(handle_flash_init_command
)
857 return ERROR_COMMAND_SYNTAX_ERROR
;
859 static bool flash_initialized
= false;
860 if (flash_initialized
)
862 LOG_INFO("'flash init' has already been called");
865 flash_initialized
= true;
867 LOG_DEBUG("Initializing flash devices...");
868 return flash_init_drivers(CMD_CTX
);
871 static const struct command_registration flash_config_command_handlers
[] = {
874 .handler
= &handle_flash_bank_command
,
875 .mode
= COMMAND_CONFIG
,
876 .usage
= "<name> <driver> <base> <size> "
877 "<chip_width> <bus_width> <target> "
878 "[driver_options ...]",
879 .help
= "Define a new bank with the given name, "
880 "using the specified NOR flash driver.",
884 .mode
= COMMAND_CONFIG
,
885 .handler
= &handle_flash_init_command
,
886 .help
= "initialize flash devices",
891 .jim_handler
= &jim_flash_banks
,
892 .help
= "return information about the flash banks",
894 COMMAND_REGISTRATION_DONE
896 static const struct command_registration flash_command_handlers
[] = {
900 .help
= "NOR flash command group",
901 .chain
= flash_config_command_handlers
,
903 COMMAND_REGISTRATION_DONE
906 int flash_register_commands(struct command_context
*cmd_ctx
)
908 return register_commands(cmd_ctx
, NULL
, flash_command_handlers
);
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)