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"
30 #include "algorithm.h"
33 struct str7x_mem_layout mem_layout_str7bank0
[] = {
34 {0x00000000, 0x02000, 0x01},
35 {0x00002000, 0x02000, 0x02},
36 {0x00004000, 0x02000, 0x04},
37 {0x00006000, 0x02000, 0x08},
38 {0x00008000, 0x08000, 0x10},
39 {0x00010000, 0x10000, 0x20},
40 {0x00020000, 0x10000, 0x40},
41 {0x00030000, 0x10000, 0x80}
44 struct str7x_mem_layout mem_layout_str7bank1
[] = {
45 {0x00000000, 0x02000, 0x10000},
46 {0x00002000, 0x02000, 0x20000}
49 static int str7x_get_flash_adr(struct flash_bank
*bank
, uint32_t reg
)
51 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
52 return (str7x_info
->register_base
| reg
);
55 static int str7x_build_block_list(struct flash_bank
*bank
)
57 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
61 int b0_sectors
= 0, b1_sectors
= 0;
78 LOG_ERROR("BUG: unknown bank->size encountered");
82 num_sectors
= b0_sectors
+ b1_sectors
;
84 bank
->num_sectors
= num_sectors
;
85 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_sectors
);
86 str7x_info
->sector_bits
= malloc(sizeof(uint32_t) * num_sectors
);
90 for (i
= 0; i
< b0_sectors
; i
++)
92 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank0
[i
].sector_start
;
93 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank0
[i
].sector_size
;
94 bank
->sectors
[num_sectors
].is_erased
= -1;
95 bank
->sectors
[num_sectors
].is_protected
= 1;
96 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank0
[i
].sector_bit
;
99 for (i
= 0; i
< b1_sectors
; i
++)
101 bank
->sectors
[num_sectors
].offset
= mem_layout_str7bank1
[i
].sector_start
;
102 bank
->sectors
[num_sectors
].size
= mem_layout_str7bank1
[i
].sector_size
;
103 bank
->sectors
[num_sectors
].is_erased
= -1;
104 bank
->sectors
[num_sectors
].is_protected
= 1;
105 str7x_info
->sector_bits
[num_sectors
++] = mem_layout_str7bank1
[i
].sector_bit
;
111 /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
113 FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command
)
115 struct str7x_flash_bank
*str7x_info
;
119 LOG_WARNING("incomplete flash_bank str7x configuration");
120 return ERROR_FLASH_BANK_INVALID
;
123 str7x_info
= malloc(sizeof(struct str7x_flash_bank
));
124 bank
->driver_priv
= str7x_info
;
126 /* set default bits for str71x flash */
127 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA1
| FLASH_BSYA0
);
128 str7x_info
->disable_bit
= (1 << 1);
130 if (strcmp(args
[6], "STR71x") == 0)
132 str7x_info
->register_base
= 0x40100000;
134 else if (strcmp(args
[6], "STR73x") == 0)
136 str7x_info
->register_base
= 0x80100000;
137 str7x_info
->busy_bits
= (FLASH_LOCK
| FLASH_BSYA0
);
139 else if (strcmp(args
[6], "STR75x") == 0)
141 str7x_info
->register_base
= 0x20100000;
142 str7x_info
->disable_bit
= (1 << 0);
146 LOG_ERROR("unknown STR7x variant: '%s'", args
[6]);
148 return ERROR_FLASH_BANK_INVALID
;
151 str7x_build_block_list(bank
);
153 str7x_info
->write_algorithm
= NULL
;
158 static uint32_t str7x_status(struct flash_bank
*bank
)
160 struct target
*target
= bank
->target
;
163 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), &retval
);
168 static uint32_t str7x_result(struct flash_bank
*bank
)
170 struct target
*target
= bank
->target
;
173 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), &retval
);
178 static int str7x_protect_check(struct flash_bank
*bank
)
180 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
181 struct target
*target
= bank
->target
;
186 if (bank
->target
->state
!= TARGET_HALTED
)
188 LOG_ERROR("Target not halted");
189 return ERROR_TARGET_NOT_HALTED
;
192 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVWPAR
), &retval
);
194 for (i
= 0; i
< bank
->num_sectors
; i
++)
196 if (retval
& str7x_info
->sector_bits
[i
])
197 bank
->sectors
[i
].is_protected
= 0;
199 bank
->sectors
[i
].is_protected
= 1;
205 static int str7x_erase(struct flash_bank
*bank
, int first
, int last
)
207 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
208 struct target
*target
= bank
->target
;
213 uint32_t sectors
= 0;
215 if (bank
->target
->state
!= TARGET_HALTED
)
217 LOG_ERROR("Target not halted");
218 return ERROR_TARGET_NOT_HALTED
;
221 for (i
= first
; i
<= last
; i
++)
223 sectors
|= str7x_info
->sector_bits
[i
];
226 LOG_DEBUG("sectors: 0x%" PRIx32
"", sectors
);
228 /* clear FLASH_ER register */
229 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
232 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
235 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR1
), cmd
);
237 cmd
= FLASH_SER
| FLASH_WMS
;
238 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
240 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)) {
244 retval
= str7x_result(bank
);
248 LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32
"", retval
);
249 return ERROR_FLASH_OPERATION_FAILED
;
252 for (i
= first
; i
<= last
; i
++)
253 bank
->sectors
[i
].is_erased
= 1;
258 static int str7x_protect(struct flash_bank
*bank
, int set
, int first
, int last
)
260 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
261 struct target
*target
= bank
->target
;
265 uint32_t protect_blocks
;
267 if (bank
->target
->state
!= TARGET_HALTED
)
269 LOG_ERROR("Target not halted");
270 return ERROR_TARGET_NOT_HALTED
;
273 protect_blocks
= 0xFFFFFFFF;
277 for (i
= first
; i
<= last
; i
++)
278 protect_blocks
&= ~(str7x_info
->sector_bits
[i
]);
281 /* clear FLASH_ER register */
282 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
285 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
287 cmd
= str7x_get_flash_adr(bank
, FLASH_NVWPAR
);
288 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), cmd
);
290 cmd
= protect_blocks
;
291 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), cmd
);
293 cmd
= FLASH_SPR
| FLASH_WMS
;
294 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
296 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
)) {
300 retval
= str7x_result(bank
);
302 LOG_DEBUG("retval: 0x%8.8" PRIx32
"", retval
);
304 if (retval
& FLASH_ERER
)
305 return ERROR_FLASH_SECTOR_NOT_ERASED
;
306 else if (retval
& FLASH_WPF
)
307 return ERROR_FLASH_OPERATION_FAILED
;
312 static int str7x_write_block(struct flash_bank
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
314 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
315 struct target
*target
= bank
->target
;
316 uint32_t buffer_size
= 8192;
317 struct working_area
*source
;
318 uint32_t address
= bank
->base
+ offset
;
319 struct reg_param reg_params
[6];
320 struct armv4_5_algorithm armv4_5_info
;
321 int retval
= ERROR_OK
;
323 uint32_t str7x_flash_write_code
[] = {
325 0xe3a04201, /* mov r4, #0x10000000 */
326 0xe5824000, /* str r4, [r2, #0x0] */
327 0xe5821010, /* str r1, [r2, #0x10] */
328 0xe4904004, /* ldr r4, [r0], #4 */
329 0xe5824008, /* str r4, [r2, #0x8] */
330 0xe4904004, /* ldr r4, [r0], #4 */
331 0xe582400c, /* str r4, [r2, #0xc] */
332 0xe3a04209, /* mov r4, #0x90000000 */
333 0xe5824000, /* str r4, [r2, #0x0] */
335 0xe5924000, /* ldr r4, [r2, #0x0] */
336 0xe1140005, /* tst r4, r5 */
337 0x1afffffc, /* bne busy */
338 0xe5924014, /* ldr r4, [r2, #0x14] */
339 0xe31400ff, /* tst r4, #0xff */
340 0x03140c01, /* tsteq r4, #0x100 */
341 0x1a000002, /* bne exit */
342 0xe2811008, /* add r1, r1, #0x8 */
343 0xe2533001, /* subs r3, r3, #1 */
344 0x1affffec, /* bne write */
346 0xeafffffe, /* b exit */
349 /* flash write code */
350 if (target_alloc_working_area(target
, 4 * 20, &str7x_info
->write_algorithm
) != ERROR_OK
)
352 LOG_WARNING("no working area available, can't do block memory writes");
353 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
356 target_write_buffer(target
, str7x_info
->write_algorithm
->address
, 20 * 4, (uint8_t*)str7x_flash_write_code
);
359 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
362 if (buffer_size
<= 256)
364 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
365 if (str7x_info
->write_algorithm
)
366 target_free_working_area(target
, str7x_info
->write_algorithm
);
368 LOG_WARNING("no large enough working area available, can't do block memory writes");
369 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
373 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
374 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
375 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
377 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
378 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
379 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
380 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
381 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
382 init_reg_param(®_params
[5], "r5", 32, PARAM_OUT
);
386 uint32_t thisrun_count
= (count
> (buffer_size
/ 8)) ? (buffer_size
/ 8) : count
;
388 target_write_buffer(target
, source
->address
, thisrun_count
* 8, buffer
);
390 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
391 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
392 buf_set_u32(reg_params
[2].value
, 0, 32, str7x_get_flash_adr(bank
, FLASH_CR0
));
393 buf_set_u32(reg_params
[3].value
, 0, 32, thisrun_count
);
394 buf_set_u32(reg_params
[5].value
, 0, 32, str7x_info
->busy_bits
);
396 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
)
398 LOG_ERROR("error executing str7x flash write algorithm");
399 retval
= ERROR_FLASH_OPERATION_FAILED
;
403 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x00)
405 retval
= ERROR_FLASH_OPERATION_FAILED
;
409 buffer
+= thisrun_count
* 8;
410 address
+= thisrun_count
* 8;
411 count
-= thisrun_count
;
414 target_free_working_area(target
, source
);
415 target_free_working_area(target
, str7x_info
->write_algorithm
);
417 destroy_reg_param(®_params
[0]);
418 destroy_reg_param(®_params
[1]);
419 destroy_reg_param(®_params
[2]);
420 destroy_reg_param(®_params
[3]);
421 destroy_reg_param(®_params
[4]);
422 destroy_reg_param(®_params
[5]);
427 static int str7x_write(struct flash_bank
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
429 struct target
*target
= bank
->target
;
430 struct str7x_flash_bank
*str7x_info
= bank
->driver_priv
;
431 uint32_t dwords_remaining
= (count
/ 8);
432 uint32_t bytes_remaining
= (count
& 0x00000007);
433 uint32_t address
= bank
->base
+ offset
;
434 uint32_t bytes_written
= 0;
437 uint32_t check_address
= offset
;
440 if (bank
->target
->state
!= TARGET_HALTED
)
442 LOG_ERROR("Target not halted");
443 return ERROR_TARGET_NOT_HALTED
;
448 LOG_WARNING("offset 0x%" PRIx32
" breaks required 8-byte alignment", offset
);
449 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
452 for (i
= 0; i
< bank
->num_sectors
; i
++)
454 uint32_t sec_start
= bank
->sectors
[i
].offset
;
455 uint32_t sec_end
= sec_start
+ bank
->sectors
[i
].size
;
457 /* check if destination falls within the current sector */
458 if ((check_address
>= sec_start
) && (check_address
< sec_end
))
460 /* check if destination ends in the current sector */
461 if (offset
+ count
< sec_end
)
462 check_address
= offset
+ count
;
464 check_address
= sec_end
;
468 if (check_address
!= offset
+ count
)
469 return ERROR_FLASH_DST_OUT_OF_BANK
;
471 /* clear FLASH_ER register */
472 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_ER
), 0x0);
474 /* multiple dwords (8-byte) to be programmed? */
475 if (dwords_remaining
> 0)
477 /* try using a block write */
478 if ((retval
= str7x_write_block(bank
, buffer
, offset
, dwords_remaining
)) != ERROR_OK
)
480 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
482 /* if block write failed (no sufficient working area),
483 * we use normal (slow) single dword accesses */
484 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
486 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
488 /* if an error occured, we examine the reason, and quit */
489 retval
= str7x_result(bank
);
491 LOG_ERROR("flash writing failed with error code: 0x%x", retval
);
492 return ERROR_FLASH_OPERATION_FAILED
;
497 buffer
+= dwords_remaining
* 8;
498 address
+= dwords_remaining
* 8;
499 dwords_remaining
= 0;
503 while (dwords_remaining
> 0)
507 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
510 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
513 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, buffer
+ bytes_written
);
517 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, buffer
+ bytes_written
);
520 /* start programming cycle */
521 cmd
= FLASH_DWPG
| FLASH_WMS
;
522 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
524 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
529 retval
= str7x_result(bank
);
531 if (retval
& FLASH_PGER
)
532 return ERROR_FLASH_OPERATION_FAILED
;
533 else if (retval
& FLASH_WPF
)
534 return ERROR_FLASH_OPERATION_FAILED
;
542 uint8_t last_dword
[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
545 while (bytes_remaining
> 0)
547 last_dword
[i
++] = *(buffer
+ bytes_written
);
554 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
557 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), address
);
560 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 4, 1, last_dword
);
564 target_write_memory(target
, str7x_get_flash_adr(bank
, FLASH_DR1
), 4, 1, last_dword
+ 4);
567 /* start programming cycle */
568 cmd
= FLASH_DWPG
| FLASH_WMS
;
569 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), cmd
);
571 while (((retval
= str7x_status(bank
)) & str7x_info
->busy_bits
))
576 retval
= str7x_result(bank
);
578 if (retval
& FLASH_PGER
)
579 return ERROR_FLASH_OPERATION_FAILED
;
580 else if (retval
& FLASH_WPF
)
581 return ERROR_FLASH_OPERATION_FAILED
;
587 static int str7x_probe(struct flash_bank
*bank
)
593 COMMAND_HANDLER(str7x_handle_part_id_command
)
599 static int str7x_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
601 snprintf(buf
, buf_size
, "str7x flash driver info");
605 COMMAND_HANDLER(str7x_handle_disable_jtag_command
)
607 struct target
*target
= NULL
;
608 struct str7x_flash_bank
*str7x_info
= NULL
;
611 uint16_t ProtectionLevel
= 0;
612 uint16_t ProtectionRegs
;
616 command_print(cmd_ctx
, "str7x disable_jtag <bank>");
620 struct flash_bank
*bank
;
621 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank_by_num
, 0, &bank
);
622 if (ERROR_OK
!= retval
)
625 str7x_info
= bank
->driver_priv
;
627 target
= bank
->target
;
629 if (target
->state
!= TARGET_HALTED
)
631 LOG_ERROR("Target not halted");
632 return ERROR_TARGET_NOT_HALTED
;
635 /* first we get protection status */
637 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR0
), ®
);
639 if (!(reg
& str7x_info
->disable_bit
))
644 target_read_u32(target
, str7x_get_flash_adr(bank
, FLASH_NVAPR1
), ®
);
645 ProtectionRegs
= ~(reg
>> 16);
647 while (((ProtectionRegs
) != 0) && (ProtectionLevel
< 16))
649 ProtectionRegs
>>= 1;
653 if (ProtectionLevel
== 0)
655 flash_cmd
= FLASH_SPR
;
656 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
657 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFB8);
658 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), 0xFFFFFFFD);
659 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
660 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
664 flash_cmd
= FLASH_SPR
;
665 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
666 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_AR
), 0x4010DFBC);
667 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_DR0
), ~(1 << (15 + ProtectionLevel
)));
668 flash_cmd
= FLASH_SPR
| FLASH_WMS
;
669 target_write_u32(target
, str7x_get_flash_adr(bank
, FLASH_CR0
), flash_cmd
);
675 static int str7x_register_commands(struct command_context
*cmd_ctx
)
677 struct command
*str7x_cmd
= register_command(cmd_ctx
, NULL
, "str7x",
678 NULL
, COMMAND_ANY
, "str7x flash specific commands");
680 register_command(cmd_ctx
, str7x_cmd
, "disable_jtag",
681 str7x_handle_disable_jtag_command
, COMMAND_EXEC
,
682 "disable jtag access");
687 struct flash_driver str7x_flash
= {
689 .register_commands
= &str7x_register_commands
,
690 .flash_bank_command
= &str7x_flash_bank_command
,
691 .erase
= &str7x_erase
,
692 .protect
= &str7x_protect
,
693 .write
= &str7x_write
,
694 .probe
= &str7x_probe
,
695 .auto_probe
= &str7x_probe
,
696 .erase_check
= &default_flash_blank_check
,
697 .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)