78d52b877aa970ce01fa27b518215654e16cdb53
[openocd.git] / src / flash / nor / nrf5.c
1 /***************************************************************************
2 * Copyright (C) 2013 Synapse Product Development *
3 * Andrey Smirnov <andrew.smironv@gmail.com> *
4 * Angus Gratton <gus@projectgus.com> *
5 * Erdem U. Altunyurt <spamjunkeater@gmail.com> *
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, see <http://www.gnu.org/licenses/>. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "imp.h"
26 #include <target/algorithm.h>
27 #include <target/armv7m.h>
28 #include <helper/types.h>
29 #include <helper/time_support.h>
30
31 enum {
32 NRF5_FLASH_BASE = 0x00000000,
33 };
34
35 enum nrf5_ficr_registers {
36 NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */
37
38 #define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset)
39
40 NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010),
41 NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014),
42 NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028),
43 NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C),
44 NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034),
45 NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038),
46 NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
47 NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
48 NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
49 NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C),
50 NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060),
51 NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064),
52 NRF5_FICR_ER0 = NRF5_FICR_REG(0x080),
53 NRF5_FICR_ER1 = NRF5_FICR_REG(0x084),
54 NRF5_FICR_ER2 = NRF5_FICR_REG(0x088),
55 NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C),
56 NRF5_FICR_IR0 = NRF5_FICR_REG(0x090),
57 NRF5_FICR_IR1 = NRF5_FICR_REG(0x094),
58 NRF5_FICR_IR2 = NRF5_FICR_REG(0x098),
59 NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C),
60 NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0),
61 NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4),
62 NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8),
63 NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC),
64 NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0),
65 NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4),
66 NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8),
67 NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC),
68 NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0),
69 NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC),
70 NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0),
71 NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4),
72 NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8),
73 NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC),
74 };
75
76 enum nrf5_uicr_registers {
77 NRF5_UICR_BASE = 0x10001000, /* User Information
78 * Configuration Regsters */
79
80 NRF5_UICR_SIZE = 0x100,
81
82 #define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
83
84 NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000),
85 NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004),
86 NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008),
87 NRF5_UICR_FWID = NRF5_UICR_REG(0x010),
88 };
89
90 enum nrf5_nvmc_registers {
91 NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory
92 * Controller Regsters */
93
94 #define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset)
95
96 NRF5_NVMC_READY = NRF5_NVMC_REG(0x400),
97 NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504),
98 NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508),
99 NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C),
100 NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514),
101 };
102
103 enum nrf5_nvmc_config_bits {
104 NRF5_NVMC_CONFIG_REN = 0x00,
105 NRF5_NVMC_CONFIG_WEN = 0x01,
106 NRF5_NVMC_CONFIG_EEN = 0x02,
107
108 };
109
110 struct nrf5_info {
111 uint32_t code_page_size;
112 uint32_t refcount;
113
114 struct nrf5_bank {
115 struct nrf5_info *chip;
116 bool probed;
117 int (*write) (struct flash_bank *bank,
118 struct nrf5_info *chip,
119 const uint8_t *buffer, uint32_t offset, uint32_t count);
120 } bank[2];
121 struct target *target;
122 };
123
124 struct nrf5_device_spec {
125 uint16_t hwid;
126 const char *part;
127 const char *variant;
128 const char *build_code;
129 unsigned int flash_size_kb;
130 };
131
132 #define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \
133 { \
134 .hwid = (id), \
135 .part = pt, \
136 .variant = var, \
137 .build_code = bcode, \
138 .flash_size_kb = (fsize), \
139 }
140
141 /* The known devices table below is derived from the "nRF51 Series
142 * Compatibility Matrix" document, which can be found by searching for
143 * ATTN-51 on the Nordic Semi website:
144 *
145 * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51
146 *
147 * Up to date with Matrix v2.0, plus some additional HWIDs.
148 *
149 * The additional HWIDs apply where the build code in the matrix is
150 * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is
151 * for x==0, x!=0 means different (unspecified) HWIDs.
152 */
153 static const struct nrf5_device_spec nrf5_known_devices_table[] = {
154 /* nRF51822 Devices (IC rev 1). */
155 NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256),
156 NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128),
157 NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128),
158 NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
159 NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
160
161 /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
162 with built-in jlink seem to use engineering samples not listed
163 in the nRF51 Series Compatibility Matrix V1.0. */
164 NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
165
166 /* nRF51822 Devices (IC rev 2). */
167 NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
168 NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
169 NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256),
170 NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256),
171 NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256),
172 NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128),
173 NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256),
174 NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256),
175 NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256),
176
177 /* nRF51822 Devices (IC rev 3). */
178 NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
179 NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
180 NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
181 NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
182 NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
183 NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
184 NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
185 NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
186 NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
187
188 /* nRF51422 Devices (IC rev 1). */
189 NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
190 NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256),
191 NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256),
192
193 /* nRF51422 Devices (IC rev 2). */
194 NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256),
195 NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256),
196 NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128),
197 NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256),
198
199 /* nRF51422 Devices (IC rev 3). */
200 NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256),
201 NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128),
202 NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256),
203 NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256),
204 NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128),
205 NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
206 NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
207
208 /* nRF52810 Devices */
209 NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192),
210 NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192),
211
212 /* nRF52832 Devices */
213 NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
214 NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
215 NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
216
217 /* nRF52840 Devices */
218 NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
219 };
220
221 static int nrf5_bank_is_probed(struct flash_bank *bank)
222 {
223 struct nrf5_bank *nbank = bank->driver_priv;
224
225 assert(nbank != NULL);
226
227 return nbank->probed;
228 }
229 static int nrf5_probe(struct flash_bank *bank);
230
231 static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip)
232 {
233 if (bank->target->state != TARGET_HALTED) {
234 LOG_ERROR("Target not halted");
235 return ERROR_TARGET_NOT_HALTED;
236 }
237
238 struct nrf5_bank *nbank = bank->driver_priv;
239 *chip = nbank->chip;
240
241 int probed = nrf5_bank_is_probed(bank);
242 if (probed < 0)
243 return probed;
244 else if (!probed)
245 return nrf5_probe(bank);
246 else
247 return ERROR_OK;
248 }
249
250 static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
251 {
252 uint32_t ready;
253 int res;
254 int timeout_ms = 340;
255 int64_t ts_start = timeval_ms();
256
257 do {
258 res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready);
259 if (res != ERROR_OK) {
260 LOG_ERROR("Couldn't read NVMC_READY register");
261 return res;
262 }
263
264 if (ready == 0x00000001)
265 return ERROR_OK;
266
267 keep_alive();
268
269 } while ((timeval_ms()-ts_start) < timeout_ms);
270
271 LOG_DEBUG("Timed out waiting for NVMC_READY");
272 return ERROR_FLASH_BUSY;
273 }
274
275 static int nrf5_nvmc_erase_enable(struct nrf5_info *chip)
276 {
277 int res;
278 res = target_write_u32(chip->target,
279 NRF5_NVMC_CONFIG,
280 NRF5_NVMC_CONFIG_EEN);
281
282 if (res != ERROR_OK) {
283 LOG_ERROR("Failed to enable erase operation");
284 return res;
285 }
286
287 /*
288 According to NVMC examples in Nordic SDK busy status must be
289 checked after writing to NVMC_CONFIG
290 */
291 res = nrf5_wait_for_nvmc(chip);
292 if (res != ERROR_OK)
293 LOG_ERROR("Erase enable did not complete");
294
295 return res;
296 }
297
298 static int nrf5_nvmc_write_enable(struct nrf5_info *chip)
299 {
300 int res;
301 res = target_write_u32(chip->target,
302 NRF5_NVMC_CONFIG,
303 NRF5_NVMC_CONFIG_WEN);
304
305 if (res != ERROR_OK) {
306 LOG_ERROR("Failed to enable write operation");
307 return res;
308 }
309
310 /*
311 According to NVMC examples in Nordic SDK busy status must be
312 checked after writing to NVMC_CONFIG
313 */
314 res = nrf5_wait_for_nvmc(chip);
315 if (res != ERROR_OK)
316 LOG_ERROR("Write enable did not complete");
317
318 return res;
319 }
320
321 static int nrf5_nvmc_read_only(struct nrf5_info *chip)
322 {
323 int res;
324 res = target_write_u32(chip->target,
325 NRF5_NVMC_CONFIG,
326 NRF5_NVMC_CONFIG_REN);
327
328 if (res != ERROR_OK) {
329 LOG_ERROR("Failed to enable read-only operation");
330 return res;
331 }
332 /*
333 According to NVMC examples in Nordic SDK busy status must be
334 checked after writing to NVMC_CONFIG
335 */
336 res = nrf5_wait_for_nvmc(chip);
337 if (res != ERROR_OK)
338 LOG_ERROR("Read only enable did not complete");
339
340 return res;
341 }
342
343 static int nrf5_nvmc_generic_erase(struct nrf5_info *chip,
344 uint32_t erase_register, uint32_t erase_value)
345 {
346 int res;
347
348 res = nrf5_nvmc_erase_enable(chip);
349 if (res != ERROR_OK)
350 goto error;
351
352 res = target_write_u32(chip->target,
353 erase_register,
354 erase_value);
355 if (res != ERROR_OK)
356 goto set_read_only;
357
358 res = nrf5_wait_for_nvmc(chip);
359 if (res != ERROR_OK)
360 goto set_read_only;
361
362 return nrf5_nvmc_read_only(chip);
363
364 set_read_only:
365 nrf5_nvmc_read_only(chip);
366 error:
367 LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32,
368 erase_register, erase_value);
369 return ERROR_FAIL;
370 }
371
372 static int nrf5_protect_check(struct flash_bank *bank)
373 {
374 int res;
375 uint32_t clenr0;
376
377 /* UICR cannot be write protected so just return early */
378 if (bank->base == NRF5_UICR_BASE)
379 return ERROR_OK;
380
381 struct nrf5_bank *nbank = bank->driver_priv;
382 struct nrf5_info *chip = nbank->chip;
383
384 assert(chip != NULL);
385
386 res = target_read_u32(chip->target, NRF5_FICR_CLENR0,
387 &clenr0);
388 if (res != ERROR_OK) {
389 LOG_ERROR("Couldn't read code region 0 size[FICR]");
390 return res;
391 }
392
393 if (clenr0 == 0xFFFFFFFF) {
394 res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
395 &clenr0);
396 if (res != ERROR_OK) {
397 LOG_ERROR("Couldn't read code region 0 size[UICR]");
398 return res;
399 }
400 }
401
402 for (int i = 0; i < bank->num_sectors; i++)
403 bank->sectors[i].is_protected =
404 clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0;
405
406 return ERROR_OK;
407 }
408
409 static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
410 {
411 int res;
412 uint32_t clenr0, ppfc;
413 struct nrf5_info *chip;
414
415 /* UICR cannot be write protected so just bail out early */
416 if (bank->base == NRF5_UICR_BASE)
417 return ERROR_FAIL;
418
419 res = nrf5_get_probed_chip_if_halted(bank, &chip);
420 if (res != ERROR_OK)
421 return res;
422
423 if (first != 0) {
424 LOG_ERROR("Code region 0 must start at the begining of the bank");
425 return ERROR_FAIL;
426 }
427
428 res = target_read_u32(chip->target, NRF5_FICR_PPFC,
429 &ppfc);
430 if (res != ERROR_OK) {
431 LOG_ERROR("Couldn't read PPFC register");
432 return res;
433 }
434
435 if ((ppfc & 0xFF) == 0x00) {
436 LOG_ERROR("Code region 0 size was pre-programmed at the factory, can't change flash protection settings");
437 return ERROR_FAIL;
438 }
439
440 res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
441 &clenr0);
442 if (res != ERROR_OK) {
443 LOG_ERROR("Couldn't read code region 0 size[UICR]");
444 return res;
445 }
446
447 if (clenr0 == 0xFFFFFFFF) {
448 res = target_write_u32(chip->target, NRF5_UICR_CLENR0,
449 clenr0);
450 if (res != ERROR_OK) {
451 LOG_ERROR("Couldn't write code region 0 size[UICR]");
452 return res;
453 }
454
455 } else {
456 LOG_ERROR("You need to perform chip erase before changing the protection settings");
457 }
458
459 nrf5_protect_check(bank);
460
461 return ERROR_OK;
462 }
463
464 static int nrf5_probe(struct flash_bank *bank)
465 {
466 uint32_t hwid;
467 int res;
468 struct nrf5_bank *nbank = bank->driver_priv;
469 struct nrf5_info *chip = nbank->chip;
470
471 res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid);
472 if (res != ERROR_OK) {
473 LOG_ERROR("Couldn't read CONFIGID register");
474 return res;
475 }
476
477 hwid &= 0xFFFF; /* HWID is stored in the lower two
478 * bytes of the CONFIGID register */
479
480 const struct nrf5_device_spec *spec = NULL;
481 for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) {
482 if (hwid == nrf5_known_devices_table[i].hwid) {
483 spec = &nrf5_known_devices_table[i];
484 break;
485 }
486 }
487
488 if (!chip->bank[0].probed && !chip->bank[1].probed) {
489 if (spec)
490 LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash",
491 spec->part, spec->variant, spec->build_code,
492 spec->flash_size_kb);
493 else
494 LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid);
495 }
496
497 if (bank->base == NRF5_FLASH_BASE) {
498 /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
499 res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
500 &chip->code_page_size);
501 if (res != ERROR_OK) {
502 LOG_ERROR("Couldn't read code page size");
503 return res;
504 }
505
506 /* Note the register name is misleading,
507 * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
508 uint32_t num_sectors;
509 res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors);
510 if (res != ERROR_OK) {
511 LOG_ERROR("Couldn't read code memory size");
512 return res;
513 }
514
515 bank->num_sectors = num_sectors;
516 bank->size = num_sectors * chip->code_page_size;
517
518 if (spec && bank->size / 1024 != spec->flash_size_kb)
519 LOG_WARNING("Chip's reported Flash capacity does not match expected one");
520
521 bank->sectors = calloc(bank->num_sectors,
522 sizeof((bank->sectors)[0]));
523 if (!bank->sectors)
524 return ERROR_FLASH_BANK_NOT_PROBED;
525
526 /* Fill out the sector information: all NRF5 sectors are the same size and
527 * there is always a fixed number of them. */
528 for (int i = 0; i < bank->num_sectors; i++) {
529 bank->sectors[i].size = chip->code_page_size;
530 bank->sectors[i].offset = i * chip->code_page_size;
531
532 /* mark as unknown */
533 bank->sectors[i].is_erased = -1;
534 bank->sectors[i].is_protected = -1;
535 }
536
537 nrf5_protect_check(bank);
538
539 chip->bank[0].probed = true;
540 } else {
541 bank->size = NRF5_UICR_SIZE;
542 bank->num_sectors = 1;
543 bank->sectors = calloc(bank->num_sectors,
544 sizeof((bank->sectors)[0]));
545 if (!bank->sectors)
546 return ERROR_FLASH_BANK_NOT_PROBED;
547
548 bank->sectors[0].size = bank->size;
549 bank->sectors[0].offset = 0;
550
551 bank->sectors[0].is_erased = 0;
552 bank->sectors[0].is_protected = 0;
553
554 chip->bank[1].probed = true;
555 }
556
557 return ERROR_OK;
558 }
559
560 static int nrf5_auto_probe(struct flash_bank *bank)
561 {
562 int probed = nrf5_bank_is_probed(bank);
563
564 if (probed < 0)
565 return probed;
566 else if (probed)
567 return ERROR_OK;
568 else
569 return nrf5_probe(bank);
570 }
571
572 static int nrf5_erase_all(struct nrf5_info *chip)
573 {
574 LOG_DEBUG("Erasing all non-volatile memory");
575 return nrf5_nvmc_generic_erase(chip,
576 NRF5_NVMC_ERASEALL,
577 0x00000001);
578 }
579
580 static int nrf5_erase_page(struct flash_bank *bank,
581 struct nrf5_info *chip,
582 struct flash_sector *sector)
583 {
584 int res;
585
586 LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
587 if (sector->is_protected) {
588 LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
589 return ERROR_FAIL;
590 }
591
592 if (bank->base == NRF5_UICR_BASE) {
593 uint32_t ppfc;
594 res = target_read_u32(chip->target, NRF5_FICR_PPFC,
595 &ppfc);
596 if (res != ERROR_OK) {
597 LOG_ERROR("Couldn't read PPFC register");
598 return res;
599 }
600
601 if ((ppfc & 0xFF) == 0xFF) {
602 /* We can't erase the UICR. Double-check to
603 see if it's already erased before complaining. */
604 default_flash_blank_check(bank);
605 if (sector->is_erased == 1)
606 return ERROR_OK;
607
608 LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
609 return ERROR_FAIL;
610 }
611
612 res = nrf5_nvmc_generic_erase(chip,
613 NRF5_NVMC_ERASEUICR,
614 0x00000001);
615
616
617 } else {
618 res = nrf5_nvmc_generic_erase(chip,
619 NRF5_NVMC_ERASEPAGE,
620 sector->offset);
621 }
622
623 return res;
624 }
625
626 static const uint8_t nrf5_flash_write_code[] = {
627 /* See contrib/loaders/flash/cortex-m0.S */
628 /* <wait_fifo>: */
629 0x0d, 0x68, /* ldr r5, [r1, #0] */
630 0x00, 0x2d, /* cmp r5, #0 */
631 0x0b, 0xd0, /* beq.n 1e <exit> */
632 0x4c, 0x68, /* ldr r4, [r1, #4] */
633 0xac, 0x42, /* cmp r4, r5 */
634 0xf9, 0xd0, /* beq.n 0 <wait_fifo> */
635 0x20, 0xcc, /* ldmia r4!, {r5} */
636 0x20, 0xc3, /* stmia r3!, {r5} */
637 0x94, 0x42, /* cmp r4, r2 */
638 0x01, 0xd3, /* bcc.n 18 <no_wrap> */
639 0x0c, 0x46, /* mov r4, r1 */
640 0x08, 0x34, /* adds r4, #8 */
641 /* <no_wrap>: */
642 0x4c, 0x60, /* str r4, [r1, #4] */
643 0x04, 0x38, /* subs r0, #4 */
644 0xf0, 0xd1, /* bne.n 0 <wait_fifo> */
645 /* <exit>: */
646 0x00, 0xbe /* bkpt 0x0000 */
647 };
648
649
650 /* Start a low level flash write for the specified region */
651 static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
652 {
653 struct target *target = chip->target;
654 uint32_t buffer_size = 8192;
655 struct working_area *write_algorithm;
656 struct working_area *source;
657 uint32_t address = NRF5_FLASH_BASE + offset;
658 struct reg_param reg_params[4];
659 struct armv7m_algorithm armv7m_info;
660 int retval = ERROR_OK;
661
662
663 LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
664 assert(bytes % 4 == 0);
665
666 /* allocate working area with flash programming code */
667 if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code),
668 &write_algorithm) != ERROR_OK) {
669 LOG_WARNING("no working area available, falling back to slow memory writes");
670
671 for (; bytes > 0; bytes -= 4) {
672 retval = target_write_memory(chip->target, offset, 4, 1, buffer);
673 if (retval != ERROR_OK)
674 return retval;
675
676 retval = nrf5_wait_for_nvmc(chip);
677 if (retval != ERROR_OK)
678 return retval;
679
680 offset += 4;
681 buffer += 4;
682 }
683
684 return ERROR_OK;
685 }
686
687 LOG_WARNING("using fast async flash loader. This is currently supported");
688 LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
689 LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it");
690
691 retval = target_write_buffer(target, write_algorithm->address,
692 sizeof(nrf5_flash_write_code),
693 nrf5_flash_write_code);
694 if (retval != ERROR_OK)
695 return retval;
696
697 /* memory buffer */
698 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
699 buffer_size /= 2;
700 buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
701 if (buffer_size <= 256) {
702 /* free working area, write algorithm already allocated */
703 target_free_working_area(target, write_algorithm);
704
705 LOG_WARNING("No large enough working area available, can't do block memory writes");
706 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
707 }
708 }
709
710 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
711 armv7m_info.core_mode = ARM_MODE_THREAD;
712
713 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */
714 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer start */
715 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* buffer end */
716 init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT); /* target address */
717
718 buf_set_u32(reg_params[0].value, 0, 32, bytes);
719 buf_set_u32(reg_params[1].value, 0, 32, source->address);
720 buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
721 buf_set_u32(reg_params[3].value, 0, 32, address);
722
723 retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
724 0, NULL,
725 4, reg_params,
726 source->address, source->size,
727 write_algorithm->address, 0,
728 &armv7m_info);
729
730 target_free_working_area(target, source);
731 target_free_working_area(target, write_algorithm);
732
733 destroy_reg_param(&reg_params[0]);
734 destroy_reg_param(&reg_params[1]);
735 destroy_reg_param(&reg_params[2]);
736 destroy_reg_param(&reg_params[3]);
737
738 return retval;
739 }
740
741 /* Check and erase flash sectors in specified range then start a low level page write.
742 start/end must be sector aligned.
743 */
744 static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
745 {
746 int res = ERROR_FAIL;
747 struct nrf5_bank *nbank = bank->driver_priv;
748 struct nrf5_info *chip = nbank->chip;
749
750 assert(start % chip->code_page_size == 0);
751 assert(end % chip->code_page_size == 0);
752
753 res = nrf5_nvmc_write_enable(chip);
754 if (res != ERROR_OK)
755 goto error;
756
757 res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
758 if (res != ERROR_OK)
759 goto error;
760
761 return nrf5_nvmc_read_only(chip);
762
763 error:
764 nrf5_nvmc_read_only(chip);
765 LOG_ERROR("Failed to write to nrf5 flash");
766 return res;
767 }
768
769 static int nrf5_erase(struct flash_bank *bank, int first, int last)
770 {
771 int res;
772 struct nrf5_info *chip;
773
774 res = nrf5_get_probed_chip_if_halted(bank, &chip);
775 if (res != ERROR_OK)
776 return res;
777
778 /* For each sector to be erased */
779 for (int s = first; s <= last && res == ERROR_OK; s++)
780 res = nrf5_erase_page(bank, chip, &bank->sectors[s]);
781
782 return res;
783 }
784
785 static int nrf5_code_flash_write(struct flash_bank *bank,
786 struct nrf5_info *chip,
787 const uint8_t *buffer, uint32_t offset, uint32_t count)
788 {
789
790 int res;
791 /* Need to perform reads to fill any gaps we need to preserve in the first page,
792 before the start of buffer, or in the last page, after the end of buffer */
793 uint32_t first_page = offset/chip->code_page_size;
794 uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
795
796 uint32_t first_page_offset = first_page * chip->code_page_size;
797 uint32_t last_page_offset = last_page * chip->code_page_size;
798
799 LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
800 offset, offset+count, first_page_offset, last_page_offset);
801
802 uint32_t page_cnt = last_page - first_page;
803 uint8_t buffer_to_flash[page_cnt*chip->code_page_size];
804
805 /* Fill in any space between start of first page and start of buffer */
806 uint32_t pre = offset - first_page_offset;
807 if (pre > 0) {
808 res = target_read_memory(bank->target,
809 first_page_offset,
810 1,
811 pre,
812 buffer_to_flash);
813 if (res != ERROR_OK)
814 return res;
815 }
816
817 /* Fill in main contents of buffer */
818 memcpy(buffer_to_flash+pre, buffer, count);
819
820 /* Fill in any space between end of buffer and end of last page */
821 uint32_t post = last_page_offset - (offset+count);
822 if (post > 0) {
823 /* Retrieve the full row contents from Flash */
824 res = target_read_memory(bank->target,
825 offset + count,
826 1,
827 post,
828 buffer_to_flash+pre+count);
829 if (res != ERROR_OK)
830 return res;
831 }
832
833 return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
834 }
835
836 static int nrf5_uicr_flash_write(struct flash_bank *bank,
837 struct nrf5_info *chip,
838 const uint8_t *buffer, uint32_t offset, uint32_t count)
839 {
840 int res;
841 uint8_t uicr[NRF5_UICR_SIZE];
842 struct flash_sector *sector = &bank->sectors[0];
843
844 if ((offset + count) > NRF5_UICR_SIZE)
845 return ERROR_FAIL;
846
847 res = target_read_memory(bank->target,
848 NRF5_UICR_BASE,
849 1,
850 NRF5_UICR_SIZE,
851 uicr);
852
853 if (res != ERROR_OK)
854 return res;
855
856 res = nrf5_erase_page(bank, chip, sector);
857 if (res != ERROR_OK)
858 return res;
859
860 res = nrf5_nvmc_write_enable(chip);
861 if (res != ERROR_OK)
862 return res;
863
864 memcpy(&uicr[offset], buffer, count);
865
866 res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE);
867 if (res != ERROR_OK) {
868 nrf5_nvmc_read_only(chip);
869 return res;
870 }
871
872 return nrf5_nvmc_read_only(chip);
873 }
874
875
876 static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
877 uint32_t offset, uint32_t count)
878 {
879 int res;
880 struct nrf5_bank *nbank = bank->driver_priv;
881 struct nrf5_info *chip;
882
883 res = nrf5_get_probed_chip_if_halted(bank, &chip);
884 if (res != ERROR_OK)
885 return res;
886
887 return nbank->write(bank, chip, buffer, offset, count);
888 }
889
890 static void nrf5_free_driver_priv(struct flash_bank *bank)
891 {
892 struct nrf5_bank *nbank = bank->driver_priv;
893 struct nrf5_info *chip = nbank->chip;
894 if (chip == NULL)
895 return;
896
897 chip->refcount--;
898 if (chip->refcount == 0) {
899 free(chip);
900 bank->driver_priv = NULL;
901 }
902 }
903
904 FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
905 {
906 static struct nrf5_info *chip;
907 struct nrf5_bank *nbank = NULL;
908
909 switch (bank->base) {
910 case NRF5_FLASH_BASE:
911 case NRF5_UICR_BASE:
912 break;
913 default:
914 LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
915 return ERROR_FAIL;
916 }
917
918 if (!chip) {
919 /* Create a new chip */
920 chip = calloc(1, sizeof(*chip));
921 if (!chip)
922 return ERROR_FAIL;
923
924 chip->target = bank->target;
925 }
926
927 switch (bank->base) {
928 case NRF5_FLASH_BASE:
929 nbank = &chip->bank[0];
930 nbank->write = nrf5_code_flash_write;
931 break;
932 case NRF5_UICR_BASE:
933 nbank = &chip->bank[1];
934 nbank->write = nrf5_uicr_flash_write;
935 break;
936 }
937 assert(nbank != NULL);
938
939 chip->refcount++;
940 nbank->chip = chip;
941 nbank->probed = false;
942 bank->driver_priv = nbank;
943
944 return ERROR_OK;
945 }
946
947 COMMAND_HANDLER(nrf5_handle_mass_erase_command)
948 {
949 int res;
950 struct flash_bank *bank = NULL;
951 struct target *target = get_current_target(CMD_CTX);
952
953 res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank);
954 if (res != ERROR_OK)
955 return res;
956
957 assert(bank != NULL);
958
959 struct nrf5_info *chip;
960
961 res = nrf5_get_probed_chip_if_halted(bank, &chip);
962 if (res != ERROR_OK)
963 return res;
964
965 uint32_t ppfc;
966
967 res = target_read_u32(target, NRF5_FICR_PPFC,
968 &ppfc);
969 if (res != ERROR_OK) {
970 LOG_ERROR("Couldn't read PPFC register");
971 return res;
972 }
973
974 if ((ppfc & 0xFF) == 0x00) {
975 LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
976 "mass erase command won't work.");
977 return ERROR_FAIL;
978 }
979
980 res = nrf5_erase_all(chip);
981 if (res != ERROR_OK) {
982 LOG_ERROR("Failed to erase the chip");
983 nrf5_protect_check(bank);
984 return res;
985 }
986
987 res = nrf5_protect_check(bank);
988 if (res != ERROR_OK) {
989 LOG_ERROR("Failed to check chip's write protection");
990 return res;
991 }
992
993 res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank);
994 if (res != ERROR_OK)
995 return res;
996
997 return ERROR_OK;
998 }
999
1000 static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
1001 {
1002 int res;
1003
1004 struct nrf5_info *chip;
1005
1006 res = nrf5_get_probed_chip_if_halted(bank, &chip);
1007 if (res != ERROR_OK)
1008 return res;
1009
1010 static struct {
1011 const uint32_t address;
1012 uint32_t value;
1013 } ficr[] = {
1014 { .address = NRF5_FICR_CODEPAGESIZE },
1015 { .address = NRF5_FICR_CODESIZE },
1016 { .address = NRF5_FICR_CLENR0 },
1017 { .address = NRF5_FICR_PPFC },
1018 { .address = NRF5_FICR_NUMRAMBLOCK },
1019 { .address = NRF5_FICR_SIZERAMBLOCK0 },
1020 { .address = NRF5_FICR_SIZERAMBLOCK1 },
1021 { .address = NRF5_FICR_SIZERAMBLOCK2 },
1022 { .address = NRF5_FICR_SIZERAMBLOCK3 },
1023 { .address = NRF5_FICR_CONFIGID },
1024 { .address = NRF5_FICR_DEVICEID0 },
1025 { .address = NRF5_FICR_DEVICEID1 },
1026 { .address = NRF5_FICR_ER0 },
1027 { .address = NRF5_FICR_ER1 },
1028 { .address = NRF5_FICR_ER2 },
1029 { .address = NRF5_FICR_ER3 },
1030 { .address = NRF5_FICR_IR0 },
1031 { .address = NRF5_FICR_IR1 },
1032 { .address = NRF5_FICR_IR2 },
1033 { .address = NRF5_FICR_IR3 },
1034 { .address = NRF5_FICR_DEVICEADDRTYPE },
1035 { .address = NRF5_FICR_DEVICEADDR0 },
1036 { .address = NRF5_FICR_DEVICEADDR1 },
1037 { .address = NRF5_FICR_OVERRIDEN },
1038 { .address = NRF5_FICR_NRF_1MBIT0 },
1039 { .address = NRF5_FICR_NRF_1MBIT1 },
1040 { .address = NRF5_FICR_NRF_1MBIT2 },
1041 { .address = NRF5_FICR_NRF_1MBIT3 },
1042 { .address = NRF5_FICR_NRF_1MBIT4 },
1043 { .address = NRF5_FICR_BLE_1MBIT0 },
1044 { .address = NRF5_FICR_BLE_1MBIT1 },
1045 { .address = NRF5_FICR_BLE_1MBIT2 },
1046 { .address = NRF5_FICR_BLE_1MBIT3 },
1047 { .address = NRF5_FICR_BLE_1MBIT4 },
1048 }, uicr[] = {
1049 { .address = NRF5_UICR_CLENR0, },
1050 { .address = NRF5_UICR_RBPCONF },
1051 { .address = NRF5_UICR_XTALFREQ },
1052 { .address = NRF5_UICR_FWID },
1053 };
1054
1055 for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) {
1056 res = target_read_u32(chip->target, ficr[i].address,
1057 &ficr[i].value);
1058 if (res != ERROR_OK) {
1059 LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address);
1060 return res;
1061 }
1062 }
1063
1064 for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) {
1065 res = target_read_u32(chip->target, uicr[i].address,
1066 &uicr[i].value);
1067 if (res != ERROR_OK) {
1068 LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address);
1069 return res;
1070 }
1071 }
1072
1073 snprintf(buf, buf_size,
1074 "\n[factory information control block]\n\n"
1075 "code page size: %"PRIu32"B\n"
1076 "code memory size: %"PRIu32"kB\n"
1077 "code region 0 size: %"PRIu32"kB\n"
1078 "pre-programmed code: %s\n"
1079 "number of ram blocks: %"PRIu32"\n"
1080 "ram block 0 size: %"PRIu32"B\n"
1081 "ram block 1 size: %"PRIu32"B\n"
1082 "ram block 2 size: %"PRIu32"B\n"
1083 "ram block 3 size: %"PRIu32 "B\n"
1084 "config id: %" PRIx32 "\n"
1085 "device id: 0x%"PRIx32"%08"PRIx32"\n"
1086 "encryption root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n"
1087 "identity root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n"
1088 "device address type: 0x%"PRIx32"\n"
1089 "device address: 0x%"PRIx32"%08"PRIx32"\n"
1090 "override enable: %"PRIx32"\n"
1091 "NRF_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n"
1092 "BLE_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n"
1093 "\n[user information control block]\n\n"
1094 "code region 0 size: %"PRIu32"kB\n"
1095 "read back protection configuration: %"PRIx32"\n"
1096 "reset value for XTALFREQ: %"PRIx32"\n"
1097 "firmware id: 0x%04"PRIx32,
1098 ficr[0].value,
1099 (ficr[1].value * ficr[0].value) / 1024,
1100 (ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024,
1101 ((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present",
1102 ficr[4].value,
1103 ficr[5].value,
1104 (ficr[6].value == 0xFFFFFFFF) ? 0 : ficr[6].value,
1105 (ficr[7].value == 0xFFFFFFFF) ? 0 : ficr[7].value,
1106 (ficr[8].value == 0xFFFFFFFF) ? 0 : ficr[8].value,
1107 ficr[9].value,
1108 ficr[10].value, ficr[11].value,
1109 ficr[12].value, ficr[13].value, ficr[14].value, ficr[15].value,
1110 ficr[16].value, ficr[17].value, ficr[18].value, ficr[19].value,
1111 ficr[20].value,
1112 ficr[21].value, ficr[22].value,
1113 ficr[23].value,
1114 ficr[24].value, ficr[25].value, ficr[26].value, ficr[27].value, ficr[28].value,
1115 ficr[29].value, ficr[30].value, ficr[31].value, ficr[32].value, ficr[33].value,
1116 (uicr[0].value == 0xFFFFFFFF) ? 0 : uicr[0].value / 1024,
1117 uicr[1].value & 0xFFFF,
1118 uicr[2].value & 0xFF,
1119 uicr[3].value & 0xFFFF);
1120
1121 return ERROR_OK;
1122 }
1123
1124 static const struct command_registration nrf5_exec_command_handlers[] = {
1125 {
1126 .name = "mass_erase",
1127 .handler = nrf5_handle_mass_erase_command,
1128 .mode = COMMAND_EXEC,
1129 .help = "Erase all flash contents of the chip.",
1130 .usage = "",
1131 },
1132 COMMAND_REGISTRATION_DONE
1133 };
1134
1135 static const struct command_registration nrf5_command_handlers[] = {
1136 {
1137 .name = "nrf5",
1138 .mode = COMMAND_ANY,
1139 .help = "nrf5 flash command group",
1140 .usage = "",
1141 .chain = nrf5_exec_command_handlers,
1142 },
1143 {
1144 .name = "nrf51",
1145 .mode = COMMAND_ANY,
1146 .help = "nrf51 flash command group",
1147 .usage = "",
1148 .chain = nrf5_exec_command_handlers,
1149 },
1150 COMMAND_REGISTRATION_DONE
1151 };
1152
1153 const struct flash_driver nrf5_flash = {
1154 .name = "nrf5",
1155 .commands = nrf5_command_handlers,
1156 .flash_bank_command = nrf5_flash_bank_command,
1157 .info = nrf5_info,
1158 .erase = nrf5_erase,
1159 .protect = nrf5_protect,
1160 .write = nrf5_write,
1161 .read = default_flash_read,
1162 .probe = nrf5_probe,
1163 .auto_probe = nrf5_auto_probe,
1164 .erase_check = default_flash_blank_check,
1165 .protect_check = nrf5_protect_check,
1166 .free_driver_priv = nrf5_free_driver_priv,
1167 };
1168
1169 /* We need to retain the flash-driver name as well as the commands
1170 * for backwards compatability */
1171 const struct flash_driver nrf51_flash = {
1172 .name = "nrf51",
1173 .commands = nrf5_command_handlers,
1174 .flash_bank_command = nrf5_flash_bank_command,
1175 .info = nrf5_info,
1176 .erase = nrf5_erase,
1177 .protect = nrf5_protect,
1178 .write = nrf5_write,
1179 .read = default_flash_read,
1180 .probe = nrf5_probe,
1181 .auto_probe = nrf5_auto_probe,
1182 .erase_check = default_flash_blank_check,
1183 .protect_check = nrf5_protect_check,
1184 .free_driver_priv = nrf5_free_driver_priv,
1185 };

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)