psoc4: support for Cypress PSoC 41xx/42xx family
[openocd.git] / src / flash / nor / non_cfi.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * Copyright (C) 2009 Michael Schwingen *
5 * michael@schwingen.org *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
21 ***************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "imp.h"
28 #include "cfi.h"
29 #include "non_cfi.h"
30
31 #define KB 1024
32 #define MB (1024*1024)
33 #define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
34
35 /* non-CFI compatible flashes */
36 static const struct non_cfi non_cfi_flashes[] = {
37 {
38 .mfr = CFI_MFR_SST,
39 .id = 0xd4,
40 .pri_id = 0x02,
41 .dev_size = 64*KB,
42 .interface_desc = 0x0, /* x8 only device */
43 .max_buf_write_size = 0x0,
44 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
45 .num_erase_regions = 1,
46 .erase_region_info = {
47 ERASE_REGION(16, 4*KB)
48 }
49 },
50 {
51 .mfr = CFI_MFR_SST,
52 .id = 0xd5,
53 .pri_id = 0x02,
54 .dev_size = 128*KB,
55 .interface_desc = 0x0, /* x8 only device */
56 .max_buf_write_size = 0x0,
57 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
58 .num_erase_regions = 1,
59 .erase_region_info = {
60 ERASE_REGION(32, 4*KB)
61 }
62 },
63 {
64 .mfr = CFI_MFR_SST,
65 .id = 0xd6,
66 .pri_id = 0x02,
67 .dev_size = 256*KB,
68 .interface_desc = 0x0, /* x8 only device */
69 .max_buf_write_size = 0x0,
70 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
71 .num_erase_regions = 1,
72 .erase_region_info = {
73 ERASE_REGION(64, 4*KB)
74 }
75 },
76 {
77 .mfr = CFI_MFR_SST,
78 .id = 0xd7,
79 .pri_id = 0x02,
80 .dev_size = 512*KB,
81 .interface_desc = 0x0, /* x8 only device */
82 .max_buf_write_size = 0x0,
83 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
84 .num_erase_regions = 1,
85 .erase_region_info = {
86 ERASE_REGION(128, 4*KB)
87 }
88 },
89 {
90 .mfr = CFI_MFR_AMD, /* Spansion AM29LV040B */
91 .id = 0x4f,
92 .pri_id = 0x02,
93 .dev_size = 512*KB,
94 .interface_desc = 0x0, /* x8 only device */
95 .max_buf_write_size = 0x0,
96 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
97 .num_erase_regions = 1,
98 .erase_region_info = {
99 ERASE_REGION(8, 64*KB)
100 }
101 },
102 {
103 .mfr = CFI_MFR_SST,
104 .id = 0x2780,
105 .pri_id = 0x02,
106 .dev_size = 512*KB,
107 .interface_desc = 0x2, /* x8 or x16 device */
108 .max_buf_write_size = 0x0,
109 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
110 .num_erase_regions = 1,
111 .erase_region_info = {
112 ERASE_REGION(128, 4*KB)
113 }
114 },
115 {
116 .mfr = CFI_MFR_ST,
117 .id = 0xd6, /* ST29F400BB */
118 .pri_id = 0x02,
119 .dev_size = 512*KB,
120 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
121 .max_buf_write_size = 0x0,
122 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
123 .num_erase_regions = 4,
124 .erase_region_info = {
125 ERASE_REGION(1, 16*KB),
126 ERASE_REGION(2, 8*KB),
127 ERASE_REGION(1, 32*KB),
128 ERASE_REGION(7, 64*KB)
129 }
130 },
131 {
132 .mfr = CFI_MFR_ST,
133 .id = 0xd5, /* ST29F400BT */
134 .pri_id = 0x02,
135 .dev_size = 512*KB,
136 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
137 .max_buf_write_size = 0x0,
138 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
139 .num_erase_regions = 4,
140 .erase_region_info = {
141 ERASE_REGION(7, 64*KB),
142 ERASE_REGION(1, 32*KB),
143 ERASE_REGION(2, 8*KB),
144 ERASE_REGION(1, 16*KB)
145 }
146 },
147
148 /* SST 39VF* do not support DQ5 status polling - this currently is
149 only supported by the host algorithm, not by the target code using
150 the work area.
151 Only true for 8-bit and 32-bit wide memories. 16-bit wide memories
152 without DQ5 status polling are supported by the target code.
153 */
154 {
155 .mfr = CFI_MFR_SST,
156 .id = 0x2782, /* SST39xF160 */
157 .pri_id = 0x02,
158 .dev_size = 2*MB,
159 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
160 .max_buf_write_size = 0x0,
161 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
162 .num_erase_regions = 1,
163 .erase_region_info = {
164 ERASE_REGION(512, 4*KB)
165 }
166 },
167 {
168 .mfr = CFI_MFR_SST,
169 .id = 0x2783, /* SST39VF320 */
170 .pri_id = 0x02,
171 .dev_size = 4*MB,
172 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
173 .max_buf_write_size = 0x0,
174 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
175 .num_erase_regions = 1,
176 .erase_region_info = {
177 ERASE_REGION(1024, 4*KB)
178 }
179 },
180 {
181 .mfr = CFI_MFR_SST,
182 .id = 0x234b, /* SST39VF1601 */
183 .pri_id = 0x02,
184 .dev_size = 2*MB,
185 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
186 .max_buf_write_size = 0x0,
187 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
188 .num_erase_regions = 1,
189 .erase_region_info = {
190 ERASE_REGION(512, 4*KB)
191 }
192 },
193 {
194 .mfr = CFI_MFR_SST,
195 .id = 0x274b, /* SST39WF1601 */
196 .pri_id = 0x02,
197 .dev_size = 2*MB,
198 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
199 .max_buf_write_size = 0x0,
200 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
201 .num_erase_regions = 1,
202 .erase_region_info = {
203 ERASE_REGION(512, 4*KB)
204 }
205 },
206 {
207 .mfr = CFI_MFR_SST,
208 .id = 0x234a, /* SST39VF1602 */
209 .pri_id = 0x02,
210 .dev_size = 2*MB,
211 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
212 .max_buf_write_size = 0x0,
213 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
214 .num_erase_regions = 1,
215 .erase_region_info = {
216 ERASE_REGION(512, 4*KB)
217 }
218 },
219 {
220 .mfr = CFI_MFR_SST,
221 .id = 0x235b, /* SST39VF3201 */
222 .pri_id = 0x02,
223 .dev_size = 4*MB,
224 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
225 .max_buf_write_size = 0x0,
226 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
227 .num_erase_regions = 1,
228 .erase_region_info = {
229 ERASE_REGION(1024, 4*KB)
230 }
231 },
232 {
233 .mfr = CFI_MFR_SST,
234 .id = 0x235a, /* SST39VF3202 */
235 .pri_id = 0x02,
236 .dev_size = 4*MB,
237 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
238 .max_buf_write_size = 0x0,
239 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
240 .num_erase_regions = 1,
241 .erase_region_info = {
242 ERASE_REGION(1024, 4*KB)
243 }
244 },
245 {
246 .mfr = CFI_MFR_SST,
247 .id = 0x236d, /* SST39VF6401B */
248 .pri_id = 0x02,
249 .dev_size = 8*MB,
250 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
251 .max_buf_write_size = 0x0,
252 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
253 .num_erase_regions = 1,
254 .erase_region_info = {
255 ERASE_REGION(2048, 4*KB)
256 }
257 },
258 {
259 .mfr = CFI_MFR_AMD,
260 .id = 0x22ab, /* AM29F400BB */
261 .pri_id = 0x02,
262 .dev_size = 512*KB,
263 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
264 .max_buf_write_size = 0x0,
265 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
266 .num_erase_regions = 4,
267 .erase_region_info = {
268 ERASE_REGION(1, 16*KB),
269 ERASE_REGION(2, 8*KB),
270 ERASE_REGION(1, 32*KB),
271 ERASE_REGION(7, 64*KB)
272 }
273 },
274 {
275 .mfr = CFI_MFR_AMD,
276 .id = 0x2223, /* AM29F400BT */
277 .pri_id = 0x02,
278 .dev_size = 512*KB,
279 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
280 .max_buf_write_size = 0x0,
281 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
282 .num_erase_regions = 4,
283 .erase_region_info = {
284 ERASE_REGION(7, 64*KB),
285 ERASE_REGION(1, 32*KB),
286 ERASE_REGION(2, 8*KB),
287 ERASE_REGION(1, 16*KB)
288 }
289 },
290 {
291 .mfr = CFI_MFR_FUJITSU,
292 .id = 0x226b, /* AM29SL800DB */
293 .pri_id = 0x02,
294 .dev_size = 1*MB,
295 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
296 .max_buf_write_size = 0x0,
297 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
298 .num_erase_regions = 4,
299 .erase_region_info = {
300 ERASE_REGION(1, 16*KB),
301 ERASE_REGION(2, 8*KB),
302 ERASE_REGION(1, 32*KB),
303 ERASE_REGION(15, 64*KB)
304 }
305 },
306 {
307 .mfr = CFI_MFR_FUJITSU,
308 .id = 0x22ea, /* MBM29SL800TE */
309 .pri_id = 0x02,
310 .dev_size = 1*MB,
311 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
312 .max_buf_write_size = 0x0,
313 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
314 .num_erase_regions = 4,
315 .erase_region_info = {
316 ERASE_REGION(15, 64*KB),
317 ERASE_REGION(1, 32*KB),
318 ERASE_REGION(2, 8*KB),
319 ERASE_REGION(1, 16*KB)
320 }
321 },
322 {
323 .mfr = CFI_MFR_FUJITSU,
324 .id = 0xba, /* 29LV400BC */
325 .pri_id = 0x02,
326 .dev_size = 512*KB,
327 .interface_desc = 0x1, /* x8 or x16 device w/ nBYTE */
328 .max_buf_write_size = 0x00,
329 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
330 .num_erase_regions = 4,
331 .erase_region_info = {
332 ERASE_REGION(1, 16*KB),
333 ERASE_REGION(2, 8*KB),
334 ERASE_REGION(1, 32*KB),
335 ERASE_REGION(7, 64*KB)
336 }
337 },
338 {
339 .mfr = CFI_MFR_AMIC,
340 .id = 0xb31a, /* A29L800A */
341 .pri_id = 0x02,
342 .dev_size = 1*MB,
343 .interface_desc = 0x2,
344 .max_buf_write_size = 0x0,
345 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
346 .num_erase_regions = 4,
347 .erase_region_info = {
348 ERASE_REGION(1, 16*KB),
349 ERASE_REGION(2, 8*KB),
350 ERASE_REGION(1, 32*KB),
351 ERASE_REGION(15, 64*KB)
352 }
353 },
354 {
355 .mfr = CFI_MFR_MX,
356 .id = 0x225b, /* MX29LV800B */
357 .pri_id = 0x02,
358 .dev_size = 1*MB,
359 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
360 .max_buf_write_size = 0x0,
361 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
362 .num_erase_regions = 4,
363 .erase_region_info = {
364 ERASE_REGION(1, 16*KB),
365 ERASE_REGION(2, 8*KB),
366 ERASE_REGION(1, 32*KB),
367 ERASE_REGION(15, 64*KB)
368 }
369 },
370
371 {
372 .mfr = CFI_MFR_MX,
373 .id = 0x2249, /* MX29LV160AB: 2MB */
374 .pri_id = 0x02,
375 .dev_size = 2*MB,
376 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
377 .max_buf_write_size = 0x0,
378 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
379 .num_erase_regions = 4,
380 .erase_region_info = {
381 ERASE_REGION(1, 16*KB),
382 ERASE_REGION(2, 8*KB),
383 ERASE_REGION(1, 32*KB),
384 ERASE_REGION(31, 64*KB)
385 }
386 },
387 {
388 .mfr = CFI_MFR_MX,
389 .id = 0x22C4, /* MX29LV160AT: 2MB */
390 .pri_id = 0x02,
391 .dev_size = 2*MB,
392 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
393 .max_buf_write_size = 0x0,
394 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
395 .num_erase_regions = 4,
396 .erase_region_info = {
397 ERASE_REGION(31, 64*KB),
398 ERASE_REGION(1, 32*KB),
399 ERASE_REGION(2, 8*KB),
400 ERASE_REGION(1, 16*KB)
401 }
402 },
403 {
404 .mfr = CFI_MFR_EON,
405 .id = 0x225b, /* EN29LV800BB */
406 .pri_id = 0x02,
407 .dev_size = 1*MB,
408 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
409 .max_buf_write_size = 0x0,
410 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
411 .num_erase_regions = 4,
412 .erase_region_info = {
413 ERASE_REGION(1, 16*KB),
414 ERASE_REGION(2, 8*KB),
415 ERASE_REGION(1, 32*KB),
416 ERASE_REGION(15, 64*KB)
417 }
418 },
419 {
420 .mfr = CFI_MFR_ATMEL,
421 .id = 0x00c0, /* Atmel 49BV1614 */
422 .pri_id = 0x02,
423 .dev_size = 2*MB,
424 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
425 .max_buf_write_size = 0x0,
426 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
427 .num_erase_regions = 3,
428 .erase_region_info = {
429 ERASE_REGION(8, 8*KB),
430 ERASE_REGION(2, 32*KB),
431 ERASE_REGION(30, 64*KB)
432 }
433 },
434 {
435 .mfr = CFI_MFR_ATMEL,
436 .id = 0xC2, /* Atmel 49BV1614T */
437 .pri_id = 0x02,
438 .dev_size = 2*MB,
439 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
440 .max_buf_write_size = 0x0,
441 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
442 .num_erase_regions = 3,
443 .erase_region_info = {
444 ERASE_REGION(30, 64*KB),
445 ERASE_REGION(2, 32*KB),
446 ERASE_REGION(8, 8*KB)
447 }
448 },
449 {
450 .mfr = CFI_MFR_AMD,
451 .id = 0x225b, /* S29AL008D */
452 .pri_id = 0x02,
453 .dev_size = 1*MB,
454 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
455 .max_buf_write_size = 0x0,
456 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
457 .num_erase_regions = 4,
458 .erase_region_info = {
459 ERASE_REGION(1, 16*KB),
460 ERASE_REGION(2, 8*KB),
461 ERASE_REGION(1, 32*KB),
462 ERASE_REGION(15, 64*KB)
463 }
464 },
465 {
466 .mfr = 0,
467 .id = 0,
468 }
469 };
470
471 void cfi_fixup_non_cfi(struct flash_bank *bank)
472 {
473 unsigned int mask;
474 struct cfi_flash_bank *cfi_info = bank->driver_priv;
475 const struct non_cfi *non_cfi = non_cfi_flashes;
476
477 if (cfi_info->x16_as_x8)
478 mask = 0xFF;
479 else
480 mask = 0xFFFF;
481
482 for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++) {
483 if ((cfi_info->manufacturer == non_cfi->mfr)
484 && (cfi_info->device_id == (non_cfi->id & mask)))
485 break;
486 }
487
488 /* only fixup jedec flashs found in table */
489 if (!non_cfi->mfr)
490 return;
491
492 cfi_info->not_cfi = 1;
493
494 /* fill in defaults for non-critical data */
495 cfi_info->vcc_min = 0x0;
496 cfi_info->vcc_max = 0x0;
497 cfi_info->vpp_min = 0x0;
498 cfi_info->vpp_max = 0x0;
499 /* these are used for timeouts - use vales that should be long enough
500 for normal operation. */
501 cfi_info->word_write_timeout_typ = 0x0a;
502 cfi_info->buf_write_timeout_typ = 0x0d;
503 cfi_info->block_erase_timeout_typ = 0x0d;
504 cfi_info->chip_erase_timeout_typ = 0x10;
505 cfi_info->word_write_timeout_max = 0x0;
506 cfi_info->buf_write_timeout_max = 0x0;
507 cfi_info->block_erase_timeout_max = 0x0;
508 cfi_info->chip_erase_timeout_max = 0x0;
509
510 cfi_info->qry[0] = 'Q';
511 cfi_info->qry[1] = 'R';
512 cfi_info->qry[2] = 'Y';
513
514 cfi_info->pri_id = non_cfi->pri_id;
515 cfi_info->pri_addr = 0x0;
516 cfi_info->alt_id = 0x0;
517 cfi_info->alt_addr = 0x0;
518 cfi_info->alt_ext = NULL;
519
520 cfi_info->interface_desc = non_cfi->interface_desc;
521 cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
522 cfi_info->status_poll_mask = non_cfi->status_poll_mask;
523 cfi_info->num_erase_regions = non_cfi->num_erase_regions;
524 size_t erase_region_info_size = sizeof(*cfi_info->erase_region_info) *
525 cfi_info->num_erase_regions;
526 cfi_info->erase_region_info = malloc(erase_region_info_size);
527 memcpy(cfi_info->erase_region_info,
528 non_cfi->erase_region_info, erase_region_info_size);
529 cfi_info->dev_size = non_cfi->dev_size;
530
531 if (cfi_info->pri_id == 0x2) {
532 struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
533
534 pri_ext->pri[0] = 'P';
535 pri_ext->pri[1] = 'R';
536 pri_ext->pri[2] = 'I';
537
538 pri_ext->major_version = '1';
539 pri_ext->minor_version = '0';
540
541 pri_ext->SiliconRevision = 0x0;
542 pri_ext->EraseSuspend = 0x0;
543 pri_ext->EraseSuspend = 0x0;
544 pri_ext->BlkProt = 0x0;
545 pri_ext->TmpBlkUnprotect = 0x0;
546 pri_ext->BlkProtUnprot = 0x0;
547 pri_ext->SimultaneousOps = 0x0;
548 pri_ext->BurstMode = 0x0;
549 pri_ext->PageMode = 0x0;
550 pri_ext->VppMin = 0x0;
551 pri_ext->VppMax = 0x0;
552 pri_ext->TopBottom = 0x0;
553
554 pri_ext->_unlock1 = 0x5555;
555 pri_ext->_unlock2 = 0x2AAA;
556 pri_ext->_reversed_geometry = 0;
557
558 cfi_info->pri_ext = pri_ext;
559 } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3)) {
560 LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
561 exit(-1);
562 }
563 }

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)