flash: nor: ath79: remove base calculation
[openocd.git] / src / flash / nor / aducm360.c
1 /***************************************************************************
2 * Copyright (C) 2015 by Ivan Buliev *
3 * i.buliev@mikrosistemi.com *
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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 /***************************************************************************
20 * This version for ADuCM360 is largely based on the following flash *
21 * drivers: *
22 * - aduc702x.c *
23 * Copyright (C) 2008 by Kevin McGuire *
24 * Copyright (C) 2008 by Marcel Wijlaars *
25 * Copyright (C) 2009 by Michael Ashton *
26 * and *
27 * - stm32f1x.c *
28 * Copyright (C) 2005 by Dominic Rath *
29 * Dominic.Rath@gmx.de *
30 * *
31 * Copyright (C) 2008 by Spencer Oliver *
32 * spen@spen-soft.co.uk *
33 * *
34 * Copyright (C) 2011 by Andreas Fritiofson *
35 * andreas.fritiofson@gmail.com *
36 ***************************************************************************/
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include "imp.h"
43 #include <helper/binarybuffer.h>
44 #include <helper/time_support.h>
45 #include <target/algorithm.h>
46 #include <target/armv7m.h>
47
48 static int aducm360_build_sector_list(struct flash_bank *bank);
49 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms);
50 static int aducm360_set_write_enable(struct target *target, int enable);
51
52 #define ADUCM360_FLASH_BASE 0x40002800
53 #define ADUCM360_FLASH_FEESTA 0x0000
54 #define ADUCM360_FLASH_FEECON0 0x0004
55 #define ADUCM360_FLASH_FEECMD 0x0008
56 #define ADUCM360_FLASH_FEEADR0L 0x0010
57 #define ADUCM360_FLASH_FEEADR0H 0x0014
58 #define ADUCM360_FLASH_FEEADR1L 0x0018
59 #define ADUCM360_FLASH_FEEADR1H 0x001C
60 #define ADUCM360_FLASH_FEEKEY 0x0020
61 #define ADUCM360_FLASH_FEEPROL 0x0028
62 #define ADUCM360_FLASH_FEEPROH 0x002C
63 #define ADUCM360_FLASH_FEESIGL 0x0030
64 #define ADUCM360_FLASH_FEESIGH 0x0034
65 #define ADUCM360_FLASH_FEECON1 0x0038
66 #define ADUCM360_FLASH_FEEADRAL 0x0048
67 #define ADUCM360_FLASH_FEEADRAH 0x004C
68 #define ADUCM360_FLASH_FEEAEN0 0x0078
69 #define ADUCM360_FLASH_FEEAEN1 0x007C
70 #define ADUCM360_FLASH_FEEAEN2 0x0080
71
72 /* flash bank aducm360 0 0 0 0 <target#> */
73 FLASH_BANK_COMMAND_HANDLER(aducm360_flash_bank_command)
74 {
75 bank->base = 0x00000000;
76 bank->size = 0x00020000;
77
78 aducm360_build_sector_list(bank);
79
80 return ERROR_OK;
81 }
82
83 #define FLASH_SECTOR_SIZE 512
84
85 /* ----------------------------------------------------------------------- */
86 static int aducm360_build_sector_list(struct flash_bank *bank)
87 {
88 int i = 0;
89 uint32_t offset = 0;
90
91 /* sector size is 512 */
92 bank->num_sectors = bank->size / FLASH_SECTOR_SIZE;
93 bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
94 for (i = 0; i < bank->num_sectors; ++i) {
95 bank->sectors[i].offset = offset;
96 bank->sectors[i].size = FLASH_SECTOR_SIZE;
97 offset += bank->sectors[i].size;
98 bank->sectors[i].is_erased = -1;
99 bank->sectors[i].is_protected = 0;
100 }
101
102 return ERROR_OK;
103 }
104
105 /* ----------------------------------------------------------------------- */
106 static int aducm360_mass_erase(struct target *target)
107 {
108 uint32_t value;
109 int res = ERROR_OK;
110
111 /* Clear any old status */
112 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
113
114 /* Enable the writing to the flash*/
115 aducm360_set_write_enable(target, 1);
116
117 /* Unlock for writing */
118 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
119 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
120 /* Issue the 'MASSERASE' command */
121 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000003);
122
123 /* Check the result */
124 res = aducm360_check_flash_completion(target, 3500);
125 if (res != ERROR_OK) {
126 LOG_ERROR("mass erase failed.");
127 aducm360_set_write_enable(target, 0);
128 res = ERROR_FLASH_OPERATION_FAILED;
129 }
130
131 return res;
132 }
133
134 /* ----------------------------------------------------------------------- */
135 static int aducm360_page_erase(struct target *target, uint32_t padd)
136 {
137 uint32_t value;
138 int res = ERROR_OK;
139
140 /* Clear any old status */
141 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
142
143 /* Enable the writing to the flash*/
144 aducm360_set_write_enable(target, 1);
145
146 /* Unlock for writing */
147 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
148 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
149 /* Write the sector address */
150 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0L, padd & 0xFFFF);
151 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0H, (padd>>16) & 0xFFFF);
152 /* Issue the 'ERASEPAGE' command */
153 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000001);
154
155 /* Check the result */
156 res = aducm360_check_flash_completion(target, 50);
157 if (res != ERROR_OK) {
158 LOG_ERROR("page erase failed at 0x%08" PRIx32, padd);
159 aducm360_set_write_enable(target, 0);
160 res = ERROR_FLASH_OPERATION_FAILED;
161 }
162
163 return res;
164 }
165
166 /* ----------------------------------------------------------------------- */
167 static int aducm360_erase(struct flash_bank *bank, int first, int last)
168 {
169 int res = ERROR_OK;
170 int i;
171 int count;
172 struct target *target = bank->target;
173 uint32_t padd;
174
175 if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
176 res = aducm360_mass_erase(target);
177 } else {
178 count = last - first + 1;
179 for (i = 0; i < count; ++i) {
180 padd = bank->base + ((first+i)*FLASH_SECTOR_SIZE);
181 res = aducm360_page_erase(target, padd);
182 if (res != ERROR_OK)
183 break;
184 }
185 }
186
187 return res;
188 }
189
190 /* ----------------------------------------------------------------------- */
191 static int aducm360_write_block_sync(
192 struct flash_bank *bank,
193 const uint8_t *buffer,
194 uint32_t offset,
195 uint32_t count)
196 {
197 struct target *target = bank->target;
198 uint32_t target_buffer_size = 8192;
199 struct working_area *helper;
200 struct working_area *target_buffer;
201 uint32_t address = bank->base + offset;
202 struct reg_param reg_params[8];
203 int retval = ERROR_OK;
204 uint32_t entry_point = 0, exit_point = 0;
205 uint32_t res;
206 struct armv7m_algorithm armv7m_algo;
207
208 static const uint32_t aducm360_flash_write_code[] = {
209 /* helper.code */
210 0x88AF4D10, 0x0704F047, 0x682F80AF, 0x600E6806,
211 0xF017882F, 0xF43F0F08, 0xF851AFFB, 0x42B77B04,
212 0x800DF040, 0x0004F100, 0xF47F3A04, 0x686FAFEF,
213 0x0704F027, 0xF04F80AF, 0xF0000400, 0xF04FB802,
214 0xBE000480, 0x40002800, 0x00015000, 0x20000000,
215 0x00013000
216 };
217
218 LOG_DEBUG("'aducm360_write_block_sync' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
219 address, count);
220
221 /* ----- Check the destination area for a Long Word alignment ----- */
222 if (((count%4) != 0) || ((offset%4) != 0)) {
223 LOG_ERROR("write block must be multiple of four bytes in offset & length");
224 return ERROR_FAIL;
225 }
226
227 /* ----- Allocate space in the target's RAM for the helper code ----- */
228 if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
229 &helper) != ERROR_OK) {
230 LOG_WARNING("no working area available, can't do block memory writes");
231 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
232 }
233
234 /* ----- Upload the helper code to the space in the target's RAM ----- */
235 uint8_t code[sizeof(aducm360_flash_write_code)];
236 target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
237 aducm360_flash_write_code);
238 retval = target_write_buffer(target, helper->address, sizeof(code), code);
239 if (retval != ERROR_OK)
240 return retval;
241 entry_point = helper->address;
242
243 /* ----- Allocate space in the target's RAM for the user application's object code ----- */
244 while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
245 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
246 target_buffer_size);
247 target_buffer_size /= 2;
248 if (target_buffer_size <= 256) { /* No room available */
249 LOG_WARNING("no large enough working area available, can't do block memory writes");
250 target_free_working_area(target, helper);
251 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
252 }
253 }
254
255 /* ----- Prepare the target for the helper ----- */
256 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
257 armv7m_algo.core_mode = ARM_MODE_THREAD;
258
259 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRC */
260 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*DST */
261 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*COUNT */
262 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*not used */
263 init_reg_param(&reg_params[4], "r4", 32, PARAM_IN); /*RESULT */
264
265 /* ===== Execute the Main Programming Loop! ===== */
266 while (count > 0) {
267 uint32_t thisrun_count = (count > target_buffer_size) ? target_buffer_size : count;
268
269 /* ----- Upload the chunk ----- */
270 retval = target_write_buffer(target, target_buffer->address, thisrun_count, buffer);
271 if (retval != ERROR_OK)
272 break;
273 /* Set the arguments for the helper */
274 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address); /*SRC */
275 buf_set_u32(reg_params[1].value, 0, 32, address); /*DST */
276 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); /*COUNT */
277 buf_set_u32(reg_params[3].value, 0, 32, 0); /*NOT USED*/
278
279 retval = target_run_algorithm(target, 0, NULL, 5,
280 reg_params, entry_point, exit_point, 10000, &armv7m_algo);
281 if (retval != ERROR_OK) {
282 LOG_ERROR("error executing aducm360 flash write algorithm");
283 break;
284 }
285
286 res = buf_get_u32(reg_params[4].value, 0, 32);
287 if (res) {
288 LOG_ERROR("aducm360 fast sync algorithm reports an error (%02X)", res);
289 retval = ERROR_FAIL;
290 break;
291 }
292
293 buffer += thisrun_count;
294 address += thisrun_count;
295 count -= thisrun_count;
296 }
297
298 target_free_working_area(target, target_buffer);
299 target_free_working_area(target, helper);
300
301 destroy_reg_param(&reg_params[0]);
302 destroy_reg_param(&reg_params[1]);
303 destroy_reg_param(&reg_params[2]);
304 destroy_reg_param(&reg_params[3]);
305 destroy_reg_param(&reg_params[4]);
306
307 return retval;
308 }
309
310 /* ----------------------------------------------------------------------- */
311 static int aducm360_write_block_async(
312 struct flash_bank *bank,
313 const uint8_t *buffer,
314 uint32_t offset,
315 uint32_t count)
316 {
317 struct target *target = bank->target;
318 uint32_t target_buffer_size = 1024;
319 struct working_area *helper;
320 struct working_area *target_buffer;
321 uint32_t address = bank->base + offset;
322 struct reg_param reg_params[9];
323 int retval = ERROR_OK;
324 uint32_t entry_point = 0, exit_point = 0;
325 uint32_t res;
326 uint32_t wcount;
327 struct armv7m_algorithm armv7m_algo;
328
329 static const uint32_t aducm360_flash_write_code[] = {
330 /* helper.code */
331 0x4050F8DF, 0xF04588A5, 0x80A50504, 0x8000F8D0,
332 0x0F00F1B8, 0x8016F000, 0x45476847, 0xAFF6F43F,
333 0x6B04F857, 0x6B04F842, 0xF0158825, 0xF43F0F08,
334 0x428FAFFB, 0xF100BF28, 0x60470708, 0xB10B3B01,
335 0xBFE4F7FF, 0xF02588A5, 0x80A50504, 0x0900F04F,
336 0xBE00BF00, 0x40002800, 0x20000000, 0x20000100,
337 0x00013000
338 };
339
340 LOG_DEBUG("'aducm360_write_block_async' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
341 address, count);
342
343 /* ----- Check the destination area for a Long Word alignment ----- */
344 if (((count%4) != 0) || ((offset%4) != 0)) {
345 LOG_ERROR("write block must be multiple of four bytes in offset & length");
346 return ERROR_FAIL;
347 }
348 wcount = count/4;
349
350 /* ----- Allocate space in the target's RAM for the helper code ----- */
351 if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
352 &helper) != ERROR_OK) {
353 LOG_WARNING("no working area available, can't do block memory writes");
354 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
355 }
356
357 /* ----- Upload the helper code to the space in the target's RAM ----- */
358 uint8_t code[sizeof(aducm360_flash_write_code)];
359 target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
360 aducm360_flash_write_code);
361 retval = target_write_buffer(target, helper->address, sizeof(code), code);
362 if (retval != ERROR_OK)
363 return retval;
364 entry_point = helper->address;
365
366 /* ----- Allocate space in the target's RAM for the user application's object code ----- */
367 while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
368 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
369 target_buffer_size);
370 target_buffer_size /= 2;
371 if (target_buffer_size <= 256) { /* No room available */
372 LOG_WARNING("no large enough working area available, can't do block memory writes");
373 target_free_working_area(target, helper);
374 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
375 }
376 }
377
378 /* ----- Prepare the target for the helper ----- */
379 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
380 armv7m_algo.core_mode = ARM_MODE_THREAD;
381
382 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRCBEG */
383 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*SRCEND */
384 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*DST */
385 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*COUNT (LWs)*/
386 init_reg_param(&reg_params[4], "r9", 32, PARAM_IN); /*RESULT */
387
388 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);
389 buf_set_u32(reg_params[1].value, 0, 32, target_buffer->address + target_buffer->size);
390 buf_set_u32(reg_params[2].value, 0, 32, address);
391 buf_set_u32(reg_params[3].value, 0, 32, wcount);
392
393 retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
394 0, NULL,
395 5, reg_params,
396 target_buffer->address, target_buffer->size,
397 entry_point, exit_point,
398 &armv7m_algo);
399 if (retval != ERROR_OK) {
400 LOG_ERROR("error executing aducm360 flash write algorithm");
401 } else {
402 res = buf_get_u32(reg_params[4].value, 0, 32); /*RESULT*/
403 if (res) {
404 LOG_ERROR("aducm360 fast async algorithm reports an error (%02X)", res);
405 retval = ERROR_FAIL;
406 }
407 }
408
409 target_free_working_area(target, target_buffer);
410 target_free_working_area(target, helper);
411
412 destroy_reg_param(&reg_params[0]);
413 destroy_reg_param(&reg_params[1]);
414 destroy_reg_param(&reg_params[2]);
415 destroy_reg_param(&reg_params[3]);
416 destroy_reg_param(&reg_params[4]);
417
418 return retval;
419 }
420
421 /* ----------------------------------------------------------------------- */
422 /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
423 * back to another mechanism that does not require onboard RAM
424 *
425 * Caller should not check for other return values specifically
426 */
427 static int aducm360_write_block(struct flash_bank *bank,
428 const uint8_t *buffer,
429 uint32_t offset,
430 uint32_t count)
431 {
432 int choice = 0;
433
434 switch (choice) {
435 case 0:
436 return aducm360_write_block_sync(bank, buffer, offset, count);
437 break;
438 case 1:
439 return aducm360_write_block_async(bank, buffer, offset, count);
440 break;
441 default:
442 LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
443 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
444 }
445 }
446
447 /* ----------------------------------------------------------------------- */
448 #define FEESTA_WRDONE 0x00000008
449
450 static int aducm360_write_modified(struct flash_bank *bank,
451 const uint8_t *buffer,
452 uint32_t offset,
453 uint32_t count)
454 {
455 uint32_t value;
456 int res = ERROR_OK;
457 uint32_t i, j, a, d;
458 struct target *target = bank->target;
459
460 LOG_DEBUG("performing slow write (offset=0x%08" PRIx32 ", count=0x%08" PRIx32 ")...",
461 offset, count);
462
463 /* Enable the writing to the flash */
464 aducm360_set_write_enable(target, 1);
465
466 /* Clear any old status */
467 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
468
469 for (i = 0; i < count; i += 4) {
470 a = offset+i;
471 for (j = 0; i < 4; i += 1)
472 *((uint8_t *)(&d) + j) = buffer[i+j];
473 target_write_u32(target, a, d);
474 do {
475 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
476 } while (!(value & FEESTA_WRDONE));
477 }
478 aducm360_set_write_enable(target, 0);
479
480 return res;
481 }
482
483 /* ----------------------------------------------------------------------- */
484 static int aducm360_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
485 {
486 int retval;
487
488 /* try using a block write */
489 retval = aducm360_write_block(bank, buffer, offset, count);
490 if (retval != ERROR_OK) {
491 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
492 /* if block write failed (no sufficient working area),
493 * use normal (slow) JTAG method */
494 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
495
496 retval = aducm360_write_modified(bank, buffer, offset, count);
497 if (retval != ERROR_OK) {
498 LOG_ERROR("slow write failed");
499 return ERROR_FLASH_OPERATION_FAILED;
500 }
501 }
502 }
503 return retval;
504 }
505
506 /* ----------------------------------------------------------------------- */
507 static int aducm360_probe(struct flash_bank *bank)
508 {
509 return ERROR_OK;
510 }
511
512 /* ----------------------------------------------------------------------- */
513 /* sets FEECON0 bit 2
514 * enable = 1 enables writes & erases, 0 disables them */
515 static int aducm360_set_write_enable(struct target *target, int enable)
516 {
517 /* don't bother to preserve int enable bit here */
518 uint32_t value;
519
520 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, &value);
521 if (enable)
522 value |= 0x00000004;
523 else
524 value &= ~0x00000004;
525 target_write_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, value);
526
527 return ERROR_OK;
528 }
529
530 /* ----------------------------------------------------------------------- */
531 /* wait up to timeout_ms for controller to not be busy,
532 * then check whether the command passed or failed.
533 *
534 * this function sleeps 1ms between checks (after the first one),
535 * so in some cases may slow things down without a usleep after the first read */
536 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms)
537 {
538 uint32_t v = 1;
539
540 int64_t endtime = timeval_ms() + timeout_ms;
541 while (1) {
542 target_read_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEESTA, &v);
543 if ((v & 0x00000001) == 0)
544 break;
545 alive_sleep(1);
546 if (timeval_ms() >= endtime)
547 break;
548 }
549
550 if (!(v & 0x00000004)) /* b2 */
551 return ERROR_FAIL;
552
553 return ERROR_OK;
554 }
555
556 /* ----------------------------------------------------------------------- */
557 struct flash_driver aducm360_flash = {
558 .name = "aducm360",
559 .flash_bank_command = aducm360_flash_bank_command,
560 .erase = aducm360_erase,
561 .write = aducm360_write,
562 .read = default_flash_read,
563 .probe = aducm360_probe,
564 .auto_probe = aducm360_probe,
565 .erase_check = default_flash_blank_check,
566 };

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)