ARM: ARMV4_5_COMMON_MAGIC --> ARM_COMMON_MAGIC
[openocd.git] / src / flash / nor / str9x.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 *
8 * Copyright (C) 2008 by Oyvind Harboe *
9 * oyvind.harboe@zylin.com *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "imp.h"
31 #include "str9x.h"
32 #include <target/arm966e.h>
33 #include <target/algorithm.h>
34
35
36 static uint32_t bank1start = 0x00080000;
37
38 static int str9x_build_block_list(struct flash_bank *bank)
39 {
40 struct str9x_flash_bank *str9x_info = bank->driver_priv;
41
42 int i;
43 int num_sectors;
44 int b0_sectors = 0, b1_sectors = 0;
45 uint32_t offset = 0;
46
47 /* set if we have large flash str9 */
48 str9x_info->variant = 0;
49 str9x_info->bank1 = 0;
50
51 switch (bank->size)
52 {
53 case (256 * 1024):
54 b0_sectors = 4;
55 break;
56 case (512 * 1024):
57 b0_sectors = 8;
58 break;
59 case (1024 * 1024):
60 bank1start = 0x00100000;
61 str9x_info->variant = 1;
62 b0_sectors = 16;
63 break;
64 case (2048 * 1024):
65 bank1start = 0x00200000;
66 str9x_info->variant = 1;
67 b0_sectors = 32;
68 break;
69 case (128 * 1024):
70 str9x_info->variant = 1;
71 str9x_info->bank1 = 1;
72 b1_sectors = 8;
73 bank1start = bank->base;
74 break;
75 case (32 * 1024):
76 str9x_info->bank1 = 1;
77 b1_sectors = 4;
78 bank1start = bank->base;
79 break;
80 default:
81 LOG_ERROR("BUG: unknown bank->size encountered");
82 exit(-1);
83 }
84
85 num_sectors = b0_sectors + b1_sectors;
86
87 bank->num_sectors = num_sectors;
88 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
89 str9x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
90
91 num_sectors = 0;
92
93 for (i = 0; i < b0_sectors; i++)
94 {
95 bank->sectors[num_sectors].offset = offset;
96 bank->sectors[num_sectors].size = 0x10000;
97 offset += bank->sectors[i].size;
98 bank->sectors[num_sectors].is_erased = -1;
99 bank->sectors[num_sectors].is_protected = 1;
100 str9x_info->sector_bits[num_sectors++] = (1 << i);
101 }
102
103 for (i = 0; i < b1_sectors; i++)
104 {
105 bank->sectors[num_sectors].offset = offset;
106 bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000;
107 offset += bank->sectors[i].size;
108 bank->sectors[num_sectors].is_erased = -1;
109 bank->sectors[num_sectors].is_protected = 1;
110 if (str9x_info->variant)
111 str9x_info->sector_bits[num_sectors++] = (1 << i);
112 else
113 str9x_info->sector_bits[num_sectors++] = (1 << (i + 8));
114 }
115
116 return ERROR_OK;
117 }
118
119 /* flash bank str9x <base> <size> 0 0 <target#>
120 */
121 FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command)
122 {
123 struct str9x_flash_bank *str9x_info;
124
125 if (CMD_ARGC < 6)
126 {
127 LOG_WARNING("incomplete flash_bank str9x configuration");
128 return ERROR_FLASH_BANK_INVALID;
129 }
130
131 str9x_info = malloc(sizeof(struct str9x_flash_bank));
132 bank->driver_priv = str9x_info;
133
134 str9x_build_block_list(bank);
135
136 str9x_info->write_algorithm = NULL;
137
138 return ERROR_OK;
139 }
140
141 static int str9x_protect_check(struct flash_bank *bank)
142 {
143 int retval;
144 struct str9x_flash_bank *str9x_info = bank->driver_priv;
145 struct target *target = bank->target;
146
147 int i;
148 uint32_t adr;
149 uint32_t status = 0;
150 uint16_t hstatus = 0;
151
152 if (bank->target->state != TARGET_HALTED)
153 {
154 LOG_ERROR("Target not halted");
155 return ERROR_TARGET_NOT_HALTED;
156 }
157
158 /* read level one protection */
159
160 if (str9x_info->variant)
161 {
162 if (str9x_info->bank1)
163 {
164 adr = bank1start + 0x18;
165 if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
166 {
167 return retval;
168 }
169 if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
170 {
171 return retval;
172 }
173 status = hstatus;
174 }
175 else
176 {
177 adr = bank1start + 0x14;
178 if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
179 {
180 return retval;
181 }
182 if ((retval = target_read_u32(target, adr, &status)) != ERROR_OK)
183 {
184 return retval;
185 }
186 }
187 }
188 else
189 {
190 adr = bank1start + 0x10;
191 if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
192 {
193 return retval;
194 }
195 if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
196 {
197 return retval;
198 }
199 status = hstatus;
200 }
201
202 /* read array command */
203 if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
204 {
205 return retval;
206 }
207
208 for (i = 0; i < bank->num_sectors; i++)
209 {
210 if (status & str9x_info->sector_bits[i])
211 bank->sectors[i].is_protected = 1;
212 else
213 bank->sectors[i].is_protected = 0;
214 }
215
216 return ERROR_OK;
217 }
218
219 static int str9x_erase(struct flash_bank *bank, int first, int last)
220 {
221 struct target *target = bank->target;
222 int i;
223 uint32_t adr;
224 uint8_t status;
225 uint8_t erase_cmd;
226
227 if (bank->target->state != TARGET_HALTED)
228 {
229 LOG_ERROR("Target not halted");
230 return ERROR_TARGET_NOT_HALTED;
231 }
232
233 /* Check if we erase whole bank */
234 if ((first == 0) && (last == (bank->num_sectors - 1)))
235 {
236 /* Optimize to run erase bank command instead of sector */
237 erase_cmd = 0x80;
238 }
239 else
240 {
241 /* Erase sector command */
242 erase_cmd = 0x20;
243 }
244
245 for (i = first; i <= last; i++)
246 {
247 int retval;
248 adr = bank->base + bank->sectors[i].offset;
249
250 /* erase sectors */
251 if ((retval = target_write_u16(target, adr, erase_cmd)) != ERROR_OK)
252 {
253 return retval;
254 }
255 if ((retval = target_write_u16(target, adr, 0xD0)) != ERROR_OK)
256 {
257 return retval;
258 }
259
260 /* get status */
261 if ((retval = target_write_u16(target, adr, 0x70)) != ERROR_OK)
262 {
263 return retval;
264 }
265
266 int timeout;
267 for (timeout = 0; timeout < 1000; timeout++) {
268 if ((retval = target_read_u8(target, adr, &status)) != ERROR_OK)
269 {
270 return retval;
271 }
272 if (status & 0x80)
273 break;
274 alive_sleep(1);
275 }
276 if (timeout == 1000)
277 {
278 LOG_ERROR("erase timed out");
279 return ERROR_FAIL;
280 }
281
282 /* clear status, also clear read array */
283 if ((retval = target_write_u16(target, adr, 0x50)) != ERROR_OK)
284 {
285 return retval;
286 }
287
288 /* read array command */
289 if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
290 {
291 return retval;
292 }
293
294 if (status & 0x22)
295 {
296 LOG_ERROR("error erasing flash bank, status: 0x%x", status);
297 return ERROR_FLASH_OPERATION_FAILED;
298 }
299
300 /* If we ran erase bank command, we are finished */
301 if (erase_cmd == 0x80)
302 break;
303 }
304
305 for (i = first; i <= last; i++)
306 bank->sectors[i].is_erased = 1;
307
308 return ERROR_OK;
309 }
310
311 static int str9x_protect(struct flash_bank *bank,
312 int set, int first, int last)
313 {
314 struct target *target = bank->target;
315 int i;
316 uint32_t adr;
317 uint8_t status;
318
319 if (bank->target->state != TARGET_HALTED)
320 {
321 LOG_ERROR("Target not halted");
322 return ERROR_TARGET_NOT_HALTED;
323 }
324
325 for (i = first; i <= last; i++)
326 {
327 /* Level One Protection */
328
329 adr = bank->base + bank->sectors[i].offset;
330
331 target_write_u16(target, adr, 0x60);
332 if (set)
333 target_write_u16(target, adr, 0x01);
334 else
335 target_write_u16(target, adr, 0xD0);
336
337 /* query status */
338 target_read_u8(target, adr, &status);
339
340 /* clear status, also clear read array */
341 target_write_u16(target, adr, 0x50);
342
343 /* read array command */
344 target_write_u16(target, adr, 0xFF);
345 }
346
347 return ERROR_OK;
348 }
349
350 static int str9x_write_block(struct flash_bank *bank,
351 uint8_t *buffer, uint32_t offset, uint32_t count)
352 {
353 struct str9x_flash_bank *str9x_info = bank->driver_priv;
354 struct target *target = bank->target;
355 uint32_t buffer_size = 8192;
356 struct working_area *source;
357 uint32_t address = bank->base + offset;
358 struct reg_param reg_params[4];
359 struct armv4_5_algorithm armv4_5_info;
360 int retval = ERROR_OK;
361
362 uint32_t str9x_flash_write_code[] = {
363 /* write: */
364 0xe3c14003, /* bic r4, r1, #3 */
365 0xe3a03040, /* mov r3, #0x40 */
366 0xe1c430b0, /* strh r3, [r4, #0] */
367 0xe0d030b2, /* ldrh r3, [r0], #2 */
368 0xe0c130b2, /* strh r3, [r1], #2 */
369 0xe3a03070, /* mov r3, #0x70 */
370 0xe1c430b0, /* strh r3, [r4, #0] */
371 /* busy: */
372 0xe5d43000, /* ldrb r3, [r4, #0] */
373 0xe3130080, /* tst r3, #0x80 */
374 0x0afffffc, /* beq busy */
375 0xe3a05050, /* mov r5, #0x50 */
376 0xe1c450b0, /* strh r5, [r4, #0] */
377 0xe3a050ff, /* mov r5, #0xFF */
378 0xe1c450b0, /* strh r5, [r4, #0] */
379 0xe3130012, /* tst r3, #0x12 */
380 0x1a000001, /* bne exit */
381 0xe2522001, /* subs r2, r2, #1 */
382 0x1affffed, /* bne write */
383 /* exit: */
384 0xeafffffe, /* b exit */
385 };
386
387 /* flash write code */
388 if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
389 {
390 LOG_WARNING("no working area available, can't do block memory writes");
391 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
392 };
393
394 target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (uint8_t*)str9x_flash_write_code);
395
396 /* memory buffer */
397 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
398 {
399 buffer_size /= 2;
400 if (buffer_size <= 256)
401 {
402 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
403 if (str9x_info->write_algorithm)
404 target_free_working_area(target, str9x_info->write_algorithm);
405
406 LOG_WARNING("no large enough working area available, can't do block memory writes");
407 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
408 }
409 }
410
411 armv4_5_info.common_magic = ARM_COMMON_MAGIC;
412 armv4_5_info.core_mode = ARM_MODE_SVC;
413 armv4_5_info.core_state = ARM_STATE_ARM;
414
415 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
416 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
417 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
418 init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
419
420 while (count > 0)
421 {
422 uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
423
424 target_write_buffer(target, source->address, thisrun_count * 2, buffer);
425
426 buf_set_u32(reg_params[0].value, 0, 32, source->address);
427 buf_set_u32(reg_params[1].value, 0, 32, address);
428 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
429
430 if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
431 {
432 LOG_ERROR("error executing str9x flash write algorithm");
433 retval = ERROR_FLASH_OPERATION_FAILED;
434 break;
435 }
436
437 if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
438 {
439 retval = ERROR_FLASH_OPERATION_FAILED;
440 break;
441 }
442
443 buffer += thisrun_count * 2;
444 address += thisrun_count * 2;
445 count -= thisrun_count;
446 }
447
448 target_free_working_area(target, source);
449 target_free_working_area(target, str9x_info->write_algorithm);
450
451 destroy_reg_param(&reg_params[0]);
452 destroy_reg_param(&reg_params[1]);
453 destroy_reg_param(&reg_params[2]);
454 destroy_reg_param(&reg_params[3]);
455
456 return retval;
457 }
458
459 static int str9x_write(struct flash_bank *bank,
460 uint8_t *buffer, uint32_t offset, uint32_t count)
461 {
462 struct target *target = bank->target;
463 uint32_t words_remaining = (count / 2);
464 uint32_t bytes_remaining = (count & 0x00000001);
465 uint32_t address = bank->base + offset;
466 uint32_t bytes_written = 0;
467 uint8_t status;
468 int retval;
469 uint32_t check_address = offset;
470 uint32_t bank_adr;
471 int i;
472
473 if (bank->target->state != TARGET_HALTED)
474 {
475 LOG_ERROR("Target not halted");
476 return ERROR_TARGET_NOT_HALTED;
477 }
478
479 if (offset & 0x1)
480 {
481 LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
482 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
483 }
484
485 for (i = 0; i < bank->num_sectors; i++)
486 {
487 uint32_t sec_start = bank->sectors[i].offset;
488 uint32_t sec_end = sec_start + bank->sectors[i].size;
489
490 /* check if destination falls within the current sector */
491 if ((check_address >= sec_start) && (check_address < sec_end))
492 {
493 /* check if destination ends in the current sector */
494 if (offset + count < sec_end)
495 check_address = offset + count;
496 else
497 check_address = sec_end;
498 }
499 }
500
501 if (check_address != offset + count)
502 return ERROR_FLASH_DST_OUT_OF_BANK;
503
504 /* multiple half words (2-byte) to be programmed? */
505 if (words_remaining > 0)
506 {
507 /* try using a block write */
508 if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
509 {
510 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
511 {
512 /* if block write failed (no sufficient working area),
513 * we use normal (slow) single dword accesses */
514 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
515 }
516 else if (retval == ERROR_FLASH_OPERATION_FAILED)
517 {
518 LOG_ERROR("flash writing failed with error code: 0x%x", retval);
519 return ERROR_FLASH_OPERATION_FAILED;
520 }
521 }
522 else
523 {
524 buffer += words_remaining * 2;
525 address += words_remaining * 2;
526 words_remaining = 0;
527 }
528 }
529
530 while (words_remaining > 0)
531 {
532 bank_adr = address & ~0x03;
533
534 /* write data command */
535 target_write_u16(target, bank_adr, 0x40);
536 target_write_memory(target, address, 2, 1, buffer + bytes_written);
537
538 /* get status command */
539 target_write_u16(target, bank_adr, 0x70);
540
541 int timeout;
542 for (timeout = 0; timeout < 1000; timeout++)
543 {
544 target_read_u8(target, bank_adr, &status);
545 if (status & 0x80)
546 break;
547 alive_sleep(1);
548 }
549 if (timeout == 1000)
550 {
551 LOG_ERROR("write timed out");
552 return ERROR_FAIL;
553 }
554
555 /* clear status reg and read array */
556 target_write_u16(target, bank_adr, 0x50);
557 target_write_u16(target, bank_adr, 0xFF);
558
559 if (status & 0x10)
560 return ERROR_FLASH_OPERATION_FAILED;
561 else if (status & 0x02)
562 return ERROR_FLASH_OPERATION_FAILED;
563
564 bytes_written += 2;
565 words_remaining--;
566 address += 2;
567 }
568
569 if (bytes_remaining)
570 {
571 uint8_t last_halfword[2] = {0xff, 0xff};
572 int i = 0;
573
574 while (bytes_remaining > 0)
575 {
576 last_halfword[i++] = *(buffer + bytes_written);
577 bytes_remaining--;
578 bytes_written++;
579 }
580
581 bank_adr = address & ~0x03;
582
583 /* write data command */
584 target_write_u16(target, bank_adr, 0x40);
585 target_write_memory(target, address, 2, 1, last_halfword);
586
587 /* query status command */
588 target_write_u16(target, bank_adr, 0x70);
589
590 int timeout;
591 for (timeout = 0; timeout < 1000; timeout++)
592 {
593 target_read_u8(target, bank_adr, &status);
594 if (status & 0x80)
595 break;
596 alive_sleep(1);
597 }
598 if (timeout == 1000)
599 {
600 LOG_ERROR("write timed out");
601 return ERROR_FAIL;
602 }
603
604 /* clear status reg and read array */
605 target_write_u16(target, bank_adr, 0x50);
606 target_write_u16(target, bank_adr, 0xFF);
607
608 if (status & 0x10)
609 return ERROR_FLASH_OPERATION_FAILED;
610 else if (status & 0x02)
611 return ERROR_FLASH_OPERATION_FAILED;
612 }
613
614 return ERROR_OK;
615 }
616
617 static int str9x_probe(struct flash_bank *bank)
618 {
619 return ERROR_OK;
620 }
621
622 #if 0
623 COMMAND_HANDLER(str9x_handle_part_id_command)
624 {
625 return ERROR_OK;
626 }
627 #endif
628
629 static int str9x_info(struct flash_bank *bank, char *buf, int buf_size)
630 {
631 snprintf(buf, buf_size, "str9x flash driver info");
632 return ERROR_OK;
633 }
634
635 COMMAND_HANDLER(str9x_handle_flash_config_command)
636 {
637 struct str9x_flash_bank *str9x_info;
638 struct target *target = NULL;
639
640 if (CMD_ARGC < 5)
641 {
642 return ERROR_COMMAND_SYNTAX_ERROR;
643 }
644
645 struct flash_bank *bank;
646 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
647 if (ERROR_OK != retval)
648 return retval;
649
650 uint32_t bbsr, nbbsr, bbadr, nbbadr;
651 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], bbsr);
652 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], nbbsr);
653 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], bbadr);
654 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], nbbadr);
655
656 str9x_info = bank->driver_priv;
657
658 target = bank->target;
659
660 if (bank->target->state != TARGET_HALTED)
661 {
662 LOG_ERROR("Target not halted");
663 return ERROR_TARGET_NOT_HALTED;
664 }
665
666 /* config flash controller */
667 target_write_u32(target, FLASH_BBSR, bbsr);
668 target_write_u32(target, FLASH_NBBSR, nbbsr);
669 target_write_u32(target, FLASH_BBADR, bbadr >> 2);
670 target_write_u32(target, FLASH_NBBADR, nbbadr >> 2);
671
672 /* set bit 18 instruction TCM order as per flash programming manual */
673 arm966e_write_cp15(target, 62, 0x40000);
674
675 /* enable flash bank 1 */
676 target_write_u32(target, FLASH_CR, 0x18);
677 return ERROR_OK;
678 }
679
680 static const struct command_registration str9x_config_command_handlers[] = {
681 {
682 .name = "disable_jtag",
683 .handler = &str9x_handle_flash_config_command,
684 .mode = COMMAND_EXEC,
685 .help = "configure str9x flash controller",
686 .usage = "<bank_id> <BBSR> <NBBSR> <BBADR> <NBBADR>",
687 },
688 COMMAND_REGISTRATION_DONE
689 };
690 static const struct command_registration str9x_command_handlers[] = {
691 {
692 .name = "str9x",
693 .mode = COMMAND_ANY,
694 .help = "str9x flash command group",
695 .chain = str9x_config_command_handlers,
696 },
697 COMMAND_REGISTRATION_DONE
698 };
699
700 struct flash_driver str9x_flash = {
701 .name = "str9x",
702 .commands = str9x_command_handlers,
703 .flash_bank_command = &str9x_flash_bank_command,
704 .erase = &str9x_erase,
705 .protect = &str9x_protect,
706 .write = &str9x_write,
707 .probe = &str9x_probe,
708 .auto_probe = &str9x_probe,
709 .erase_check = &default_flash_blank_check,
710 .protect_check = &str9x_protect_check,
711 .info = &str9x_info,
712 };

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)