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

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)