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

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)