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

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)