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

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)