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
[] = {
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},
47 {0x000C0000, 0x02000, 0x10000},
48 {0x000C2000, 0x02000, 0x20000},
51 int str7x_register_commands(struct command_context_s
*cmd_ctx
);
52 int str7x_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
);
53 int str7x_erase(struct flash_bank_s
*bank
, int first
, int last
);
54 int str7x_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
);
55 int str7x_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
);
56 int str7x_probe(struct flash_bank_s
*bank
);
57 int str7x_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
58 int str7x_protect_check(struct flash_bank_s
*bank
);
59 int str7x_erase_check(struct flash_bank_s
*bank
);
60 int str7x_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
);
62 flash_driver_t str7x_flash
=
65 .register_commands
= str7x_register_commands
,
66 .flash_bank_command
= str7x_flash_bank_command
,
68 .protect
= str7x_protect
,
71 .erase_check
= str7x_erase_check
,
72 .protect_check
= str7x_protect_check
,
76 int str7x_register_commands(struct command_context_s
*cmd_ctx
)
82 int str7x_get_flash_adr(struct flash_bank_s
*bank
, u32 reg
)
84 return (bank
->base
| reg
);
87 int str7x_build_block_list(struct flash_bank_s
*bank
)
89 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
92 int num_sectors
= 0, b0_sectors
= 0, b1_sectors
= 0;
109 ERROR("BUG: unknown bank->size encountered");
113 if( str7x_info
->bank1
== 1 )
118 num_sectors
= b0_sectors
+ b1_sectors
;
120 bank
->num_sectors
= num_sectors
;
121 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
122 str7x_info
->sector_bits
= malloc(sizeof(u32
) * num_sectors
);
123 str7x_info
->sector_bank
= malloc(sizeof(u32
) * num_sectors
);
127 for (i
= 0; i
< b0_sectors
; i
++)
129 bank
->sectors
[num_sectors
].offset
= mem_layout
[i
].sector_start
;
130 bank
->sectors
[num_sectors
].size
= mem_layout
[i
].sector_size
;
131 bank
->sectors
[num_sectors
].is_erased
= -1;
132 bank
->sectors
[num_sectors
].is_protected
= 1;
133 str7x_info
->sector_bank
[num_sectors
] = 0;
134 str7x_info
->sector_bits
[num_sectors
++] = mem_layout
[i
].sector_bit
;
139 for (i
= 8; i
< 10; i
++)
141 bank
->sectors
[num_sectors
].offset
= mem_layout
[i
].sector_start
;
142 bank
->sectors
[num_sectors
].size
= mem_layout
[i
].sector_size
;
143 bank
->sectors
[num_sectors
].is_erased
= -1;
144 bank
->sectors
[num_sectors
].is_protected
= 1;
145 str7x_info
->sector_bank
[num_sectors
] = 1;
146 str7x_info
->sector_bits
[num_sectors
++] = mem_layout
[i
].sector_bit
;
153 /* flash bank str7x <base> <size> 0 0 <str71_variant> <target#>
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 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 if (strcmp(args
[5], "STR71x") == 0)
170 str7x_info
->bank1
= 1;
171 if (bank
->base
!= 0x40000000)
173 WARNING("overriding flash base address for STR71x device with 0x40000000");
174 bank
->base
= 0x40000000;
177 else if (strcmp(args
[5], "STR73x") == 0)
179 str7x_info
->bank1
= 0;
180 if (bank
->base
!= 0x80000000)
182 WARNING("overriding flash base address for STR73x device with 0x80000000");
183 bank
->base
= 0x80000000;
186 else if (strcmp(args
[5], "STR75x") == 0)
188 str7x_info
->bank1
= 1;
189 if (bank
->base
!= 0x20000000)
191 WARNING("overriding flash base address for STR75x device with 0x20000000");
192 bank
->base
= 0x20000000;
197 ERROR("unknown STR7x variant");
199 return ERROR_FLASH_BANK_INVALID
;
202 str7x_info
->target
= get_target_by_num(strtoul(args
[6], NULL
, 0));
203 if (!str7x_info
->target
)
205 ERROR("no target '%s' configured", args
[6]);
209 str7x_build_block_list(bank
);
211 str7x_info
->write_algorithm
= NULL
;
216 u32
str7x_status(struct flash_bank_s
*bank
)
218 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
219 target_t
*target
= str7x_info
->target
;
222 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), &retval
);
227 u32
str7x_result(struct flash_bank_s
*bank
)
229 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
230 target_t
*target
= str7x_info
->target
;
233 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), &retval
);
238 int str7x_blank_check(struct flash_bank_s
*bank
, int first
, int last
)
240 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
241 target_t
*target
= str7x_info
->target
;
246 if ((first
< 0) || (last
> bank
->num_sectors
))
247 return ERROR_FLASH_SECTOR_INVALID
;
249 if (str7x_info
->target
->state
!= TARGET_HALTED
)
251 return ERROR_TARGET_NOT_HALTED
;
254 buffer
= malloc(256);
256 for (i
= first
; i
<= last
; i
++)
258 bank
->sectors
[i
].is_erased
= 1;
260 target
->type
->read_memory(target
, bank
->base
+ bank
->sectors
[i
].offset
, 4, 256/4, buffer
);
262 for (nBytes
= 0; nBytes
< 256; nBytes
++)
264 if (buffer
[nBytes
] != 0xFF)
266 bank
->sectors
[i
].is_erased
= 0;
277 int str7x_protect_check(struct flash_bank_s
*bank
)
279 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
280 target_t
*target
= str7x_info
->target
;
285 if (str7x_info
->target
->state
!= TARGET_HALTED
)
287 return ERROR_TARGET_NOT_HALTED
;
290 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVWPAR
), &retval
);
292 for (i
= 0; i
< bank
->num_sectors
; i
++)
294 if (retval
& str7x_info
->sector_bits
[i
])
295 bank
->sectors
[i
].is_protected
= 0;
297 bank
->sectors
[i
].is_protected
= 1;
303 int str7x_erase(struct flash_bank_s
*bank
, int first
, int last
)
305 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
306 target_t
*target
= str7x_info
->target
;
311 u32 b0_sectors
= 0, b1_sectors
= 0;
313 if (str7x_info
->target
->state
!= TARGET_HALTED
)
315 return ERROR_TARGET_NOT_HALTED
;
318 for (i
= first
; i
<= last
; i
++)
320 if (str7x_info
->sector_bank
[i
] == 0)
321 b0_sectors
|= str7x_info
->sector_bits
[i
];
322 else if (str7x_info
->sector_bank
[i
] == 1)
323 b1_sectors
|= str7x_info
->sector_bits
[i
];
325 ERROR("BUG: str7x_info->sector_bank[i] neither 0 nor 1 (%i)", str7x_info
->sector_bank
[i
]);
330 DEBUG("b0_sectors: 0x%x", b0_sectors
);
332 /* clear FLASH_ER register */
333 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
336 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
339 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
341 cmd
= FLASH_SER
|FLASH_WMS
;
342 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
344 while (((retval
= str7x_status(bank
)) & (FLASH_BSYA1
|FLASH_BSYA2
))){
348 retval
= str7x_result(bank
);
352 ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval
);
353 return ERROR_FLASH_OPERATION_FAILED
;
359 DEBUG("b1_sectors: 0x%x", b1_sectors
);
361 /* clear FLASH_ER register */
362 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
365 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
368 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
370 cmd
= FLASH_SER
|FLASH_WMS
;
371 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
373 while (((retval
= str7x_status(bank
)) & (FLASH_BSYA1
|FLASH_BSYA2
))){
377 retval
= str7x_result(bank
);
381 ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval
);
382 return ERROR_FLASH_OPERATION_FAILED
;
386 for (i
= first
; i
<= last
; i
++)
387 bank
->sectors
[i
].is_erased
= 1;
392 int str7x_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
394 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
395 target_t
*target
= str7x_info
->target
;
401 if (str7x_info
->target
->state
!= TARGET_HALTED
)
403 return ERROR_TARGET_NOT_HALTED
;
406 protect_blocks
= 0xFFFFFFFF;
410 for (i
= first
; i
<= last
; i
++)
411 protect_blocks
&= ~(str7x_info
->sector_bits
[i
]);
414 /* clear FLASH_ER register */
415 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
418 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
420 cmd
= str7x_get_flash_adr(bank
, FLASH_NVWPAR
);
421 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), cmd
);
423 cmd
= protect_blocks
;
424 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), cmd
);
426 cmd
= FLASH_SPR
|FLASH_WMS
;
427 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
429 while (((retval
= str7x_status(bank
)) & (FLASH_BSYA1
|FLASH_BSYA2
))){
433 retval
= str7x_result(bank
);
435 DEBUG("retval: 0x%8.8x", retval
);
437 if (retval
& FLASH_ERER
)
438 return ERROR_FLASH_SECTOR_NOT_ERASED
;
439 else if (retval
& FLASH_WPF
)
440 return ERROR_FLASH_OPERATION_FAILED
;
445 int str7x_write_block(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
447 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
448 target_t
*target
= str7x_info
->target
;
449 u32 buffer_size
= 8192;
450 working_area_t
*source
;
451 u32 address
= bank
->base
+ offset
;
452 reg_param_t reg_params
[5];
453 armv4_5_algorithm_t armv4_5_info
;
456 u32 str7x_flash_write_code
[] = {
458 0xe3a04201, /* mov r4, #0x10000000 */
459 0xe5824000, /* str r4, [r2, #0x0] */
460 0xe5821010, /* str r1, [r2, #0x10] */
461 0xe4904004, /* ldr r4, [r0], #4 */
462 0xe5824008, /* str r4, [r2, #0x8] */
463 0xe4904004, /* ldr r4, [r0], #4 */
464 0xe582400c, /* str r4, [r2, #0xc] */
465 0xe3a04209, /* mov r4, #0x90000000 */
466 0xe5824000, /* str r4, [r2, #0x0] */
468 0xe5924000, /* ldr r4, [r2, #0x0] */
469 0xe3140016, /* tst r4, #0x16 */
470 0x1afffffc, /* bne busy */
471 0xe5924014, /* ldr r4, [r2, #0x14] */
472 0xe31400ff, /* tst r4, #0xff */
473 0x03140c01, /* tsteq r4, #0x100 */
474 0x1a000002, /* bne exit */
475 0xe2811008, /* add r1, r1, #0x8 */
476 0xe2533001, /* subs r3, r3, #1 */
477 0x1affffec, /* bne write */
479 0xeafffffe, /* b exit */
482 u8 str7x_flash_write_code_buf
[80];
485 /* flash write code */
486 if (!str7x_info
->write_algorithm
)
488 if (target_alloc_working_area(target
, 4 * 20, &str7x_info
->write_algorithm
) != ERROR_OK
)
490 WARNING("no working area available, can't do block memory writes");
491 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
494 /* convert flash writing code into a buffer in target endianness */
495 for (i
= 0; i
< 20; i
++)
496 target_buffer_set_u32(target
, str7x_flash_write_code_buf
+ i
*4, str7x_flash_write_code
[i
]);
498 target_write_buffer(target
, str7x_info
->write_algorithm
->address
, 20 * 4, str7x_flash_write_code_buf
);
502 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
505 if (buffer_size
<= 256)
507 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
508 if (str7x_info
->write_algorithm
)
509 target_free_working_area(target
, str7x_info
->write_algorithm
);
511 WARNING("no large enough working area available, can't do block memory writes");
512 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
516 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
517 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
518 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
520 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
521 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
522 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
523 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
524 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
528 u32 thisrun_count
= (count
> (buffer_size
/ 8)) ? (buffer_size
/ 8) : count
;
530 target_write_buffer(target
, source
->address
, thisrun_count
* 8, buffer
);
532 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
533 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
534 buf_set_u32(reg_params
[2].value
, 0, 32, str7x_get_flash_adr(bank
, FLASH_CR0
));
535 buf_set_u32(reg_params
[3].value
, 0, 32, thisrun_count
);
537 if ((retval
= target
->type
->run_algorithm(target
, 0, NULL
, 5, reg_params
, str7x_info
->write_algorithm
->address
, str7x_info
->write_algorithm
->address
+ (19 * 4), 10000, &armv4_5_info
)) != ERROR_OK
)
539 ERROR("error executing str7x flash write algorithm");
540 return ERROR_FLASH_OPERATION_FAILED
;
543 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
545 return ERROR_FLASH_OPERATION_FAILED
;
548 buffer
+= thisrun_count
* 8;
549 address
+= thisrun_count
* 8;
550 count
-= thisrun_count
;
553 target_free_working_area(target
, source
);
555 destroy_reg_param(®_params
[0]);
556 destroy_reg_param(®_params
[1]);
557 destroy_reg_param(®_params
[2]);
558 destroy_reg_param(®_params
[3]);
559 destroy_reg_param(®_params
[4]);
564 int str7x_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
566 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
567 target_t
*target
= str7x_info
->target
;
568 u32 dwords_remaining
= (count
/ 8);
569 u32 bytes_remaining
= (count
& 0x00000007);
570 u32 address
= bank
->base
+ offset
;
571 u32 bytes_written
= 0;
574 u32 check_address
= offset
;
577 if (str7x_info
->target
->state
!= TARGET_HALTED
)
579 return ERROR_TARGET_NOT_HALTED
;
584 WARNING("offset 0x%x breaks required 8-byte alignment", offset
);
585 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
588 for (i
= 0; i
< bank
->num_sectors
; i
++)
590 u32 sec_start
= bank
->sectors
[i
].offset
;
591 u32 sec_end
= sec_start
+ bank
->sectors
[i
].size
;
593 /* check if destination falls within the current sector */
594 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
596 /* check if destination ends in the current sector */
597 if (offset
+ count
< sec_end
)
598 check_address
= offset
+ count
;
600 check_address
= sec_end
;
604 if (check_address
!= offset
+ count
)
605 return ERROR_FLASH_DST_OUT_OF_BANK
;
607 /* clear FLASH_ER register */
608 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
610 /* multiple dwords (8-byte) to be programmed? */
611 if (dwords_remaining
> 0)
613 /* try using a block write */
614 if ((retval
= str7x_write_block(bank
, buffer
, offset
, dwords_remaining
)) != ERROR_OK
)
616 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
618 /* if block write failed (no sufficient working area),
619 * we use normal (slow) single dword accesses */
620 WARNING("couldn't use block writes, falling back to single memory accesses");
622 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
624 /* if an error occured, we examine the reason, and quit */
625 retval
= str7x_result(bank
);
627 ERROR("flash writing failed with error code: 0x%x", retval
);
628 return ERROR_FLASH_OPERATION_FAILED
;
633 buffer
+= dwords_remaining
* 8;
634 address
+= dwords_remaining
* 8;
635 dwords_remaining
= 0;
639 while (dwords_remaining
> 0)
643 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
646 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
649 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, buffer
+ bytes_written
);
653 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, buffer
+ bytes_written
);
656 /* start programming cycle */
657 cmd
= FLASH_DWPG
| FLASH_WMS
;
658 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
660 while (((retval
= str7x_status(bank
)) & (FLASH_BSYA1
| FLASH_BSYA2
)))
665 retval
= str7x_result(bank
);
667 if (retval
& FLASH_PGER
)
668 return ERROR_FLASH_OPERATION_FAILED
;
669 else if (retval
& FLASH_WPF
)
670 return ERROR_FLASH_OPERATION_FAILED
;
678 u8 last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
681 while(bytes_remaining
> 0)
683 last_dword
[i
++] = *(buffer
+ bytes_written
);
690 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
693 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
696 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, last_dword
);
700 target
->type
->write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, last_dword
+ 4);
703 /* start programming cycle */
704 cmd
= FLASH_DWPG
| FLASH_WMS
;
705 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
707 while (((retval
= str7x_status(bank
)) & (FLASH_BSYA1
| FLASH_BSYA2
)))
712 retval
= str7x_result(bank
);
714 if (retval
& FLASH_PGER
)
715 return ERROR_FLASH_OPERATION_FAILED
;
716 else if (retval
& FLASH_WPF
)
717 return ERROR_FLASH_OPERATION_FAILED
;
723 int str7x_probe(struct flash_bank_s
*bank
)
728 int str7x_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
733 int str7x_erase_check(struct flash_bank_s
*bank
)
735 return str7x_blank_check(bank
, 0, bank
->num_sectors
- 1);
738 int str7x_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
740 snprintf(buf
, buf_size
, "str7x flash driver 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)