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 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
29 #include <target/arm.h>
30 #include <helper/binarybuffer.h>
31 #include <target/algorithm.h>
34 struct str7x_mem_layout mem_layout_str7bank0
[] = {
35 {0x00000000, 0x02000, 0x01},
36 {0x00002000, 0x02000, 0x02},
37 {0x00004000, 0x02000, 0x04},
38 {0x00006000, 0x02000, 0x08},
39 {0x00008000, 0x08000, 0x10},
40 {0x00010000, 0x10000, 0x20},
41 {0x00020000, 0x10000, 0x40},
42 {0x00030000, 0x10000, 0x80}
45 struct str7x_mem_layout mem_layout_str7bank1
[] = {
46 {0x00000000, 0x02000, 0x10000},
47 {0x00002000, 0x02000, 0x20000}
50 static int str7x_get_flash_adr(struct flash_bank
*bank
, uint32_t reg
)
52 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
53 return (str7x_info
->register_base
| reg
);
56 static int str7x_build_block_list(struct flash_bank
*bank
)
58 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
62 int b0_sectors
= 0, b1_sectors
= 0;
79 LOG_ERROR("BUG: unknown bank->size encountered");
83 num_sectors
= b0_sectors
+ b1_sectors
;
85 bank
->num_sectors
= num_sectors
;
86 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_sectors
);
87 str7x_info
->sector_bits
= malloc(sizeof(uint32_t) * num_sectors
);
91 for (i
= 0; i
< b0_sectors
; i
++)
93 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank0
[i
].sector_start
;
94 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank0
[i
].sector_size
;
95 bank
->sectors
[num_sectors
].is_erased
= -1;
96 /* the reset_init handler marks all the sectors unprotected,
97 * matching hardware after reset; keep the driver in sync
99 bank
->sectors
[num_sectors
].is_protected
= 0;
100 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank0
[i
].sector_bit
;
103 for (i
= 0; i
< b1_sectors
; i
++)
105 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank1
[i
].sector_start
;
106 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank1
[i
].sector_size
;
107 bank
->sectors
[num_sectors
].is_erased
= -1;
108 /* the reset_init handler marks all the sectors unprotected,
109 * matching hardware after reset; keep the driver in sync
111 bank
->sectors
[num_sectors
].is_protected
= 0;
112 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank1
[i
].sector_bit
;
118 /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
120 FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command
)
122 struct str7x_flash_bank
*str7x_info
;
126 LOG_WARNING("incomplete flash_bank str7x configuration");
127 return ERROR_FLASH_BANK_INVALID
;
130 str7x_info
= malloc(sizeof(struct str7x_flash_bank
));
131 bank
->driver_priv
= str7x_info
;
133 /* set default bits for str71x flash */
134 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA1
| FLASH_BSYA0
);
135 str7x_info
->disable_bit
= (1 << 1);
137 if (strcmp(CMD_ARGV
[6], "STR71x") == 0)
139 str7x_info
->register_base
= 0x40100000;
141 else if (strcmp(CMD_ARGV
[6], "STR73x") == 0)
143 str7x_info
->register_base
= 0x80100000;
144 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA0
);
146 else if (strcmp(CMD_ARGV
[6], "STR75x") == 0)
148 str7x_info
->register_base
= 0x20100000;
149 str7x_info
->disable_bit
= (1 << 0);
153 LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV
[6]);
155 return ERROR_FLASH_BANK_INVALID
;
158 str7x_build_block_list(bank
);
160 str7x_info
->write_algorithm
= NULL
;
165 static uint32_t str7x_status(struct flash_bank
*bank
)
167 struct target
*target
= bank
->target
;
170 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), &retval
);
175 static uint32_t str7x_result(struct flash_bank
*bank
)
177 struct target
*target
= bank
->target
;
180 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), &retval
);
185 static int str7x_protect_check(struct flash_bank
*bank
)
187 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
188 struct target
*target
= bank
->target
;
193 if (bank
->target
->state
!= TARGET_HALTED
)
195 LOG_ERROR("Target not halted");
196 return ERROR_TARGET_NOT_HALTED
;
199 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVWPAR
), &retval
);
201 for (i
= 0; i
< bank
->num_sectors
; i
++)
203 if (retval
& str7x_info
->sector_bits
[i
])
204 bank
->sectors
[i
].is_protected
= 0;
206 bank
->sectors
[i
].is_protected
= 1;
212 static int str7x_erase(struct flash_bank
*bank
, int first
, int last
)
214 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
215 struct target
*target
= bank
->target
;
220 uint32_t sectors
= 0;
222 if (bank
->target
->state
!= TARGET_HALTED
)
224 LOG_ERROR("Target not halted");
225 return ERROR_TARGET_NOT_HALTED
;
228 for (i
= first
; i
<= last
; i
++)
230 sectors
|= str7x_info
->sector_bits
[i
];
233 LOG_DEBUG("sectors: 0x%" PRIx32
"", sectors
);
235 /* clear FLASH_ER register */
236 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
239 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
242 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
244 cmd
= FLASH_SER
| FLASH_WMS
;
245 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
247 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)) {
251 retval
= str7x_result(bank
);
255 LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32
"", retval
);
256 return ERROR_FLASH_OPERATION_FAILED
;
259 for (i
= first
; i
<= last
; i
++)
260 bank
->sectors
[i
].is_erased
= 1;
265 static int str7x_protect(struct flash_bank
*bank
, int set
, int first
, int last
)
267 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
268 struct target
*target
= bank
->target
;
272 uint32_t protect_blocks
;
274 if (bank
->target
->state
!= TARGET_HALTED
)
276 LOG_ERROR("Target not halted");
277 return ERROR_TARGET_NOT_HALTED
;
280 protect_blocks
= 0xFFFFFFFF;
284 for (i
= first
; i
<= last
; i
++)
285 protect_blocks
&= ~(str7x_info
->sector_bits
[i
]);
288 /* clear FLASH_ER register */
289 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
292 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
294 cmd
= str7x_get_flash_adr(bank
, FLASH_NVWPAR
);
295 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), cmd
);
297 cmd
= protect_blocks
;
298 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), cmd
);
300 cmd
= FLASH_SPR
| FLASH_WMS
;
301 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
303 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)) {
307 retval
= str7x_result(bank
);
309 LOG_DEBUG("retval: 0x%8.8" PRIx32
"", retval
);
311 if (retval
& FLASH_ERER
)
312 return ERROR_FLASH_SECTOR_NOT_ERASED
;
313 else if (retval
& FLASH_WPF
)
314 return ERROR_FLASH_OPERATION_FAILED
;
319 static int str7x_write_block(struct flash_bank
*bank
, uint8_t *buffer
,
320 uint32_t offset
, uint32_t count
)
322 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
323 struct target
*target
= bank
->target
;
324 uint32_t buffer_size
= 32768;
325 struct working_area
*source
;
326 uint32_t address
= bank
->base
+ offset
;
327 struct reg_param reg_params
[6];
328 struct arm_algorithm armv4_5_info
;
329 int retval
= ERROR_OK
;
331 static const uint32_t str7x_flash_write_code
[] = {
333 0xe3a04201, /* mov r4, #0x10000000 */
334 0xe5824000, /* str r4, [r2, #0x0] */
335 0xe5821010, /* str r1, [r2, #0x10] */
336 0xe4904004, /* ldr r4, [r0], #4 */
337 0xe5824008, /* str r4, [r2, #0x8] */
338 0xe4904004, /* ldr r4, [r0], #4 */
339 0xe582400c, /* str r4, [r2, #0xc] */
340 0xe3a04209, /* mov r4, #0x90000000 */
341 0xe5824000, /* str r4, [r2, #0x0] */
343 0xe5924000, /* ldr r4, [r2, #0x0] */
344 0xe1140005, /* tst r4, r5 */
345 0x1afffffc, /* bne busy */
346 0xe5924014, /* ldr r4, [r2, #0x14] */
347 0xe31400ff, /* tst r4, #0xff */
348 0x03140c01, /* tsteq r4, #0x100 */
349 0x1a000002, /* bne exit */
350 0xe2811008, /* add r1, r1, #0x8 */
351 0xe2533001, /* subs r3, r3, #1 */
352 0x1affffec, /* bne write */
354 0xeafffffe, /* b exit */
357 /* flash write code */
358 if (target_alloc_working_area(target
, sizeof(str7x_flash_write_code
),
359 &str7x_info
->write_algorithm
) != ERROR_OK
)
361 LOG_WARNING("no working area available, can't do block memory writes");
362 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
365 target_write_buffer(target
, str7x_info
->write_algorithm
->address
,
366 sizeof(str7x_flash_write_code
),
367 (uint8_t*)str7x_flash_write_code
);
370 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
373 if (buffer_size
<= 256)
375 /* if we already allocated the writing code, but failed to get a
376 * buffer, free the algorithm */
377 if (str7x_info
->write_algorithm
)
378 target_free_working_area(target
, str7x_info
->write_algorithm
);
380 LOG_WARNING("no large enough working area available, can't do block memory writes");
381 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
385 armv4_5_info
.common_magic
= ARM_COMMON_MAGIC
;
386 armv4_5_info
.core_mode
= ARM_MODE_SVC
;
387 armv4_5_info
.core_state
= ARM_STATE_ARM
;
389 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
390 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
391 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
392 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
393 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
394 init_reg_param(®_params
[5], "r5", 32, PARAM_OUT
);
398 uint32_t thisrun_count
= (count
> (buffer_size
/ 8)) ? (buffer_size
/ 8) : count
;
400 target_write_buffer(target
, source
->address
, thisrun_count
* 8, buffer
);
402 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
403 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
404 buf_set_u32(reg_params
[2].value
, 0, 32, str7x_get_flash_adr(bank
, FLASH_CR0
));
405 buf_set_u32(reg_params
[3].value
, 0, 32, thisrun_count
);
406 buf_set_u32(reg_params
[5].value
, 0, 32, str7x_info
->busy_bits
);
408 if ((retval
= target_run_algorithm(target
, 0, NULL
, 6, reg_params
,
409 str7x_info
->write_algorithm
->address
,
410 str7x_info
->write_algorithm
->address
+ (sizeof(str7x_flash_write_code
) - 4),
411 10000, &armv4_5_info
)) != ERROR_OK
)
413 LOG_ERROR("error executing str7x flash write algorithm");
414 retval
= ERROR_FLASH_OPERATION_FAILED
;
418 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
420 retval
= ERROR_FLASH_OPERATION_FAILED
;
424 buffer
+= thisrun_count
* 8;
425 address
+= thisrun_count
* 8;
426 count
-= thisrun_count
;
429 target_free_working_area(target
, source
);
430 target_free_working_area(target
, str7x_info
->write_algorithm
);
432 destroy_reg_param(®_params
[0]);
433 destroy_reg_param(®_params
[1]);
434 destroy_reg_param(®_params
[2]);
435 destroy_reg_param(®_params
[3]);
436 destroy_reg_param(®_params
[4]);
437 destroy_reg_param(®_params
[5]);
442 static int str7x_write(struct flash_bank
*bank
, uint8_t *buffer
,
443 uint32_t offset
, uint32_t count
)
445 struct target
*target
= bank
->target
;
446 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
447 uint32_t dwords_remaining
= (count
/ 8);
448 uint32_t bytes_remaining
= (count
& 0x00000007);
449 uint32_t address
= bank
->base
+ offset
;
450 uint32_t bytes_written
= 0;
453 uint32_t check_address
= offset
;
456 if (bank
->target
->state
!= TARGET_HALTED
)
458 LOG_ERROR("Target not halted");
459 return ERROR_TARGET_NOT_HALTED
;
464 LOG_WARNING("offset 0x%" PRIx32
" breaks required 8-byte alignment", offset
);
465 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
468 for (i
= 0; i
< bank
->num_sectors
; i
++)
470 uint32_t sec_start
= bank
->sectors
[i
].offset
;
471 uint32_t sec_end
= sec_start
+ bank
->sectors
[i
].size
;
473 /* check if destination falls within the current sector */
474 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
476 /* check if destination ends in the current sector */
477 if (offset
+ count
< sec_end
)
478 check_address
= offset
+ count
;
480 check_address
= sec_end
;
484 if (check_address
!= offset
+ count
)
485 return ERROR_FLASH_DST_OUT_OF_BANK
;
487 /* clear FLASH_ER register */
488 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
490 /* multiple dwords (8-byte) to be programmed? */
491 if (dwords_remaining
> 0)
493 /* try using a block write */
494 if ((retval
= str7x_write_block(bank
, buffer
, offset
,
495 dwords_remaining
)) != ERROR_OK
)
497 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
499 /* if block write failed (no sufficient working area),
500 * we use normal (slow) single dword accesses */
501 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
503 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
505 /* if an error occured, we examine the reason, and quit */
506 retval
= str7x_result(bank
);
508 LOG_ERROR("flash writing failed with error code: 0x%x", retval
);
509 return ERROR_FLASH_OPERATION_FAILED
;
514 buffer
+= dwords_remaining
* 8;
515 address
+= dwords_remaining
* 8;
516 dwords_remaining
= 0;
520 while (dwords_remaining
> 0)
524 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
527 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
530 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
),
531 4, 1, buffer
+ bytes_written
);
535 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
),
536 4, 1, buffer
+ bytes_written
);
539 /* start programming cycle */
540 cmd
= FLASH_DWPG
| FLASH_WMS
;
541 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
543 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
548 retval
= str7x_result(bank
);
550 if (retval
& FLASH_PGER
)
551 return ERROR_FLASH_OPERATION_FAILED
;
552 else if (retval
& FLASH_WPF
)
553 return ERROR_FLASH_OPERATION_FAILED
;
561 uint8_t last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
564 while (bytes_remaining
> 0)
566 last_dword
[i
++] = *(buffer
+ bytes_written
);
573 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
576 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
579 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
),
584 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
),
585 4, 1, last_dword
+ 4);
588 /* start programming cycle */
589 cmd
= FLASH_DWPG
| FLASH_WMS
;
590 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
592 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
597 retval
= str7x_result(bank
);
599 if (retval
& FLASH_PGER
)
600 return ERROR_FLASH_OPERATION_FAILED
;
601 else if (retval
& FLASH_WPF
)
602 return ERROR_FLASH_OPERATION_FAILED
;
608 static int str7x_probe(struct flash_bank
*bank
)
614 COMMAND_HANDLER(str7x_handle_part_id_command
)
620 static int str7x_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
622 snprintf(buf
, buf_size
, "str7x flash driver info");
623 /* STR7x flash doesn't support sector protection interrogation.
624 * FLASH_NVWPAR acts as a write only register; its read value
625 * doesn't reflect the actual protection state of the sectors.
627 LOG_WARNING("STR7x flash lock information might not be correct "
628 "due to hardware limitations.");
632 COMMAND_HANDLER(str7x_handle_disable_jtag_command
)
634 struct target
*target
= NULL
;
635 struct str7x_flash_bank
*str7x_info
= NULL
;
638 uint16_t ProtectionLevel
= 0;
639 uint16_t ProtectionRegs
;
643 command_print(CMD_CTX
, "str7x disable_jtag <bank>");
647 struct flash_bank
*bank
;
648 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
649 if (ERROR_OK
!= retval
)
652 str7x_info
= bank
->driver_priv
;
654 target
= bank
->target
;
656 if (target
->state
!= TARGET_HALTED
)
658 LOG_ERROR("Target not halted");
659 return ERROR_TARGET_NOT_HALTED
;
662 /* first we get protection status */
664 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR0
), ®
);
666 if (!(reg
& str7x_info
->disable_bit
))
671 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR1
), ®
);
672 ProtectionRegs
= ~(reg
>> 16);
674 while (((ProtectionRegs
) != 0) && (ProtectionLevel
< 16))
676 ProtectionRegs
>>= 1;
680 if (ProtectionLevel
== 0)
682 flash_cmd
= FLASH_SPR
;
683 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
684 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFB8);
685 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 0xFFFFFFFD);
686 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
687 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
691 flash_cmd
= FLASH_SPR
;
692 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
693 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFBC);
694 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
),
695 ~(1 << (15 + ProtectionLevel
)));
696 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
697 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
703 static const struct command_registration str7x_exec_command_handlers
[] = {
705 .name
= "disable_jtag",
706 .handler
= str7x_handle_disable_jtag_command
,
707 .mode
= COMMAND_EXEC
,
708 .help
= "disable jtag access",
710 COMMAND_REGISTRATION_DONE
713 static const struct command_registration str7x_command_handlers
[] = {
717 .help
= "str7x flash command group",
718 .chain
= str7x_exec_command_handlers
,
720 COMMAND_REGISTRATION_DONE
723 struct flash_driver str7x_flash
= {
725 .commands
= str7x_command_handlers
,
726 .flash_bank_command
= str7x_flash_bank_command
,
727 .erase
= str7x_erase
,
728 .protect
= str7x_protect
,
729 .write
= str7x_write
,
730 .probe
= str7x_probe
,
731 .auto_probe
= str7x_probe
,
732 .erase_check
= default_flash_blank_check
,
733 .protect_check
= str7x_protect_check
,
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)