- keep additional information for decoded instructions
[openocd.git] / src / flash / at91sam7.c
1 /***************************************************************************
2 * Copyright (C) 2006 by Magnus Lundin *
3 * lundin@mlu.mine.nu *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 /***************************************************************************
22 There are some things to notice
23
24 * AT91SAM7S64 is tested
25 * All AT91SAM7Sxx and AT91SAM7Xxx should work but is not tested
26 * All parameters are identified from onchip configuartion registers
27 *
28 * The flash controller handles erases automatically on a page (128/265 byte) basis
29 * Only an EraseAll command is supported by the controller
30 * Partial erases can be implemented in software by writing one 0xFFFFFFFF word to
31 * some location in every page in the region to be erased
32 *
33 * Lock regions (sectors) are 32 or 64 pages
34 *
35 ***************************************************************************/
36
37 #include "at91sam7.h"
38
39 #include "flash.h"
40 #include "target.h"
41 #include "log.h"
42 #include "binarybuffer.h"
43 #include "types.h"
44
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 int at91sam7_register_commands(struct command_context_s *cmd_ctx);
50 int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
51 int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
52 int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
53 int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
54 int at91sam7_probe(struct flash_bank_s *bank);
55 int at91sam7_erase_check(struct flash_bank_s *bank);
56 int at91sam7_protect_check(struct flash_bank_s *bank);
57 int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
58
59 u32 at91sam7_get_flash_status(flash_bank_t *bank);
60 void at91sam7_set_flash_mode(flash_bank_t *bank,int mode);
61 u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout);
62 int at91sam7_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
63
64 flash_driver_t at91sam7_flash =
65 {
66 .name = "at91sam7",
67 .register_commands = at91sam7_register_commands,
68 .flash_bank_command = at91sam7_flash_bank_command,
69 .erase = at91sam7_erase,
70 .protect = at91sam7_protect,
71 .write = at91sam7_write,
72 .probe = at91sam7_probe,
73 .erase_check = at91sam7_erase_check,
74 .protect_check = at91sam7_protect_check,
75 .info = at91sam7_info
76 };
77
78
79 char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
80 long NVPSIZ[16] = {
81 0,
82 0x2000, /* 8K */
83 0x4000, /* 16K */
84 0x8000, /* 32K */
85 -1,
86 0x10000, /* 64K */
87 -1,
88 0x20000, /* 128K */
89 -1,
90 0x40000, /* 256K */
91 0x80000, /* 512K */
92 -1,
93 0x100000, /* 1024K */
94 -1,
95 0x200000, /* 2048K */
96 -1
97 };
98
99 long SRAMSIZ[16] = {
100 -1,
101 0x0400, /* 1K */
102 0x0800, /* 2K */
103 -1,
104 0x1c000, /* 112K */
105 0x1000, /* 4K */
106 0x14000, /* 80K */
107 0x28000, /* 160K */
108 0x2000, /* 8K */
109 0x4000, /* 16K */
110 0x8000, /* 32K */
111 0x10000, /* 64K */
112 0x20000, /* 128K */
113 0x40000, /* 256K */
114 0x18000, /* 96K */
115 0x80000, /* 512K */
116 };
117
118 u32 at91sam7_get_flash_status(flash_bank_t *bank)
119 {
120 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
121 target_t *target = at91sam7_info->target;
122 long fsr;
123
124 target->type->read_memory(target, MC_FSR, 4, 1, (u8 *)&fsr);
125
126 return fsr;
127 }
128
129 /* Setup the timimg registers for nvbits or normal flash */
130 void at91sam7_set_flash_mode(flash_bank_t *bank,int mode)
131 {
132 u32 fmcn, fmr;
133 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
134 target_t *target = at91sam7_info->target;
135
136 if (mode != at91sam7_info->flashmode) {
137 /* mainf contains the number of main clocks in approx 500uS */
138 if (mode==1)
139 /* main clocks in 1uS */
140 fmcn = (at91sam7_info->mainf>>9)+1;
141 else
142 /* main clocks in 1.5uS */
143 fmcn = (at91sam7_info->mainf>>9)+(at91sam7_info->mainf>>10)+1;
144 DEBUG("fmcn: %i", fmcn);
145 fmr = fmcn<<16;
146 target->type->write_memory(target, MC_FSR, 4, 1, (u8 *)&fmr);
147 at91sam7_info->flashmode = mode;
148 }
149 }
150
151 u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout)
152 {
153 u32 status;
154
155 while ((!((status = at91sam7_get_flash_status(bank)) & 0x01)) && (timeout-- > 0))
156 {
157 DEBUG("status: 0x%x", status);
158 usleep(1000);
159 }
160
161 DEBUG("status: 0x%x", status);
162
163 if (status&0x0C)
164 {
165 ERROR("status register: 0x%x", status);
166 if (status & 0x4)
167 ERROR("Lock Error Bit Detected, Operation Abort");
168 if (status & 0x8)
169 ERROR("Invalid command and/or bad keyword, Operation Abort");
170 if (status & 0x10)
171 ERROR("Security Bit Set, Operation Abort");
172 }
173
174 return status;
175 }
176
177 int at91sam7_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen)
178 {
179 u32 fcr;
180 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
181 target_t *target = at91sam7_info->target;
182
183 fcr = (0x5A<<24) | (pagen<<8) | cmd;
184 target->type->write_memory(target, MC_FCR, 4, 1, (u8 *)&fcr);
185 DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
186
187 if (at91sam7_wait_status_busy(bank, 10)&0x0C)
188 {
189 return ERROR_FLASH_OPERATION_FAILED;
190 }
191 return ERROR_OK;
192 }
193
194 /* Read device id register, main clock frequency register and fill in driver info structure */
195 int at91sam7_read_part_info(struct flash_bank_s *bank)
196 {
197 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
198 target_t *target = at91sam7_info->target;
199 unsigned long cidr, mcfr, status;
200
201 if (at91sam7_info->target->state != TARGET_HALTED)
202 {
203 return ERROR_TARGET_NOT_HALTED;
204 }
205
206 /* Read and parse chip identification register */
207 target->type->read_memory(target, DBGU_CIDR, 4, 1, (u8 *)&cidr);
208
209 if (cidr == 0)
210 {
211 WARNING("Cannot identify target as an AT91SAM");
212 return ERROR_FLASH_OPERATION_FAILED;
213 }
214
215 at91sam7_info->cidr = cidr;
216 at91sam7_info->cidr_ext = (cidr>>31)&0x0001;
217 at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;
218 at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;
219 at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;
220 at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
221 at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;
222 at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;
223 at91sam7_info->cidr_version = cidr&0x001F;
224 bank->size = NVPSIZ[at91sam7_info->cidr_nvpsiz];
225
226 DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch );
227
228 /* Read main clock freqency register */
229 target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr);
230 if (mcfr&0x10000)
231 {
232 at91sam7_info->mainrdy = 1;
233 at91sam7_info->mainf = mcfr&0xFFFF;
234 at91sam7_info->usec_clocks = mcfr>>9;
235 }
236 else
237 {
238 at91sam7_info->mainrdy = 0;
239 at91sam7_info->mainf = 0;
240 at91sam7_info->usec_clocks = 0;
241 }
242
243 status = at91sam7_get_flash_status(bank);
244 at91sam7_info->lockbits = status>>16;
245 at91sam7_info->securitybit = (status>>4)&0x01;
246
247 if (at91sam7_info->cidr_arch == 0x70 ) {
248 at91sam7_info->num_nvmbits = 2;
249 at91sam7_info->nvmbits = (status>>8)&0x03;
250 bank->base = 0x100000;
251 bank->bus_width = 4;
252 if (bank->size==0x40000) /* AT91SAM7S256 */
253 {
254 at91sam7_info->num_lockbits = 16;
255 at91sam7_info->pagesize = 256;
256 at91sam7_info->pages_in_lockregion = 64;
257 at91sam7_info->num_pages = 16*64;
258 }
259 if (bank->size==0x20000) /* AT91SAM7S128 */
260 {
261 at91sam7_info->num_lockbits = 8;
262 at91sam7_info->pagesize = 256;
263 at91sam7_info->pages_in_lockregion = 64;
264 at91sam7_info->num_pages = 8*64;
265 }
266 if (bank->size==0x10000) /* AT91SAM7S64 */
267 {
268 at91sam7_info->num_lockbits = 16;
269 at91sam7_info->pagesize = 128;
270 at91sam7_info->pages_in_lockregion = 32;
271 at91sam7_info->num_pages = 16*32;
272 }
273 if (bank->size==0x08000) /* AT91SAM7S321/32 */
274 {
275 at91sam7_info->num_lockbits = 8;
276 at91sam7_info->pagesize = 128;
277 at91sam7_info->pages_in_lockregion = 32;
278 at91sam7_info->num_pages = 8*32;
279 }
280
281 return ERROR_OK;
282 }
283
284 if (at91sam7_info->cidr_arch == 0x71 ) {
285 at91sam7_info->num_nvmbits = 2;
286 at91sam7_info->nvmbits = (status>>8)&0x03;
287 bank->base = 0x100000;
288 bank->bus_width = 4;
289 if (bank->size==0x40000) /* AT91SAM7XC256 */
290 {
291 at91sam7_info->num_lockbits = 16;
292 at91sam7_info->pagesize = 256;
293 at91sam7_info->pages_in_lockregion = 64;
294 at91sam7_info->num_pages = 16*64;
295 }
296 if (bank->size==0x20000) /* AT91SAM7XC128 */
297 {
298 at91sam7_info->num_lockbits = 8;
299 at91sam7_info->pagesize = 256;
300 at91sam7_info->pages_in_lockregion = 64;
301 at91sam7_info->num_pages = 8*64;
302 }
303
304 return ERROR_OK;
305 }
306
307 if (at91sam7_info->cidr_arch == 0x75 ) {
308 at91sam7_info->num_nvmbits = 3;
309 at91sam7_info->nvmbits = (status>>8)&0x07;
310 bank->base = 0x100000;
311 bank->bus_width = 4;
312 if (bank->size==0x40000) /* AT91SAM7X256 */
313 {
314 at91sam7_info->num_lockbits = 16;
315 at91sam7_info->pagesize = 256;
316 at91sam7_info->pages_in_lockregion = 64;
317 at91sam7_info->num_pages = 16*64;
318 }
319 if (bank->size==0x20000) /* AT91SAM7X128 */
320 {
321 at91sam7_info->num_lockbits = 8;
322 at91sam7_info->pagesize = 256;
323 at91sam7_info->pages_in_lockregion = 64;
324 at91sam7_info->num_pages = 8*64;
325 }
326
327 return ERROR_OK;
328 }
329
330 if (at91sam7_info->cidr_arch != 0x70 )
331 {
332 WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
333 }
334 return ERROR_OK;
335 }
336
337 int at91sam7_erase_check(struct flash_bank_s *bank)
338 {
339 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
340 target_t *target = at91sam7_info->target;
341 int i;
342
343 if (!at91sam7_info->working_area_size)
344 {
345 }
346 else
347 {
348 }
349
350 return ERROR_OK;
351 }
352
353 int at91sam7_protect_check(struct flash_bank_s *bank)
354 {
355 u32 status;
356
357 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
358 target_t *target = at91sam7_info->target;
359
360 if (at91sam7_info->cidr == 0)
361 {
362 at91sam7_read_part_info(bank);
363 }
364
365 if (at91sam7_info->cidr == 0)
366 {
367 WARNING("Cannot identify target as an AT91SAM");
368 return ERROR_FLASH_OPERATION_FAILED;
369 }
370
371 status = at91sam7_get_flash_status(bank);
372 at91sam7_info->lockbits = status>>16;
373
374 return ERROR_OK;
375 }
376
377
378 int at91sam7_register_commands(struct command_context_s *cmd_ctx)
379 {
380 command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
381
382 return ERROR_OK;
383 }
384
385 int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
386 {
387 at91sam7_flash_bank_t *at91sam7_info;
388
389 if (argc < 6)
390 {
391 WARNING("incomplete flash_bank at91sam7 configuration");
392 return ERROR_FLASH_BANK_INVALID;
393 }
394
395 at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
396 bank->driver_priv = at91sam7_info;
397
398 at91sam7_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
399 if (!at91sam7_info->target)
400 {
401 ERROR("no target '%i' configured", args[5]);
402 exit(-1);
403 }
404
405
406 /* part wasn't probed for info yet */
407 at91sam7_info->cidr = 0;
408
409 return ERROR_OK;
410 }
411
412 int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
413 {
414 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
415
416 if (at91sam7_info->target->state != TARGET_HALTED)
417 {
418 return ERROR_TARGET_NOT_HALTED;
419 }
420
421 if (at91sam7_info->cidr == 0)
422 {
423 at91sam7_read_part_info(bank);
424 }
425
426 if (at91sam7_info->cidr == 0)
427 {
428 WARNING("Cannot identify target as an AT91SAM");
429 return ERROR_FLASH_OPERATION_FAILED;
430 }
431
432 if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
433 {
434 return ERROR_FLASH_SECTOR_INVALID;
435 }
436
437 if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))
438 {
439 return at91sam7_flash_command(bank, EA, 0);
440 }
441
442 WARNING("Can only erase the whole flash area, pages are autoerased on write");
443 return ERROR_FLASH_OPERATION_FAILED;
444 }
445
446 int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
447 {
448 u32 cmd, pagen, status;
449 int lockregion;
450
451 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
452 target_t *target = at91sam7_info->target;
453
454 if (at91sam7_info->target->state != TARGET_HALTED)
455 {
456 return ERROR_TARGET_NOT_HALTED;
457 }
458
459 if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
460 {
461 return ERROR_FLASH_SECTOR_INVALID;
462 }
463
464 if (at91sam7_info->cidr == 0)
465 {
466 at91sam7_read_part_info(bank);
467 }
468
469 if (at91sam7_info->cidr == 0)
470 {
471 WARNING("Cannot identify target as an AT91SAM");
472 return ERROR_FLASH_OPERATION_FAILED;
473 }
474
475 /* Configure the flash controller timing */
476 at91sam7_set_flash_mode(bank,1);
477
478 for (lockregion=first;lockregion<=last;lockregion++)
479 {
480 pagen = lockregion*at91sam7_info->pages_in_lockregion;
481 if (set)
482 cmd = SLB;
483 else
484 cmd = CLB;
485 if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
486 {
487 return ERROR_FLASH_OPERATION_FAILED;
488 }
489 }
490
491 status = at91sam7_get_flash_status(bank);
492 at91sam7_info->lockbits = status>>16;
493
494 return ERROR_OK;
495 }
496
497
498 int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
499 {
500 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
501 target_t *target = at91sam7_info->target;
502 u32 dst_min_alignment, wcount, bytes_remaining = count;
503 u32 first_page, last_page, pagen, buffer_pos;
504 u32 fcr;
505
506 if (at91sam7_info->target->state != TARGET_HALTED)
507 {
508 return ERROR_TARGET_NOT_HALTED;
509 }
510
511 if (at91sam7_info->cidr == 0)
512 {
513 at91sam7_read_part_info(bank);
514 }
515
516 if (at91sam7_info->cidr == 0)
517 {
518 WARNING("Cannot identify target as an AT91SAM");
519 return ERROR_FLASH_OPERATION_FAILED;
520 }
521
522 if (offset + count > bank->size)
523 return ERROR_FLASH_DST_OUT_OF_BANK;
524
525 dst_min_alignment = at91sam7_info->pagesize;
526
527 if (offset % dst_min_alignment)
528 {
529 WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
530 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
531 }
532
533 if (offset + count > bank->size)
534 return ERROR_FLASH_DST_OUT_OF_BANK;
535
536 if (at91sam7_info->cidr_arch == 0)
537 return ERROR_FLASH_BANK_NOT_PROBED;
538
539 first_page = offset/dst_min_alignment;
540 last_page = CEIL(offset + count, dst_min_alignment);
541
542 DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
543
544 /* Configure the flash controller timing */
545 at91sam7_set_flash_mode(bank,2);
546
547 for (pagen=first_page; pagen<last_page; pagen++) {
548 if (bytes_remaining<dst_min_alignment)
549 count = bytes_remaining;
550 else
551 count = dst_min_alignment;
552 bytes_remaining -= count;
553
554 /* Write one block to the PageWriteBuffer */
555 buffer_pos = (pagen-first_page)*dst_min_alignment;
556 wcount = CEIL(count,4);
557 target->type->write_memory(target, bank->base, 4, wcount, buffer+buffer_pos);
558
559 /* Send Write Page command to Flash Controller */
560 if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
561 {
562 return ERROR_FLASH_OPERATION_FAILED;
563 }
564 DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
565 }
566
567 return ERROR_OK;
568 }
569
570
571 int at91sam7_probe(struct flash_bank_s *bank)
572 {
573 /* we can't probe on an at91sam7
574 * if this is an at91sam7, it has the configured flash
575 */
576 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
577
578 if (at91sam7_info->cidr == 0)
579 {
580 at91sam7_read_part_info(bank);
581 }
582
583 if (at91sam7_info->cidr == 0)
584 {
585 WARNING("Cannot identify target as an AT91SAM");
586 return ERROR_FLASH_OPERATION_FAILED;
587 }
588 return ERROR_OK;
589 }
590
591 int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
592 {
593 int printed;
594 at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
595
596 if (at91sam7_info->cidr == 0)
597 {
598 at91sam7_read_part_info(bank);
599 }
600
601 if (at91sam7_info->cidr == 0)
602 {
603 printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");
604 buf += printed;
605 buf_size -= printed;
606 return ERROR_FLASH_OPERATION_FAILED;
607 }
608
609 printed = snprintf(buf, buf_size, "\nat91sam7 information:\n");
610 buf += printed;
611 buf_size -= printed;
612
613 printed = snprintf(buf, buf_size, "cidr: 0x%8.8x, arch: 0x%4.4x, eproc: %s, version:0x%3.3x, flashsize: 0x%8.8x\n", at91sam7_info->cidr, at91sam7_info->cidr_arch, EPROC[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size);
614 buf += printed;
615 buf_size -= printed;
616
617 printed = snprintf(buf, buf_size, "main clock(estimated): %ikHz \n", at91sam7_info->mainf*2);
618 buf += printed;
619 buf_size -= printed;
620
621 if (at91sam7_info->num_lockbits>0) {
622 printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->lockbits,at91sam7_info->num_pages/at91sam7_info->num_lockbits);
623 buf += printed;
624 buf_size -= printed;
625 }
626
627 printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);
628 buf += printed;
629 buf_size -= printed;
630
631 return ERROR_OK;
632 }

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)