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");
438 retval
= ERROR_FLASH_OPERATION_FAILED
;
442 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
444 retval
= ERROR_FLASH_OPERATION_FAILED
;
448 buffer
+= thisrun_count
* 8;
449 address
+= thisrun_count
* 8;
450 count
-= thisrun_count
;
453 target_free_working_area(target
, source
);
454 target_free_working_area(target
, str7x_info
->write_algorithm
);
456 destroy_reg_param(®_params
[0]);
457 destroy_reg_param(®_params
[1]);
458 destroy_reg_param(®_params
[2]);
459 destroy_reg_param(®_params
[3]);
460 destroy_reg_param(®_params
[4]);
461 destroy_reg_param(®_params
[5]);
466 int str7x_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
468 target_t
*target
= bank
->target
;
469 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
470 u32 dwords_remaining
= (count
/ 8);
471 u32 bytes_remaining
= (count
& 0x00000007);
472 u32 address
= bank
->base
+ offset
;
473 u32 bytes_written
= 0;
476 u32 check_address
= offset
;
479 if (bank
->target
->state
!= TARGET_HALTED
)
481 return ERROR_TARGET_NOT_HALTED
;
486 LOG_WARNING("offset 0x%x breaks required 8-byte alignment", offset
);
487 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
490 for (i
= 0; i
< bank
->num_sectors
; i
++)
492 u32 sec_start
= bank
->sectors
[i
].offset
;
493 u32 sec_end
= sec_start
+ bank
->sectors
[i
].size
;
495 /* check if destination falls within the current sector */
496 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
498 /* check if destination ends in the current sector */
499 if (offset
+ count
< sec_end
)
500 check_address
= offset
+ count
;
502 check_address
= sec_end
;
506 if (check_address
!= offset
+ count
)
507 return ERROR_FLASH_DST_OUT_OF_BANK
;
509 /* clear FLASH_ER register */
510 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
512 /* multiple dwords (8-byte) to be programmed? */
513 if (dwords_remaining
> 0)
515 /* try using a block write */
516 if ((retval
= str7x_write_block(bank
, buffer
, offset
, dwords_remaining
)) != ERROR_OK
)
518 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
520 /* if block write failed (no sufficient working area),
521 * we use normal (slow) single dword accesses */
522 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
524 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
526 /* if an error occured, we examine the reason, and quit */
527 retval
= str7x_result(bank
);
529 LOG_ERROR("flash writing failed with error code: 0x%x", retval
);
530 return ERROR_FLASH_OPERATION_FAILED
;
535 buffer
+= dwords_remaining
* 8;
536 address
+= dwords_remaining
* 8;
537 dwords_remaining
= 0;
541 while (dwords_remaining
> 0)
545 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
548 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
551 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, buffer
+ bytes_written
);
555 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, buffer
+ bytes_written
);
558 /* start programming cycle */
559 cmd
= FLASH_DWPG
| FLASH_WMS
;
560 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
562 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
567 retval
= str7x_result(bank
);
569 if (retval
& FLASH_PGER
)
570 return ERROR_FLASH_OPERATION_FAILED
;
571 else if (retval
& FLASH_WPF
)
572 return ERROR_FLASH_OPERATION_FAILED
;
580 u8 last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
583 while(bytes_remaining
> 0)
585 last_dword
[i
++] = *(buffer
+ bytes_written
);
592 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
595 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
598 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, last_dword
);
602 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, last_dword
+ 4);
605 /* start programming cycle */
606 cmd
= FLASH_DWPG
| FLASH_WMS
;
607 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
609 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
614 retval
= str7x_result(bank
);
616 if (retval
& FLASH_PGER
)
617 return ERROR_FLASH_OPERATION_FAILED
;
618 else if (retval
& FLASH_WPF
)
619 return ERROR_FLASH_OPERATION_FAILED
;
625 int str7x_probe(struct flash_bank_s
*bank
)
630 int str7x_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
635 int str7x_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
637 snprintf(buf
, buf_size
, "str7x flash driver info" );
641 int str7x_handle_disable_jtag_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
644 target_t
*target
= NULL
;
645 str7x_flash_bank_t
*str7x_info
= NULL
;
649 u16 ProtectionLevel
= 0;
654 command_print(cmd_ctx
, "str7x disable_jtag <bank>");
658 bank
= get_flash_bank_by_num(strtoul(args
[0], NULL
, 0));
661 command_print(cmd_ctx
, "str7x disable_jtag <bank> ok");
665 str7x_info
= bank
->driver_priv
;
667 target
= bank
->target
;
669 if (target
->state
!= TARGET_HALTED
)
671 return ERROR_TARGET_NOT_HALTED
;
674 /* first we get protection status */
675 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR0
), &retval
);
677 if (!(retval
& str7x_info
->disable_bit
))
682 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR1
), &retval
);
683 ProtectionRegs
= ~(retval
>> 16);
685 while (((ProtectionRegs
) != 0) && (ProtectionLevel
< 16))
687 ProtectionRegs
>>= 1;
691 if (ProtectionLevel
== 0)
693 flash_cmd
= FLASH_SPR
;
694 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
695 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFB8);
696 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 0xFFFFFFFD);
697 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
698 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
702 flash_cmd
= FLASH_SPR
;
703 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
704 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFBC);
705 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), ~(1<<(15+ProtectionLevel
)));
706 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
707 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)