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 "binarybuffer.h"
32 str7x_mem_layout_t mem_layout_str7bank0
[] = {
33 {0x00000000, 0x02000, 0x01},
34 {0x00002000, 0x02000, 0x02},
35 {0x00004000, 0x02000, 0x04},
36 {0x00006000, 0x02000, 0x08},
37 {0x00008000, 0x08000, 0x10},
38 {0x00010000, 0x10000, 0x20},
39 {0x00020000, 0x10000, 0x40},
40 {0x00030000, 0x10000, 0x80}
43 str7x_mem_layout_t mem_layout_str7bank1
[] = {
44 {0x00000000, 0x02000, 0x10000},
45 {0x00002000, 0x02000, 0x20000}
48 static int str7x_get_flash_adr(struct flash_bank_s
*bank
, uint32_t reg
)
50 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
51 return (str7x_info
->register_base
| reg
);
54 static int str7x_build_block_list(struct flash_bank_s
*bank
)
56 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
60 int b0_sectors
= 0, b1_sectors
= 0;
77 LOG_ERROR("BUG: unknown bank->size encountered");
81 num_sectors
= b0_sectors
+ b1_sectors
;
83 bank
->num_sectors
= num_sectors
;
84 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
85 str7x_info
->sector_bits
= malloc(sizeof(uint32_t) * num_sectors
);
89 for (i
= 0; i
< b0_sectors
; i
++)
91 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank0
[i
].sector_start
;
92 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank0
[i
].sector_size
;
93 bank
->sectors
[num_sectors
].is_erased
= -1;
94 bank
->sectors
[num_sectors
].is_protected
= 1;
95 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank0
[i
].sector_bit
;
98 for (i
= 0; i
< b1_sectors
; i
++)
100 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank1
[i
].sector_start
;
101 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank1
[i
].sector_size
;
102 bank
->sectors
[num_sectors
].is_erased
= -1;
103 bank
->sectors
[num_sectors
].is_protected
= 1;
104 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank1
[i
].sector_bit
;
110 /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
112 static int str7x_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
)
114 str7x_flash_bank_t
*str7x_info
;
118 LOG_WARNING("incomplete flash_bank str7x configuration");
119 return ERROR_FLASH_BANK_INVALID
;
122 str7x_info
= malloc(sizeof(str7x_flash_bank_t
));
123 bank
->driver_priv
= str7x_info
;
125 /* set default bits for str71x flash */
126 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA1
| FLASH_BSYA0
);
127 str7x_info
->disable_bit
= (1 << 1);
129 if (strcmp(args
[6], "STR71x") == 0)
131 str7x_info
->register_base
= 0x40100000;
133 else if (strcmp(args
[6], "STR73x") == 0)
135 str7x_info
->register_base
= 0x80100000;
136 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA0
);
138 else if (strcmp(args
[6], "STR75x") == 0)
140 str7x_info
->register_base
= 0x20100000;
141 str7x_info
->disable_bit
= (1 << 0);
145 LOG_ERROR("unknown STR7x variant: '%s'", args
[6]);
147 return ERROR_FLASH_BANK_INVALID
;
150 str7x_build_block_list(bank
);
152 str7x_info
->write_algorithm
= NULL
;
157 static uint32_t str7x_status(struct flash_bank_s
*bank
)
159 target_t
*target
= bank
->target
;
162 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), &retval
);
167 static uint32_t str7x_result(struct flash_bank_s
*bank
)
169 target_t
*target
= bank
->target
;
172 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), &retval
);
177 static int str7x_protect_check(struct flash_bank_s
*bank
)
179 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
180 target_t
*target
= bank
->target
;
185 if (bank
->target
->state
!= TARGET_HALTED
)
187 LOG_ERROR("Target not halted");
188 return ERROR_TARGET_NOT_HALTED
;
191 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVWPAR
), &retval
);
193 for (i
= 0; i
< bank
->num_sectors
; i
++)
195 if (retval
& str7x_info
->sector_bits
[i
])
196 bank
->sectors
[i
].is_protected
= 0;
198 bank
->sectors
[i
].is_protected
= 1;
204 static int str7x_erase(struct flash_bank_s
*bank
, int first
, int last
)
206 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
207 target_t
*target
= bank
->target
;
212 uint32_t sectors
= 0;
214 if (bank
->target
->state
!= TARGET_HALTED
)
216 LOG_ERROR("Target not halted");
217 return ERROR_TARGET_NOT_HALTED
;
220 for (i
= first
; i
<= last
; i
++)
222 sectors
|= str7x_info
->sector_bits
[i
];
225 LOG_DEBUG("sectors: 0x%" PRIx32
"", sectors
);
227 /* clear FLASH_ER register */
228 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
231 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
234 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
236 cmd
= FLASH_SER
| FLASH_WMS
;
237 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
239 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)) {
243 retval
= str7x_result(bank
);
247 LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32
"", retval
);
248 return ERROR_FLASH_OPERATION_FAILED
;
251 for (i
= first
; i
<= last
; i
++)
252 bank
->sectors
[i
].is_erased
= 1;
257 static int str7x_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
259 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
260 target_t
*target
= bank
->target
;
264 uint32_t protect_blocks
;
266 if (bank
->target
->state
!= TARGET_HALTED
)
268 LOG_ERROR("Target not halted");
269 return ERROR_TARGET_NOT_HALTED
;
272 protect_blocks
= 0xFFFFFFFF;
276 for (i
= first
; i
<= last
; i
++)
277 protect_blocks
&= ~(str7x_info
->sector_bits
[i
]);
280 /* clear FLASH_ER register */
281 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
284 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
286 cmd
= str7x_get_flash_adr(bank
, FLASH_NVWPAR
);
287 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), cmd
);
289 cmd
= protect_blocks
;
290 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), cmd
);
292 cmd
= FLASH_SPR
| FLASH_WMS
;
293 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
295 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)) {
299 retval
= str7x_result(bank
);
301 LOG_DEBUG("retval: 0x%8.8" PRIx32
"", retval
);
303 if (retval
& FLASH_ERER
)
304 return ERROR_FLASH_SECTOR_NOT_ERASED
;
305 else if (retval
& FLASH_WPF
)
306 return ERROR_FLASH_OPERATION_FAILED
;
311 static int str7x_write_block(struct flash_bank_s
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
313 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
314 target_t
*target
= bank
->target
;
315 uint32_t buffer_size
= 8192;
316 working_area_t
*source
;
317 uint32_t address
= bank
->base
+ offset
;
318 reg_param_t reg_params
[6];
319 armv4_5_algorithm_t armv4_5_info
;
320 int retval
= ERROR_OK
;
322 uint32_t str7x_flash_write_code
[] = {
324 0xe3a04201, /* mov r4, #0x10000000 */
325 0xe5824000, /* str r4, [r2, #0x0] */
326 0xe5821010, /* str r1, [r2, #0x10] */
327 0xe4904004, /* ldr r4, [r0], #4 */
328 0xe5824008, /* str r4, [r2, #0x8] */
329 0xe4904004, /* ldr r4, [r0], #4 */
330 0xe582400c, /* str r4, [r2, #0xc] */
331 0xe3a04209, /* mov r4, #0x90000000 */
332 0xe5824000, /* str r4, [r2, #0x0] */
334 0xe5924000, /* ldr r4, [r2, #0x0] */
335 0xe1140005, /* tst r4, r5 */
336 0x1afffffc, /* bne busy */
337 0xe5924014, /* ldr r4, [r2, #0x14] */
338 0xe31400ff, /* tst r4, #0xff */
339 0x03140c01, /* tsteq r4, #0x100 */
340 0x1a000002, /* bne exit */
341 0xe2811008, /* add r1, r1, #0x8 */
342 0xe2533001, /* subs r3, r3, #1 */
343 0x1affffec, /* bne write */
345 0xeafffffe, /* b exit */
348 /* flash write code */
349 if (target_alloc_working_area(target
, 4 * 20, &str7x_info
->write_algorithm
) != ERROR_OK
)
351 LOG_WARNING("no working area available, can't do block memory writes");
352 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
355 target_write_buffer(target
, str7x_info
->write_algorithm
->address
, 20 * 4, (uint8_t*)str7x_flash_write_code
);
358 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
361 if (buffer_size
<= 256)
363 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
364 if (str7x_info
->write_algorithm
)
365 target_free_working_area(target
, str7x_info
->write_algorithm
);
367 LOG_WARNING("no large enough working area available, can't do block memory writes");
368 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
372 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
373 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
374 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
376 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
377 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
378 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
379 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
380 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
381 init_reg_param(®_params
[5], "r5", 32, PARAM_OUT
);
385 uint32_t thisrun_count
= (count
> (buffer_size
/ 8)) ? (buffer_size
/ 8) : count
;
387 target_write_buffer(target
, source
->address
, thisrun_count
* 8, buffer
);
389 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
390 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
391 buf_set_u32(reg_params
[2].value
, 0, 32, str7x_get_flash_adr(bank
, FLASH_CR0
));
392 buf_set_u32(reg_params
[3].value
, 0, 32, thisrun_count
);
393 buf_set_u32(reg_params
[5].value
, 0, 32, str7x_info
->busy_bits
);
395 if ((retval
= target_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
)
397 LOG_ERROR("error executing str7x flash write algorithm");
398 retval
= ERROR_FLASH_OPERATION_FAILED
;
402 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
404 retval
= ERROR_FLASH_OPERATION_FAILED
;
408 buffer
+= thisrun_count
* 8;
409 address
+= thisrun_count
* 8;
410 count
-= thisrun_count
;
413 target_free_working_area(target
, source
);
414 target_free_working_area(target
, str7x_info
->write_algorithm
);
416 destroy_reg_param(®_params
[0]);
417 destroy_reg_param(®_params
[1]);
418 destroy_reg_param(®_params
[2]);
419 destroy_reg_param(®_params
[3]);
420 destroy_reg_param(®_params
[4]);
421 destroy_reg_param(®_params
[5]);
426 static int str7x_write(struct flash_bank_s
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
428 target_t
*target
= bank
->target
;
429 str7x_flash_bank_t
*str7x_info
= bank
->driver_priv
;
430 uint32_t dwords_remaining
= (count
/ 8);
431 uint32_t bytes_remaining
= (count
& 0x00000007);
432 uint32_t address
= bank
->base
+ offset
;
433 uint32_t bytes_written
= 0;
436 uint32_t check_address
= offset
;
439 if (bank
->target
->state
!= TARGET_HALTED
)
441 LOG_ERROR("Target not halted");
442 return ERROR_TARGET_NOT_HALTED
;
447 LOG_WARNING("offset 0x%" PRIx32
" breaks required 8-byte alignment", offset
);
448 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
451 for (i
= 0; i
< bank
->num_sectors
; i
++)
453 uint32_t sec_start
= bank
->sectors
[i
].offset
;
454 uint32_t sec_end
= sec_start
+ bank
->sectors
[i
].size
;
456 /* check if destination falls within the current sector */
457 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
459 /* check if destination ends in the current sector */
460 if (offset
+ count
< sec_end
)
461 check_address
= offset
+ count
;
463 check_address
= sec_end
;
467 if (check_address
!= offset
+ count
)
468 return ERROR_FLASH_DST_OUT_OF_BANK
;
470 /* clear FLASH_ER register */
471 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
473 /* multiple dwords (8-byte) to be programmed? */
474 if (dwords_remaining
> 0)
476 /* try using a block write */
477 if ((retval
= str7x_write_block(bank
, buffer
, offset
, dwords_remaining
)) != ERROR_OK
)
479 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
481 /* if block write failed (no sufficient working area),
482 * we use normal (slow) single dword accesses */
483 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
485 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
487 /* if an error occured, we examine the reason, and quit */
488 retval
= str7x_result(bank
);
490 LOG_ERROR("flash writing failed with error code: 0x%x", retval
);
491 return ERROR_FLASH_OPERATION_FAILED
;
496 buffer
+= dwords_remaining
* 8;
497 address
+= dwords_remaining
* 8;
498 dwords_remaining
= 0;
502 while (dwords_remaining
> 0)
506 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
509 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
512 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, buffer
+ bytes_written
);
516 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, buffer
+ bytes_written
);
519 /* start programming cycle */
520 cmd
= FLASH_DWPG
| FLASH_WMS
;
521 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
523 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
528 retval
= str7x_result(bank
);
530 if (retval
& FLASH_PGER
)
531 return ERROR_FLASH_OPERATION_FAILED
;
532 else if (retval
& FLASH_WPF
)
533 return ERROR_FLASH_OPERATION_FAILED
;
541 uint8_t last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
544 while (bytes_remaining
> 0)
546 last_dword
[i
++] = *(buffer
+ bytes_written
);
553 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
556 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
559 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, last_dword
);
563 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, last_dword
+ 4);
566 /* start programming cycle */
567 cmd
= FLASH_DWPG
| FLASH_WMS
;
568 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
570 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
575 retval
= str7x_result(bank
);
577 if (retval
& FLASH_PGER
)
578 return ERROR_FLASH_OPERATION_FAILED
;
579 else if (retval
& FLASH_WPF
)
580 return ERROR_FLASH_OPERATION_FAILED
;
586 static int str7x_probe(struct flash_bank_s
*bank
)
592 COMMAND_HANDLER(str7x_handle_part_id_command
)
598 static int str7x_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
600 snprintf(buf
, buf_size
, "str7x flash driver info");
604 COMMAND_HANDLER(str7x_handle_disable_jtag_command
)
606 target_t
*target
= NULL
;
607 str7x_flash_bank_t
*str7x_info
= NULL
;
610 uint16_t ProtectionLevel
= 0;
611 uint16_t ProtectionRegs
;
615 command_print(cmd_ctx
, "str7x disable_jtag <bank>");
620 int retval
= flash_command_get_bank_by_num(cmd_ctx
, args
[0], &bank
);
621 if (ERROR_OK
!= retval
)
624 str7x_info
= bank
->driver_priv
;
626 target
= bank
->target
;
628 if (target
->state
!= TARGET_HALTED
)
630 LOG_ERROR("Target not halted");
631 return ERROR_TARGET_NOT_HALTED
;
634 /* first we get protection status */
636 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR0
), ®
);
638 if (!(reg
& str7x_info
->disable_bit
))
643 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR1
), ®
);
644 ProtectionRegs
= ~(reg
>> 16);
646 while (((ProtectionRegs
) != 0) && (ProtectionLevel
< 16))
648 ProtectionRegs
>>= 1;
652 if (ProtectionLevel
== 0)
654 flash_cmd
= FLASH_SPR
;
655 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
656 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFB8);
657 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 0xFFFFFFFD);
658 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
659 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
663 flash_cmd
= FLASH_SPR
;
664 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
665 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFBC);
666 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), ~(1 << (15 + ProtectionLevel
)));
667 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
668 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
674 static int str7x_register_commands(struct command_context_s
*cmd_ctx
)
676 command_t
*str7x_cmd
= register_command(cmd_ctx
, NULL
, "str7x",
677 NULL
, COMMAND_ANY
, "str7x flash specific commands");
679 register_command(cmd_ctx
, str7x_cmd
, "disable_jtag",
680 str7x_handle_disable_jtag_command
, COMMAND_EXEC
,
681 "disable jtag access");
686 flash_driver_t str7x_flash
= {
688 .register_commands
= &str7x_register_commands
,
689 .flash_bank_command
= &str7x_flash_bank_command
,
690 .erase
= &str7x_erase
,
691 .protect
= &str7x_protect
,
692 .write
= &str7x_write
,
693 .probe
= &str7x_probe
,
694 .auto_probe
= &str7x_probe
,
695 .erase_check
= &default_flash_blank_check
,
696 .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)