1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
24 #include "replacements.h"
31 #include "algorithm.h"
32 #include "binarybuffer.h"
38 str7x_mem_layout_t mem_layout_str7bank0
[] = {
39 {0x00000000, 0x02000, 0x01},
40 {0x00002000, 0x02000, 0x02},
41 {0x00004000, 0x02000, 0x04},
42 {0x00006000, 0x02000, 0x08},
43 {0x00008000, 0x08000, 0x10},
44 {0x00010000, 0x10000, 0x20},
45 {0x00020000, 0x10000, 0x40},
46 {0x00030000, 0x10000, 0x80}
49 str7x_mem_layout_t mem_layout_str7bank1
[] = {
50 {0x00000000, 0x02000, 0x10000},
51 {0x00002000, 0x02000, 0x20000}
54 int str7x_register_commands(struct command_context_s
*cmd_ctx
);
55 int str7x_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
);
56 int str7x_erase(struct flash_bank_s
*bank
, int first
, int last
);
57 int str7x_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
);
58 int str7x_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
);
59 int str7x_probe(struct flash_bank_s
*bank
);
60 int str7x_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
61 int str7x_protect_check(struct flash_bank_s
*bank
);
62 int str7x_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
);
64 int str7x_handle_disable_jtag_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
66 flash_driver_t str7x_flash
=
69 .register_commands
= str7x_register_commands
,
70 .flash_bank_command
= str7x_flash_bank_command
,
72 .protect
= str7x_protect
,
75 .auto_probe
= str7x_probe
,
76 .erase_check
= default_flash_blank_check
,
77 .protect_check
= str7x_protect_check
,
81 int str7x_register_commands(struct command_context_s
*cmd_ctx
)
83 command_t
*str7x_cmd
= register_command(cmd_ctx
, NULL
, "str7x", NULL
, COMMAND_ANY
, NULL
);
85 register_command(cmd_ctx
, str7x_cmd
, "disable_jtag", str7x_handle_disable_jtag_command
, COMMAND_EXEC
,
86 "disable jtag access");
91 int str7x_get_flash_adr(struct flash_bank_s
*bank
, u32 reg
)
93 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
94 return (str7x_info
->register_base
| reg
);
97 int str7x_build_block_list(struct flash_bank_s
*bank
)
99 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
103 int b0_sectors
= 0, b1_sectors
= 0;
120 LOG_ERROR("BUG: unknown bank->size encountered");
124 num_sectors
= b0_sectors
+ b1_sectors
;
126 bank
->num_sectors
= num_sectors
;
127 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
128 str7x_info
->sector_bits
= malloc(sizeof(u32
) * num_sectors
);
132 for (i
= 0; i
< b0_sectors
; i
++)
134 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank0
[i
].sector_start
;
135 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank0
[i
].sector_size
;
136 bank
->sectors
[num_sectors
].is_erased
= -1;
137 bank
->sectors
[num_sectors
].is_protected
= 1;
138 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank0
[i
].sector_bit
;
141 for (i
= 0; i
< b1_sectors
; i
++)
143 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank1
[i
].sector_start
;
144 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank1
[i
].sector_size
;
145 bank
->sectors
[num_sectors
].is_erased
= -1;
146 bank
->sectors
[num_sectors
].is_protected
= 1;
147 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank1
[i
].sector_bit
;
153 /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
155 int str7x_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
)
157 str7x_flash_bank_t
*str7x_info
;
161 LOG_WARNING("incomplete flash_bank str7x configuration");
162 return ERROR_FLASH_BANK_INVALID
;
165 str7x_info
= malloc(sizeof(str7x_flash_bank_t
));
166 bank
->driver_priv
= str7x_info
;
168 /* set default bits for str71x flash */
169 str7x_info
->busy_bits
= (FLASH_LOCK
|FLASH_BSYA1
|FLASH_BSYA0
);
170 str7x_info
->disable_bit
= (1<<1);
172 if (strcmp(args
[6], "STR71x") == 0)
174 str7x_info
->register_base
= 0x40100000;
176 else if (strcmp(args
[6], "STR73x") == 0)
178 str7x_info
->register_base
= 0x80100000;
179 str7x_info
->busy_bits
= (FLASH_LOCK
|FLASH_BSYA0
);
181 else if (strcmp(args
[6], "STR75x") == 0)
183 str7x_info
->register_base
= 0x20100000;
184 str7x_info
->disable_bit
= (1<<0);
188 LOG_ERROR("unknown STR7x variant: '%s'", args
[6]);
190 return ERROR_FLASH_BANK_INVALID
;
193 str7x_build_block_list(bank
);
195 str7x_info
->write_algorithm
= NULL
;
200 u32
str7x_status(struct flash_bank_s
*bank
)
202 target_t
*target
= bank
->target
;
205 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), &retval
);
210 u32
str7x_result(struct flash_bank_s
*bank
)
212 target_t
*target
= bank
->target
;
215 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), &retval
);
220 int str7x_protect_check(struct flash_bank_s
*bank
)
222 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
223 target_t
*target
= bank
->target
;
228 if (bank
->target
->state
!= TARGET_HALTED
)
230 return ERROR_TARGET_NOT_HALTED
;
233 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVWPAR
), &retval
);
235 for (i
= 0; i
< bank
->num_sectors
; i
++)
237 if (retval
& str7x_info
->sector_bits
[i
])
238 bank
->sectors
[i
].is_protected
= 0;
240 bank
->sectors
[i
].is_protected
= 1;
246 int str7x_erase(struct flash_bank_s
*bank
, int first
, int last
)
248 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
249 target_t
*target
= bank
->target
;
256 if (bank
->target
->state
!= TARGET_HALTED
)
258 return ERROR_TARGET_NOT_HALTED
;
261 for (i
= first
; i
<= last
; i
++)
263 sectors
|= str7x_info
->sector_bits
[i
];
266 LOG_DEBUG("sectors: 0x%x", sectors
);
268 /* clear FLASH_ER register */
269 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
272 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
275 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
277 cmd
= FLASH_SER
|FLASH_WMS
;
278 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
280 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)){
284 retval
= str7x_result(bank
);
288 LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval
);
289 return ERROR_FLASH_OPERATION_FAILED
;
292 for (i
= first
; i
<= last
; i
++)
293 bank
->sectors
[i
].is_erased
= 1;
298 int str7x_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
300 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
301 target_t
*target
= bank
->target
;
307 if (bank
->target
->state
!= TARGET_HALTED
)
309 return ERROR_TARGET_NOT_HALTED
;
312 protect_blocks
= 0xFFFFFFFF;
316 for (i
= first
; i
<= last
; i
++)
317 protect_blocks
&= ~(str7x_info
->sector_bits
[i
]);
320 /* clear FLASH_ER register */
321 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
324 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
326 cmd
= str7x_get_flash_adr(bank
, FLASH_NVWPAR
);
327 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), cmd
);
329 cmd
= protect_blocks
;
330 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), cmd
);
332 cmd
= FLASH_SPR
|FLASH_WMS
;
333 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
335 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)){
339 retval
= str7x_result(bank
);
341 LOG_DEBUG("retval: 0x%8.8x", retval
);
343 if (retval
& FLASH_ERER
)
344 return ERROR_FLASH_SECTOR_NOT_ERASED
;
345 else if (retval
& FLASH_WPF
)
346 return ERROR_FLASH_OPERATION_FAILED
;
351 int str7x_write_block(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
353 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
354 target_t
*target
= bank
->target
;
355 u32 buffer_size
= 8192;
356 working_area_t
*source
;
357 u32 address
= bank
->base
+ offset
;
358 reg_param_t reg_params
[6];
359 armv4_5_algorithm_t armv4_5_info
;
360 int retval
= ERROR_OK
;
362 u32 str7x_flash_write_code
[] = {
364 0xe3a04201, /* mov r4, #0x10000000 */
365 0xe5824000, /* str r4, [r2, #0x0] */
366 0xe5821010, /* str r1, [r2, #0x10] */
367 0xe4904004, /* ldr r4, [r0], #4 */
368 0xe5824008, /* str r4, [r2, #0x8] */
369 0xe4904004, /* ldr r4, [r0], #4 */
370 0xe582400c, /* str r4, [r2, #0xc] */
371 0xe3a04209, /* mov r4, #0x90000000 */
372 0xe5824000, /* str r4, [r2, #0x0] */
374 0xe5924000, /* ldr r4, [r2, #0x0] */
375 0xe1140005, /* tst r4, r5 */
376 0x1afffffc, /* bne busy */
377 0xe5924014, /* ldr r4, [r2, #0x14] */
378 0xe31400ff, /* tst r4, #0xff */
379 0x03140c01, /* tsteq r4, #0x100 */
380 0x1a000002, /* bne exit */
381 0xe2811008, /* add r1, r1, #0x8 */
382 0xe2533001, /* subs r3, r3, #1 */
383 0x1affffec, /* bne write */
385 0xeafffffe, /* b exit */
388 /* flash write code */
389 if (target_alloc_working_area(target
, 4 * 20, &str7x_info
->write_algorithm
) != ERROR_OK
)
391 LOG_WARNING("no working area available, can't do block memory writes");
392 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
395 target_write_buffer(target
, str7x_info
->write_algorithm
->address
, 20 * 4, (u8
*)str7x_flash_write_code
);
398 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
401 if (buffer_size
<= 256)
403 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
404 if (str7x_info
->write_algorithm
)
405 target_free_working_area(target
, str7x_info
->write_algorithm
);
407 LOG_WARNING("no large enough working area available, can't do block memory writes");
408 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
412 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
413 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
414 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
416 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
417 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
418 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
419 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
420 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
421 init_reg_param(®_params
[5], "r5", 32, PARAM_OUT
);
425 u32 thisrun_count
= (count
> (buffer_size
/ 8)) ? (buffer_size
/ 8) : count
;
427 target_write_buffer(target
, source
->address
, thisrun_count
* 8, buffer
);
429 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
430 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
431 buf_set_u32(reg_params
[2].value
, 0, 32, str7x_get_flash_adr(bank
, FLASH_CR0
));
432 buf_set_u32(reg_params
[3].value
, 0, 32, thisrun_count
);
433 buf_set_u32(reg_params
[5].value
, 0, 32, str7x_info
->busy_bits
);
435 if ((retval
= target
->type
->run_algorithm(target
, 0, NULL
, 6, reg_params
, str7x_info
->write_algorithm
->address
, str7x_info
->write_algorithm
->address
+ (19 * 4), 10000, &armv4_5_info
)) != ERROR_OK
)
437 LOG_ERROR("error executing str7x flash write algorithm");
441 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
443 retval
= ERROR_FLASH_OPERATION_FAILED
;
447 buffer
+= thisrun_count
* 8;
448 address
+= thisrun_count
* 8;
449 count
-= thisrun_count
;
452 target_free_working_area(target
, source
);
453 target_free_working_area(target
, str7x_info
->write_algorithm
);
455 destroy_reg_param(®_params
[0]);
456 destroy_reg_param(®_params
[1]);
457 destroy_reg_param(®_params
[2]);
458 destroy_reg_param(®_params
[3]);
459 destroy_reg_param(®_params
[4]);
460 destroy_reg_param(®_params
[5]);
465 int str7x_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
467 target_t
*target
= bank
->target
;
468 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
469 u32 dwords_remaining
= (count
/ 8);
470 u32 bytes_remaining
= (count
& 0x00000007);
471 u32 address
= bank
->base
+ offset
;
472 u32 bytes_written
= 0;
475 u32 check_address
= offset
;
478 if (bank
->target
->state
!= TARGET_HALTED
)
480 return ERROR_TARGET_NOT_HALTED
;
485 LOG_WARNING("offset 0x%x breaks required 8-byte alignment", offset
);
486 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
489 for (i
= 0; i
< bank
->num_sectors
; i
++)
491 u32 sec_start
= bank
->sectors
[i
].offset
;
492 u32 sec_end
= sec_start
+ bank
->sectors
[i
].size
;
494 /* check if destination falls within the current sector */
495 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
497 /* check if destination ends in the current sector */
498 if (offset
+ count
< sec_end
)
499 check_address
= offset
+ count
;
501 check_address
= sec_end
;
505 if (check_address
!= offset
+ count
)
506 return ERROR_FLASH_DST_OUT_OF_BANK
;
508 /* clear FLASH_ER register */
509 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
511 /* multiple dwords (8-byte) to be programmed? */
512 if (dwords_remaining
> 0)
514 /* try using a block write */
515 if ((retval
= str7x_write_block(bank
, buffer
, offset
, dwords_remaining
)) != ERROR_OK
)
517 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
519 /* if block write failed (no sufficient working area),
520 * we use normal (slow) single dword accesses */
521 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
523 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
525 /* if an error occured, we examine the reason, and quit */
526 retval
= str7x_result(bank
);
528 LOG_ERROR("flash writing failed with error code: 0x%x", retval
);
529 return ERROR_FLASH_OPERATION_FAILED
;
534 buffer
+= dwords_remaining
* 8;
535 address
+= dwords_remaining
* 8;
536 dwords_remaining
= 0;
540 while (dwords_remaining
> 0)
544 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
547 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
550 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, buffer
+ bytes_written
);
554 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, buffer
+ bytes_written
);
557 /* start programming cycle */
558 cmd
= FLASH_DWPG
| FLASH_WMS
;
559 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
561 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
566 retval
= str7x_result(bank
);
568 if (retval
& FLASH_PGER
)
569 return ERROR_FLASH_OPERATION_FAILED
;
570 else if (retval
& FLASH_WPF
)
571 return ERROR_FLASH_OPERATION_FAILED
;
579 u8 last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
582 while(bytes_remaining
> 0)
584 last_dword
[i
++] = *(buffer
+ bytes_written
);
591 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
594 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
597 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, last_dword
);
601 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, last_dword
+ 4);
604 /* start programming cycle */
605 cmd
= FLASH_DWPG
| FLASH_WMS
;
606 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
608 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
613 retval
= str7x_result(bank
);
615 if (retval
& FLASH_PGER
)
616 return ERROR_FLASH_OPERATION_FAILED
;
617 else if (retval
& FLASH_WPF
)
618 return ERROR_FLASH_OPERATION_FAILED
;
624 int str7x_probe(struct flash_bank_s
*bank
)
629 int str7x_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
634 int str7x_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
636 snprintf(buf
, buf_size
, "str7x flash driver info" );
640 int str7x_handle_disable_jtag_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
643 target_t
*target
= NULL
;
644 str7x_flash_bank_t
*str7x_info
= NULL
;
648 u16 ProtectionLevel
= 0;
653 command_print(cmd_ctx
, "str7x disable_jtag <bank>");
657 bank
= get_flash_bank_by_num(strtoul(args
[0], NULL
, 0));
660 command_print(cmd_ctx
, "str7x disable_jtag <bank> ok");
664 str7x_info
= bank
->driver_priv
;
666 target
= bank
->target
;
668 if (target
->state
!= TARGET_HALTED
)
670 return ERROR_TARGET_NOT_HALTED
;
673 /* first we get protection status */
674 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR0
), &retval
);
676 if (!(retval
& str7x_info
->disable_bit
))
681 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR1
), &retval
);
682 ProtectionRegs
= ~(retval
>> 16);
684 while (((ProtectionRegs
) != 0) && (ProtectionLevel
< 16))
686 ProtectionRegs
>>= 1;
690 if (ProtectionLevel
== 0)
692 flash_cmd
= FLASH_SPR
;
693 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
694 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFB8);
695 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 0xFFFFFFFD);
696 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
697 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
701 flash_cmd
= FLASH_SPR
;
702 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
703 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFBC);
704 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), ~(1<<(15+ProtectionLevel
)));
705 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
706 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
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)