1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
8 * Copyright (C) 2010 Øyvind Harboe *
9 * oyvind.harboe@zylin.com *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
32 #include <target/arm.h>
33 #include <helper/binarybuffer.h>
34 #include <target/algorithm.h>
37 static struct str7x_mem_layout mem_layout_str7bank0
[] = {
38 {0x00000000, 0x02000, 0x01},
39 {0x00002000, 0x02000, 0x02},
40 {0x00004000, 0x02000, 0x04},
41 {0x00006000, 0x02000, 0x08},
42 {0x00008000, 0x08000, 0x10},
43 {0x00010000, 0x10000, 0x20},
44 {0x00020000, 0x10000, 0x40},
45 {0x00030000, 0x10000, 0x80}
48 static struct str7x_mem_layout mem_layout_str7bank1
[] = {
49 {0x00000000, 0x02000, 0x10000},
50 {0x00002000, 0x02000, 0x20000}
53 static int str7x_get_flash_adr(struct flash_bank
*bank
, uint32_t reg
)
55 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
56 return (str7x_info
->register_base
| reg
);
59 static int str7x_build_block_list(struct flash_bank
*bank
)
61 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
65 int b0_sectors
= 0, b1_sectors
= 0;
82 LOG_ERROR("BUG: unknown bank->size encountered");
86 num_sectors
= b0_sectors
+ b1_sectors
;
88 bank
->num_sectors
= num_sectors
;
89 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_sectors
);
90 str7x_info
->sector_bits
= malloc(sizeof(uint32_t) * num_sectors
);
94 for (i
= 0; i
< b0_sectors
; i
++)
96 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank0
[i
].sector_start
;
97 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank0
[i
].sector_size
;
98 bank
->sectors
[num_sectors
].is_erased
= -1;
99 /* the reset_init handler marks all the sectors unprotected,
100 * matching hardware after reset; keep the driver in sync
102 bank
->sectors
[num_sectors
].is_protected
= 0;
103 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank0
[i
].sector_bit
;
106 for (i
= 0; i
< b1_sectors
; i
++)
108 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank1
[i
].sector_start
;
109 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank1
[i
].sector_size
;
110 bank
->sectors
[num_sectors
].is_erased
= -1;
111 /* the reset_init handler marks all the sectors unprotected,
112 * matching hardware after reset; keep the driver in sync
114 bank
->sectors
[num_sectors
].is_protected
= 0;
115 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank1
[i
].sector_bit
;
121 /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
123 FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command
)
125 struct str7x_flash_bank
*str7x_info
;
129 LOG_WARNING("incomplete flash_bank str7x configuration");
130 return ERROR_FLASH_BANK_INVALID
;
133 str7x_info
= malloc(sizeof(struct str7x_flash_bank
));
134 bank
->driver_priv
= str7x_info
;
136 /* set default bits for str71x flash */
137 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA1
| FLASH_BSYA0
);
138 str7x_info
->disable_bit
= (1 << 1);
140 if (strcmp(CMD_ARGV
[6], "STR71x") == 0)
142 str7x_info
->register_base
= 0x40100000;
144 else if (strcmp(CMD_ARGV
[6], "STR73x") == 0)
146 str7x_info
->register_base
= 0x80100000;
147 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA0
);
149 else if (strcmp(CMD_ARGV
[6], "STR75x") == 0)
151 str7x_info
->register_base
= 0x20100000;
152 str7x_info
->disable_bit
= (1 << 0);
156 LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV
[6]);
158 return ERROR_FLASH_BANK_INVALID
;
161 str7x_build_block_list(bank
);
163 str7x_info
->write_algorithm
= NULL
;
168 /* wait for flash to become idle or report errors.
170 FIX!!! what's the maximum timeout??? The documentation doesn't
171 state any maximum time.... by inspection it seems > 1000ms is to be
174 10000ms is long enough that it should cover anything, yet not
175 quite be equivalent to an infinite loop.
178 static int str7x_waitbusy(struct flash_bank
*bank
)
182 struct target
*target
= bank
->target
;
183 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
185 for (i
= 0 ; i
< 10000; i
++)
188 err
= target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), &retval
);
192 if ((retval
& str7x_info
->busy_bits
) == 0)
197 LOG_ERROR("Timed out waiting for str7x flash");
202 static int str7x_result(struct flash_bank
*bank
)
204 struct target
*target
= bank
->target
;
208 err
= target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), &retval
);
212 if (retval
& FLASH_WPF
)
214 LOG_ERROR("str7x hw write protection set");
217 if (retval
& FLASH_RESER
)
219 LOG_ERROR("str7x suspended program erase not resumed");
222 if (retval
& FLASH_10ER
)
224 LOG_ERROR("str7x trying to set bit to 1 when it is already 0");
227 if (retval
& FLASH_PGER
)
229 LOG_ERROR("str7x program error");
232 if (retval
& FLASH_ERER
)
234 LOG_ERROR("str7x erase error");
239 if (retval
& FLASH_ERR
)
241 /* this should always be set if one of the others are set... */
242 LOG_ERROR("str7x write operation failed / bad setup");
248 LOG_ERROR("FLASH_ER register contents: 0x%" PRIx32
, retval
);
254 static int str7x_protect_check(struct flash_bank
*bank
)
256 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
257 struct target
*target
= bank
->target
;
262 if (bank
->target
->state
!= TARGET_HALTED
)
264 LOG_ERROR("Target not halted");
265 return ERROR_TARGET_NOT_HALTED
;
268 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVWPAR
), &retval
);
270 for (i
= 0; i
< bank
->num_sectors
; i
++)
272 if (retval
& str7x_info
->sector_bits
[i
])
273 bank
->sectors
[i
].is_protected
= 0;
275 bank
->sectors
[i
].is_protected
= 1;
281 static int str7x_erase(struct flash_bank
*bank
, int first
, int last
)
283 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
284 struct target
*target
= bank
->target
;
288 uint32_t sectors
= 0;
291 if (bank
->target
->state
!= TARGET_HALTED
)
293 LOG_ERROR("Target not halted");
294 return ERROR_TARGET_NOT_HALTED
;
297 for (i
= first
; i
<= last
; i
++)
299 sectors
|= str7x_info
->sector_bits
[i
];
302 LOG_DEBUG("sectors: 0x%" PRIx32
"", sectors
);
304 /* clear FLASH_ER register */
305 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
310 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
315 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
319 cmd
= FLASH_SER
| FLASH_WMS
;
320 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
324 err
= str7x_waitbusy(bank
);
328 err
= str7x_result(bank
);
332 for (i
= first
; i
<= last
; i
++)
333 bank
->sectors
[i
].is_erased
= 1;
338 static int str7x_protect(struct flash_bank
*bank
, int set
, int first
, int last
)
340 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
341 struct target
*target
= bank
->target
;
344 uint32_t protect_blocks
;
346 if (bank
->target
->state
!= TARGET_HALTED
)
348 LOG_ERROR("Target not halted");
349 return ERROR_TARGET_NOT_HALTED
;
352 protect_blocks
= 0xFFFFFFFF;
356 for (i
= first
; i
<= last
; i
++)
357 protect_blocks
&= ~(str7x_info
->sector_bits
[i
]);
360 /* clear FLASH_ER register */
362 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
367 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
371 cmd
= str7x_get_flash_adr(bank
, FLASH_NVWPAR
);
372 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), cmd
);
376 cmd
= protect_blocks
;
377 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), cmd
);
381 cmd
= FLASH_SPR
| FLASH_WMS
;
382 err
= target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
386 err
= str7x_waitbusy(bank
);
390 err
= str7x_result(bank
);
397 static int str7x_write_block(struct flash_bank
*bank
, uint8_t *buffer
,
398 uint32_t offset
, uint32_t count
)
400 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
401 struct target
*target
= bank
->target
;
402 uint32_t buffer_size
= 32768;
403 struct working_area
*source
;
404 uint32_t address
= bank
->base
+ offset
;
405 struct reg_param reg_params
[6];
406 struct arm_algorithm armv4_5_info
;
407 int retval
= ERROR_OK
;
409 /* see contib/loaders/flash/str7x.s for src */
411 static const uint32_t str7x_flash_write_code
[] = {
413 0xe3a04201, /* mov r4, #0x10000000 */
414 0xe5824000, /* str r4, [r2, #0x0] */
415 0xe5821010, /* str r1, [r2, #0x10] */
416 0xe4904004, /* ldr r4, [r0], #4 */
417 0xe5824008, /* str r4, [r2, #0x8] */
418 0xe4904004, /* ldr r4, [r0], #4 */
419 0xe582400c, /* str r4, [r2, #0xc] */
420 0xe3a04209, /* mov r4, #0x90000000 */
421 0xe5824000, /* str r4, [r2, #0x0] */
423 0xe5924000, /* ldr r4, [r2, #0x0] */
424 0xe1140005, /* tst r4, r5 */
425 0x1afffffc, /* bne busy */
426 0xe5924014, /* ldr r4, [r2, #0x14] */
427 0xe31400ff, /* tst r4, #0xff */
428 0x03140c01, /* tsteq r4, #0x100 */
429 0x1a000002, /* bne exit */
430 0xe2811008, /* add r1, r1, #0x8 */
431 0xe2533001, /* subs r3, r3, #1 */
432 0x1affffec, /* bne write */
434 0xeafffffe, /* b exit */
437 /* flash write code */
438 if (target_alloc_working_area_try(target
, sizeof(str7x_flash_write_code
),
439 &str7x_info
->write_algorithm
) != ERROR_OK
)
441 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
444 target_write_buffer(target
, str7x_info
->write_algorithm
->address
,
445 sizeof(str7x_flash_write_code
),
446 (uint8_t*)str7x_flash_write_code
);
449 while (target_alloc_working_area_try(target
, buffer_size
, &source
) != ERROR_OK
)
452 if (buffer_size
<= 256)
454 /* if we already allocated the writing code, but failed to get a
455 * buffer, free the algorithm */
456 if (str7x_info
->write_algorithm
)
457 target_free_working_area(target
, str7x_info
->write_algorithm
);
459 LOG_WARNING("no large enough working area available, can't do block memory writes");
460 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
464 armv4_5_info
.common_magic
= ARM_COMMON_MAGIC
;
465 armv4_5_info
.core_mode
= ARM_MODE_SVC
;
466 armv4_5_info
.core_state
= ARM_STATE_ARM
;
468 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
469 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
470 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
471 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
472 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
473 init_reg_param(®_params
[5], "r5", 32, PARAM_OUT
);
477 uint32_t thisrun_count
= (count
> (buffer_size
/ 8)) ? (buffer_size
/ 8) : count
;
479 target_write_buffer(target
, source
->address
, thisrun_count
* 8, buffer
);
481 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
482 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
483 buf_set_u32(reg_params
[2].value
, 0, 32, str7x_get_flash_adr(bank
, FLASH_CR0
));
484 buf_set_u32(reg_params
[3].value
, 0, 32, thisrun_count
);
485 buf_set_u32(reg_params
[5].value
, 0, 32, str7x_info
->busy_bits
);
487 if ((retval
= target_run_algorithm(target
, 0, NULL
, 6, reg_params
,
488 str7x_info
->write_algorithm
->address
,
489 str7x_info
->write_algorithm
->address
+ (sizeof(str7x_flash_write_code
) - 4),
490 10000, &armv4_5_info
)) != ERROR_OK
)
495 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
497 retval
= str7x_result(bank
);
501 buffer
+= thisrun_count
* 8;
502 address
+= thisrun_count
* 8;
503 count
-= thisrun_count
;
506 target_free_working_area(target
, source
);
507 target_free_working_area(target
, str7x_info
->write_algorithm
);
509 destroy_reg_param(®_params
[0]);
510 destroy_reg_param(®_params
[1]);
511 destroy_reg_param(®_params
[2]);
512 destroy_reg_param(®_params
[3]);
513 destroy_reg_param(®_params
[4]);
514 destroy_reg_param(®_params
[5]);
519 static int str7x_write(struct flash_bank
*bank
, uint8_t *buffer
,
520 uint32_t offset
, uint32_t count
)
522 struct target
*target
= bank
->target
;
523 uint32_t dwords_remaining
= (count
/ 8);
524 uint32_t bytes_remaining
= (count
& 0x00000007);
525 uint32_t address
= bank
->base
+ offset
;
526 uint32_t bytes_written
= 0;
529 uint32_t check_address
= offset
;
532 if (bank
->target
->state
!= TARGET_HALTED
)
534 LOG_ERROR("Target not halted");
535 return ERROR_TARGET_NOT_HALTED
;
540 LOG_WARNING("offset 0x%" PRIx32
" breaks required 8-byte alignment", offset
);
541 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
544 for (i
= 0; i
< bank
->num_sectors
; i
++)
546 uint32_t sec_start
= bank
->sectors
[i
].offset
;
547 uint32_t sec_end
= sec_start
+ bank
->sectors
[i
].size
;
549 /* check if destination falls within the current sector */
550 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
552 /* check if destination ends in the current sector */
553 if (offset
+ count
< sec_end
)
554 check_address
= offset
+ count
;
556 check_address
= sec_end
;
560 if (check_address
!= offset
+ count
)
561 return ERROR_FLASH_DST_OUT_OF_BANK
;
563 /* clear FLASH_ER register */
564 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
566 /* multiple dwords (8-byte) to be programmed? */
567 if (dwords_remaining
> 0)
569 /* try using a block write */
570 if ((retval
= str7x_write_block(bank
, buffer
, offset
,
571 dwords_remaining
)) != ERROR_OK
)
573 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
575 /* if block write failed (no sufficient working area),
576 * we use normal (slow) single dword accesses */
577 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
585 buffer
+= dwords_remaining
* 8;
586 address
+= dwords_remaining
* 8;
587 dwords_remaining
= 0;
591 while (dwords_remaining
> 0)
595 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
598 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
601 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
),
602 4, 1, buffer
+ bytes_written
);
606 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
),
607 4, 1, buffer
+ bytes_written
);
610 /* start programming cycle */
611 cmd
= FLASH_DWPG
| FLASH_WMS
;
612 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
615 err
= str7x_waitbusy(bank
);
619 err
= str7x_result(bank
);
629 uint8_t last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
632 while (bytes_remaining
> 0)
634 last_dword
[i
++] = *(buffer
+ bytes_written
);
641 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
644 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
647 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
),
652 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
),
653 4, 1, last_dword
+ 4);
656 /* start programming cycle */
657 cmd
= FLASH_DWPG
| FLASH_WMS
;
658 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
661 err
= str7x_waitbusy(bank
);
665 err
= str7x_result(bank
);
673 static int str7x_probe(struct flash_bank
*bank
)
679 COMMAND_HANDLER(str7x_handle_part_id_command
)
685 static int get_str7x_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
687 snprintf(buf
, buf_size
, "str7x flash driver info");
688 /* STR7x flash doesn't support sector protection interrogation.
689 * FLASH_NVWPAR acts as a write only register; its read value
690 * doesn't reflect the actual protection state of the sectors.
692 LOG_WARNING("STR7x flash lock information might not be correct "
693 "due to hardware limitations.");
697 COMMAND_HANDLER(str7x_handle_disable_jtag_command
)
699 struct target
*target
= NULL
;
700 struct str7x_flash_bank
*str7x_info
= NULL
;
703 uint16_t ProtectionLevel
= 0;
704 uint16_t ProtectionRegs
;
708 command_print(CMD_CTX
, "str7x disable_jtag <bank>");
712 struct flash_bank
*bank
;
713 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
714 if (ERROR_OK
!= retval
)
717 str7x_info
= bank
->driver_priv
;
719 target
= bank
->target
;
721 if (target
->state
!= TARGET_HALTED
)
723 LOG_ERROR("Target not halted");
724 return ERROR_TARGET_NOT_HALTED
;
727 /* first we get protection status */
729 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR0
), ®
);
731 if (!(reg
& str7x_info
->disable_bit
))
736 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR1
), ®
);
737 ProtectionRegs
= ~(reg
>> 16);
739 while (((ProtectionRegs
) != 0) && (ProtectionLevel
< 16))
741 ProtectionRegs
>>= 1;
745 if (ProtectionLevel
== 0)
747 flash_cmd
= FLASH_SPR
;
748 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
749 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFB8);
750 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 0xFFFFFFFD);
751 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
752 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
756 flash_cmd
= FLASH_SPR
;
757 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
758 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFBC);
759 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
),
760 ~(1 << (15 + ProtectionLevel
)));
761 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
762 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
768 static const struct command_registration str7x_exec_command_handlers
[] = {
770 .name
= "disable_jtag",
771 .handler
= str7x_handle_disable_jtag_command
,
772 .mode
= COMMAND_EXEC
,
773 .help
= "disable jtag access",
775 COMMAND_REGISTRATION_DONE
778 static const struct command_registration str7x_command_handlers
[] = {
782 .help
= "str7x flash command group",
783 .chain
= str7x_exec_command_handlers
,
785 COMMAND_REGISTRATION_DONE
788 struct flash_driver str7x_flash
= {
790 .commands
= str7x_command_handlers
,
791 .flash_bank_command
= str7x_flash_bank_command
,
792 .erase
= str7x_erase
,
793 .protect
= str7x_protect
,
794 .write
= str7x_write
,
795 .read
= default_flash_read
,
796 .probe
= str7x_probe
,
797 .auto_probe
= str7x_probe
,
798 .erase_check
= default_flash_blank_check
,
799 .protect_check
= str7x_protect_check
,
800 .info
= get_str7x_info
,
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)