Set empty usage field for commands that do not need parameters
[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 {
115 bool probed;
116 int (*write) (struct flash_bank *bank,
117 struct nrf5_info *chip,
118 const uint8_t *buffer, uint32_t offset, uint32_t count);
119 } bank[2];
120 struct target *target;
121 };
122
123 struct nrf5_device_spec {
124 uint16_t hwid;
125 const char *part;
126 const char *variant;
127 const char *build_code;
128 unsigned int flash_size_kb;
129 };
130
131 #define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \
132 { \
133 .hwid = (id), \
134 .part = pt, \
135 .variant = var, \
136 .build_code = bcode, \
137 .flash_size_kb = (fsize), \
138 }
139
140 /* The known devices table below is derived from the "nRF51 Series
141 * Compatibility Matrix" document, which can be found by searching for
142 * ATTN-51 on the Nordic Semi website:
143 *
144 * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51
145 *
146 * Up to date with Matrix v2.0, plus some additional HWIDs.
147 *
148 * The additional HWIDs apply where the build code in the matrix is
149 * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is
150 * for x==0, x!=0 means different (unspecified) HWIDs.
151 */
152 static const struct nrf5_device_spec nrf5_known_devices_table[] = {
153 /* nRF51822 Devices (IC rev 1). */
154 NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256),
155 NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128),
156 NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128),
157 NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
158 NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
159
160 /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
161 with built-in jlink seem to use engineering samples not listed
162 in the nRF51 Series Compatibility Matrix V1.0. */
163 NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
164
165 /* nRF51822 Devices (IC rev 2). */
166 NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
167 NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
168 NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256),
169 NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256),
170 NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256),
171 NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128),
172 NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256),
173 NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256),
174 NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256),
175
176 /* nRF51822 Devices (IC rev 3). */
177 NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
178 NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
179 NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
180 NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
181 NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
182 NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
183 NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
184 NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
185 NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
186
187 /* nRF51422 Devices (IC rev 1). */
188 NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
189 NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256),
190 NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256),
191
192 /* nRF51422 Devices (IC rev 2). */
193 NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256),
194 NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256),
195 NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128),
196 NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256),
197
198 /* nRF51422 Devices (IC rev 3). */
199 NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256),
200 NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128),
201 NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256),
202 NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256),
203 NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128),
204 NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
205 NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
206
207 /* nRF52810 Devices */
208 NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192),
209 NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192),
210
211 /* nRF52832 Devices */
212 NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
213 NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
214 NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
215
216 /* nRF52840 Devices */
217 NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
218 };
219
220 static int nrf5_bank_is_probed(struct flash_bank *bank)
221 {
222 struct nrf5_info *chip = bank->driver_priv;
223
224 assert(chip != NULL);
225
226 return chip->bank[bank->bank_number].probed;
227 }
228 static int nrf5_probe(struct flash_bank *bank);
229
230 static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip)
231 {
232 if (bank->target->state != TARGET_HALTED) {
233 LOG_ERROR("Target not halted");
234 return ERROR_TARGET_NOT_HALTED;
235 }
236
237 *chip = bank->driver_priv;
238
239 int probed = nrf5_bank_is_probed(bank);
240 if (probed < 0)
241 return probed;
242 else if (!probed)
243 return nrf5_probe(bank);
244 else
245 return ERROR_OK;
246 }
247
248 static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
249 {
250 uint32_t ready;
251 int res;
252 int timeout_ms = 340;
253 int64_t ts_start = timeval_ms();
254
255 do {
256 res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready);
257 if (res != ERROR_OK) {
258 LOG_ERROR("Couldn't read NVMC_READY register");
259 return res;
260 }
261
262 if (ready == 0x00000001)
263 return ERROR_OK;
264
265 keep_alive();
266
267 } while ((timeval_ms()-ts_start) < timeout_ms);
268
269 LOG_DEBUG("Timed out waiting for NVMC_READY");
270 return ERROR_FLASH_BUSY;
271 }
272
273 static int nrf5_nvmc_erase_enable(struct nrf5_info *chip)
274 {
275 int res;
276 res = target_write_u32(chip->target,
277 NRF5_NVMC_CONFIG,
278 NRF5_NVMC_CONFIG_EEN);
279
280 if (res != ERROR_OK) {
281 LOG_ERROR("Failed to enable erase operation");
282 return res;
283 }
284
285 /*
286 According to NVMC examples in Nordic SDK busy status must be
287 checked after writing to NVMC_CONFIG
288 */
289 res = nrf5_wait_for_nvmc(chip);
290 if (res != ERROR_OK)
291 LOG_ERROR("Erase enable did not complete");
292
293 return res;
294 }
295
296 static int nrf5_nvmc_write_enable(struct nrf5_info *chip)
297 {
298 int res;
299 res = target_write_u32(chip->target,
300 NRF5_NVMC_CONFIG,
301 NRF5_NVMC_CONFIG_WEN);
302
303 if (res != ERROR_OK) {
304 LOG_ERROR("Failed to enable write operation");
305 return res;
306 }
307
308 /*
309 According to NVMC examples in Nordic SDK busy status must be
310 checked after writing to NVMC_CONFIG
311 */
312 res = nrf5_wait_for_nvmc(chip);
313 if (res != ERROR_OK)
314 LOG_ERROR("Write enable did not complete");
315
316 return res;
317 }
318
319 static int nrf5_nvmc_read_only(struct nrf5_info *chip)
320 {
321 int res;
322 res = target_write_u32(chip->target,
323 NRF5_NVMC_CONFIG,
324 NRF5_NVMC_CONFIG_REN);
325
326 if (res != ERROR_OK) {
327 LOG_ERROR("Failed to enable read-only operation");
328 return res;
329 }
330 /*
331 According to NVMC examples in Nordic SDK busy status must be
332 checked after writing to NVMC_CONFIG
333 */
334 res = nrf5_wait_for_nvmc(chip);
335 if (res != ERROR_OK)
336 LOG_ERROR("Read only enable did not complete");
337
338 return res;
339 }
340
341 static int nrf5_nvmc_generic_erase(struct nrf5_info *chip,
342 uint32_t erase_register, uint32_t erase_value)
343 {
344 int res;
345
346 res = nrf5_nvmc_erase_enable(chip);
347 if (res != ERROR_OK)
348 goto error;
349
350 res = target_write_u32(chip->target,
351 erase_register,
352 erase_value);
353 if (res != ERROR_OK)
354 goto set_read_only;
355
356 res = nrf5_wait_for_nvmc(chip);
357 if (res != ERROR_OK)
358 goto set_read_only;
359
360 return nrf5_nvmc_read_only(chip);
361
362 set_read_only:
363 nrf5_nvmc_read_only(chip);
364 error:
365 LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32,
366 erase_register, erase_value);
367 return ERROR_FAIL;
368 }
369
370 static int nrf5_protect_check(struct flash_bank *bank)
371 {
372 int res;
373 uint32_t clenr0;
374
375 /* UICR cannot be write protected so just return early */
376 if (bank->base == NRF5_UICR_BASE)
377 return ERROR_OK;
378
379 struct nrf5_info *chip = bank->driver_priv;
380
381 assert(chip != NULL);
382
383 res = target_read_u32(chip->target, NRF5_FICR_CLENR0,
384 &clenr0);
385 if (res != ERROR_OK) {
386 LOG_ERROR("Couldn't read code region 0 size[FICR]");
387 return res;
388 }
389
390 if (clenr0 == 0xFFFFFFFF) {
391 res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
392 &clenr0);
393 if (res != ERROR_OK) {
394 LOG_ERROR("Couldn't read code region 0 size[UICR]");
395 return res;
396 }
397 }
398
399 for (int i = 0; i < bank->num_sectors; i++)
400 bank->sectors[i].is_protected =
401 clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0;
402
403 return ERROR_OK;
404 }
405
406 static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
407 {
408 int res;
409 uint32_t clenr0, ppfc;
410 struct nrf5_info *chip;
411
412 /* UICR cannot be write protected so just bail out early */
413 if (bank->base == NRF5_UICR_BASE)
414 return ERROR_FAIL;
415
416 res = nrf5_get_probed_chip_if_halted(bank, &chip);
417 if (res != ERROR_OK)
418 return res;
419
420 if (first != 0) {
421 LOG_ERROR("Code region 0 must start at the begining of the bank");
422 return ERROR_FAIL;
423 }
424
425 res = target_read_u32(chip->target, NRF5_FICR_PPFC,
426 &ppfc);
427 if (res != ERROR_OK) {
428 LOG_ERROR("Couldn't read PPFC register");
429 return res;
430 }
431
432 if ((ppfc & 0xFF) == 0x00) {
433 LOG_ERROR("Code region 0 size was pre-programmed at the factory, can't change flash protection settings");
434 return ERROR_FAIL;
435 }
436
437 res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
438 &clenr0);
439 if (res != ERROR_OK) {
440 LOG_ERROR("Couldn't read code region 0 size[UICR]");
441 return res;
442 }
443
444 if (clenr0 == 0xFFFFFFFF) {
445 res = target_write_u32(chip->target, NRF5_UICR_CLENR0,
446 clenr0);
447 if (res != ERROR_OK) {
448 LOG_ERROR("Couldn't write code region 0 size[UICR]");
449 return res;
450 }
451
452 } else {
453 LOG_ERROR("You need to perform chip erase before changing the protection settings");
454 }
455
456 nrf5_protect_check(bank);
457
458 return ERROR_OK;
459 }
460
461 static int nrf5_probe(struct flash_bank *bank)
462 {
463 uint32_t hwid;
464 int res;
465 struct nrf5_info *chip = bank->driver_priv;
466
467 res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid);
468 if (res != ERROR_OK) {
469 LOG_ERROR("Couldn't read CONFIGID register");
470 return res;
471 }
472
473 hwid &= 0xFFFF; /* HWID is stored in the lower two
474 * bytes of the CONFIGID register */
475
476 const struct nrf5_device_spec *spec = NULL;
477 for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) {
478 if (hwid == nrf5_known_devices_table[i].hwid) {
479 spec = &nrf5_known_devices_table[i];
480 break;
481 }
482 }
483
484 if (!chip->bank[0].probed && !chip->bank[1].probed) {
485 if (spec)
486 LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash",
487 spec->part, spec->variant, spec->build_code,
488 spec->flash_size_kb);
489 else
490 LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid);
491 }
492
493 if (bank->base == NRF5_FLASH_BASE) {
494 /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
495 res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
496 &chip->code_page_size);
497 if (res != ERROR_OK) {
498 LOG_ERROR("Couldn't read code page size");
499 return res;
500 }
501
502 /* Note the register name is misleading,
503 * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
504 uint32_t num_sectors;
505 res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors);
506 if (res != ERROR_OK) {
507 LOG_ERROR("Couldn't read code memory size");
508 return res;
509 }
510
511 bank->num_sectors = num_sectors;
512 bank->size = num_sectors * chip->code_page_size;
513
514 if (spec && bank->size / 1024 != spec->flash_size_kb)
515 LOG_WARNING("Chip's reported Flash capacity does not match expected one");
516
517 bank->sectors = calloc(bank->num_sectors,
518 sizeof((bank->sectors)[0]));
519 if (!bank->sectors)
520 return ERROR_FLASH_BANK_NOT_PROBED;
521
522 /* Fill out the sector information: all NRF5 sectors are the same size and
523 * there is always a fixed number of them. */
524 for (int i = 0; i < bank->num_sectors; i++) {
525 bank->sectors[i].size = chip->code_page_size;
526 bank->sectors[i].offset = i * chip->code_page_size;
527
528 /* mark as unknown */
529 bank->sectors[i].is_erased = -1;
530 bank->sectors[i].is_protected = -1;
531 }
532
533 nrf5_protect_check(bank);
534
535 chip->bank[0].probed = true;
536 } else {
537 bank->size = NRF5_UICR_SIZE;
538 bank->num_sectors = 1;
539 bank->sectors = calloc(bank->num_sectors,
540 sizeof((bank->sectors)[0]));
541 if (!bank->sectors)
542 return ERROR_FLASH_BANK_NOT_PROBED;
543
544 bank->sectors[0].size = bank->size;
545 bank->sectors[0].offset = 0;
546
547 bank->sectors[0].is_erased = 0;
548 bank->sectors[0].is_protected = 0;
549
550 chip->bank[1].probed = true;
551 }
552
553 return ERROR_OK;
554 }
555
556 static int nrf5_auto_probe(struct flash_bank *bank)
557 {
558 int probed = nrf5_bank_is_probed(bank);
559
560 if (probed < 0)
561 return probed;
562 else if (probed)
563 return ERROR_OK;
564 else
565 return nrf5_probe(bank);
566 }
567
568 static int nrf5_erase_all(struct nrf5_info *chip)
569 {
570 LOG_DEBUG("Erasing all non-volatile memory");
571 return nrf5_nvmc_generic_erase(chip,
572 NRF5_NVMC_ERASEALL,
573 0x00000001);
574 }
575
576 static int nrf5_erase_page(struct flash_bank *bank,
577 struct nrf5_info *chip,
578 struct flash_sector *sector)
579 {
580 int res;
581
582 LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
583 if (sector->is_protected) {
584 LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
585 return ERROR_FAIL;
586 }
587
588 if (bank->base == NRF5_UICR_BASE) {
589 uint32_t ppfc;
590 res = target_read_u32(chip->target, NRF5_FICR_PPFC,
591 &ppfc);
592 if (res != ERROR_OK) {
593 LOG_ERROR("Couldn't read PPFC register");
594 return res;
595 }
596
597 if ((ppfc & 0xFF) == 0xFF) {
598 /* We can't erase the UICR. Double-check to
599 see if it's already erased before complaining. */
600 default_flash_blank_check(bank);
601 if (sector->is_erased == 1)
602 return ERROR_OK;
603
604 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");
605 return ERROR_FAIL;
606 }
607
608 res = nrf5_nvmc_generic_erase(chip,
609 NRF5_NVMC_ERASEUICR,
610 0x00000001);
611
612
613 } else {
614 res = nrf5_nvmc_generic_erase(chip,
615 NRF5_NVMC_ERASEPAGE,
616 sector->offset);
617 }
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
745 assert(start % chip->code_page_size == 0);
746 assert(end % chip->code_page_size == 0);
747
748 res = nrf5_nvmc_write_enable(chip);
749 if (res != ERROR_OK)
750 goto error;
751
752 res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
753 if (res != ERROR_OK)
754 goto error;
755
756 return nrf5_nvmc_read_only(chip);
757
758 error:
759 nrf5_nvmc_read_only(chip);
760 LOG_ERROR("Failed to write to nrf5 flash");
761 return res;
762 }
763
764 static int nrf5_erase(struct flash_bank *bank, int first, int last)
765 {
766 int res;
767 struct nrf5_info *chip;
768
769 res = nrf5_get_probed_chip_if_halted(bank, &chip);
770 if (res != ERROR_OK)
771 return res;
772
773 /* For each sector to be erased */
774 for (int s = first; s <= last && res == ERROR_OK; s++)
775 res = nrf5_erase_page(bank, chip, &bank->sectors[s]);
776
777 return res;
778 }
779
780 static int nrf5_code_flash_write(struct flash_bank *bank,
781 struct nrf5_info *chip,
782 const uint8_t *buffer, uint32_t offset, uint32_t count)
783 {
784
785 int res;
786 /* Need to perform reads to fill any gaps we need to preserve in the first page,
787 before the start of buffer, or in the last page, after the end of buffer */
788 uint32_t first_page = offset/chip->code_page_size;
789 uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
790
791 uint32_t first_page_offset = first_page * chip->code_page_size;
792 uint32_t last_page_offset = last_page * chip->code_page_size;
793
794 LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
795 offset, offset+count, first_page_offset, last_page_offset);
796
797 uint32_t page_cnt = last_page - first_page;
798 uint8_t buffer_to_flash[page_cnt*chip->code_page_size];
799
800 /* Fill in any space between start of first page and start of buffer */
801 uint32_t pre = offset - first_page_offset;
802 if (pre > 0) {
803 res = target_read_memory(bank->target,
804 first_page_offset,
805 1,
806 pre,
807 buffer_to_flash);
808 if (res != ERROR_OK)
809 return res;
810 }
811
812 /* Fill in main contents of buffer */
813 memcpy(buffer_to_flash+pre, buffer, count);
814
815 /* Fill in any space between end of buffer and end of last page */
816 uint32_t post = last_page_offset - (offset+count);
817 if (post > 0) {
818 /* Retrieve the full row contents from Flash */
819 res = target_read_memory(bank->target,
820 offset + count,
821 1,
822 post,
823 buffer_to_flash+pre+count);
824 if (res != ERROR_OK)
825 return res;
826 }
827
828 return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
829 }
830
831 static int nrf5_uicr_flash_write(struct flash_bank *bank,
832 struct nrf5_info *chip,
833 const uint8_t *buffer, uint32_t offset, uint32_t count)
834 {
835 int res;
836 uint8_t uicr[NRF5_UICR_SIZE];
837 struct flash_sector *sector = &bank->sectors[0];
838
839 if ((offset + count) > NRF5_UICR_SIZE)
840 return ERROR_FAIL;
841
842 res = target_read_memory(bank->target,
843 NRF5_UICR_BASE,
844 1,
845 NRF5_UICR_SIZE,
846 uicr);
847
848 if (res != ERROR_OK)
849 return res;
850
851 res = nrf5_erase_page(bank, chip, sector);
852 if (res != ERROR_OK)
853 return res;
854
855 res = nrf5_nvmc_write_enable(chip);
856 if (res != ERROR_OK)
857 return res;
858
859 memcpy(&uicr[offset], buffer, count);
860
861 res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE);
862 if (res != ERROR_OK) {
863 nrf5_nvmc_read_only(chip);
864 return res;
865 }
866
867 return nrf5_nvmc_read_only(chip);
868 }
869
870
871 static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
872 uint32_t offset, uint32_t count)
873 {
874 int res;
875 struct nrf5_info *chip;
876
877 res = nrf5_get_probed_chip_if_halted(bank, &chip);
878 if (res != ERROR_OK)
879 return res;
880
881 return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
882 }
883
884 static void nrf5_free_driver_priv(struct flash_bank *bank)
885 {
886 struct nrf5_info *chip = bank->driver_priv;
887 if (chip == NULL)
888 return;
889
890 chip->refcount--;
891 if (chip->refcount == 0) {
892 free(chip);
893 bank->driver_priv = NULL;
894 }
895 }
896
897 FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
898 {
899 static struct nrf5_info *chip;
900
901 switch (bank->base) {
902 case NRF5_FLASH_BASE:
903 bank->bank_number = 0;
904 break;
905 case NRF5_UICR_BASE:
906 bank->bank_number = 1;
907 break;
908 default:
909 LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
910 return ERROR_FAIL;
911 }
912
913 if (!chip) {
914 /* Create a new chip */
915 chip = calloc(1, sizeof(*chip));
916 if (!chip)
917 return ERROR_FAIL;
918
919 chip->target = bank->target;
920 }
921
922 switch (bank->base) {
923 case NRF5_FLASH_BASE:
924 chip->bank[bank->bank_number].write = nrf5_code_flash_write;
925 break;
926 case NRF5_UICR_BASE:
927 chip->bank[bank->bank_number].write = nrf5_uicr_flash_write;
928 break;
929 }
930
931 chip->refcount++;
932 chip->bank[bank->bank_number].probed = false;
933 bank->driver_priv = chip;
934
935 return ERROR_OK;
936 }
937
938 COMMAND_HANDLER(nrf5_handle_mass_erase_command)
939 {
940 int res;
941 struct flash_bank *bank = NULL;
942 struct target *target = get_current_target(CMD_CTX);
943
944 res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank);
945 if (res != ERROR_OK)
946 return res;
947
948 assert(bank != NULL);
949
950 struct nrf5_info *chip;
951
952 res = nrf5_get_probed_chip_if_halted(bank, &chip);
953 if (res != ERROR_OK)
954 return res;
955
956 uint32_t ppfc;
957
958 res = target_read_u32(target, NRF5_FICR_PPFC,
959 &ppfc);
960 if (res != ERROR_OK) {
961 LOG_ERROR("Couldn't read PPFC register");
962 return res;
963 }
964
965 if ((ppfc & 0xFF) == 0x00) {
966 LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
967 "mass erase command won't work.");
968 return ERROR_FAIL;
969 }
970
971 res = nrf5_erase_all(chip);
972 if (res != ERROR_OK) {
973 LOG_ERROR("Failed to erase the chip");
974 nrf5_protect_check(bank);
975 return res;
976 }
977
978 res = nrf5_protect_check(bank);
979 if (res != ERROR_OK) {
980 LOG_ERROR("Failed to check chip's write protection");
981 return res;
982 }
983
984 res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank);
985 if (res != ERROR_OK)
986 return res;
987
988 return ERROR_OK;
989 }
990
991 static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
992 {
993 int res;
994
995 struct nrf5_info *chip;
996
997 res = nrf5_get_probed_chip_if_halted(bank, &chip);
998 if (res != ERROR_OK)
999 return res;
1000
1001 static struct {
1002 const uint32_t address;
1003 uint32_t value;
1004 } ficr[] = {
1005 { .address = NRF5_FICR_CODEPAGESIZE },
1006 { .address = NRF5_FICR_CODESIZE },
1007 { .address = NRF5_FICR_CLENR0 },
1008 { .address = NRF5_FICR_PPFC },
1009 { .address = NRF5_FICR_NUMRAMBLOCK },
1010 { .address = NRF5_FICR_SIZERAMBLOCK0 },
1011 { .address = NRF5_FICR_SIZERAMBLOCK1 },
1012 { .address = NRF5_FICR_SIZERAMBLOCK2 },
1013 { .address = NRF5_FICR_SIZERAMBLOCK3 },
1014 { .address = NRF5_FICR_CONFIGID },
1015 { .address = NRF5_FICR_DEVICEID0 },
1016 { .address = NRF5_FICR_DEVICEID1 },
1017 { .address = NRF5_FICR_ER0 },
1018 { .address = NRF5_FICR_ER1 },
1019 { .address = NRF5_FICR_ER2 },
1020 { .address = NRF5_FICR_ER3 },
1021 { .address = NRF5_FICR_IR0 },
1022 { .address = NRF5_FICR_IR1 },
1023 { .address = NRF5_FICR_IR2 },
1024 { .address = NRF5_FICR_IR3 },
1025 { .address = NRF5_FICR_DEVICEADDRTYPE },
1026 { .address = NRF5_FICR_DEVICEADDR0 },
1027 { .address = NRF5_FICR_DEVICEADDR1 },
1028 { .address = NRF5_FICR_OVERRIDEN },
1029 { .address = NRF5_FICR_NRF_1MBIT0 },
1030 { .address = NRF5_FICR_NRF_1MBIT1 },
1031 { .address = NRF5_FICR_NRF_1MBIT2 },
1032 { .address = NRF5_FICR_NRF_1MBIT3 },
1033 { .address = NRF5_FICR_NRF_1MBIT4 },
1034 { .address = NRF5_FICR_BLE_1MBIT0 },
1035 { .address = NRF5_FICR_BLE_1MBIT1 },
1036 { .address = NRF5_FICR_BLE_1MBIT2 },
1037 { .address = NRF5_FICR_BLE_1MBIT3 },
1038 { .address = NRF5_FICR_BLE_1MBIT4 },
1039 }, uicr[] = {
1040 { .address = NRF5_UICR_CLENR0, },
1041 { .address = NRF5_UICR_RBPCONF },
1042 { .address = NRF5_UICR_XTALFREQ },
1043 { .address = NRF5_UICR_FWID },
1044 };
1045
1046 for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) {
1047 res = target_read_u32(chip->target, ficr[i].address,
1048 &ficr[i].value);
1049 if (res != ERROR_OK) {
1050 LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address);
1051 return res;
1052 }
1053 }
1054
1055 for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) {
1056 res = target_read_u32(chip->target, uicr[i].address,
1057 &uicr[i].value);
1058 if (res != ERROR_OK) {
1059 LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address);
1060 return res;
1061 }
1062 }
1063
1064 snprintf(buf, buf_size,
1065 "\n[factory information control block]\n\n"
1066 "code page size: %"PRIu32"B\n"
1067 "code memory size: %"PRIu32"kB\n"
1068 "code region 0 size: %"PRIu32"kB\n"
1069 "pre-programmed code: %s\n"
1070 "number of ram blocks: %"PRIu32"\n"
1071 "ram block 0 size: %"PRIu32"B\n"
1072 "ram block 1 size: %"PRIu32"B\n"
1073 "ram block 2 size: %"PRIu32"B\n"
1074 "ram block 3 size: %"PRIu32 "B\n"
1075 "config id: %" PRIx32 "\n"
1076 "device id: 0x%"PRIx32"%08"PRIx32"\n"
1077 "encryption root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n"
1078 "identity root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n"
1079 "device address type: 0x%"PRIx32"\n"
1080 "device address: 0x%"PRIx32"%08"PRIx32"\n"
1081 "override enable: %"PRIx32"\n"
1082 "NRF_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n"
1083 "BLE_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n"
1084 "\n[user information control block]\n\n"
1085 "code region 0 size: %"PRIu32"kB\n"
1086 "read back protection configuration: %"PRIx32"\n"
1087 "reset value for XTALFREQ: %"PRIx32"\n"
1088 "firmware id: 0x%04"PRIx32,
1089 ficr[0].value,
1090 (ficr[1].value * ficr[0].value) / 1024,
1091 (ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024,
1092 ((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present",
1093 ficr[4].value,
1094 ficr[5].value,
1095 (ficr[6].value == 0xFFFFFFFF) ? 0 : ficr[6].value,
1096 (ficr[7].value == 0xFFFFFFFF) ? 0 : ficr[7].value,
1097 (ficr[8].value == 0xFFFFFFFF) ? 0 : ficr[8].value,
1098 ficr[9].value,
1099 ficr[10].value, ficr[11].value,
1100 ficr[12].value, ficr[13].value, ficr[14].value, ficr[15].value,
1101 ficr[16].value, ficr[17].value, ficr[18].value, ficr[19].value,
1102 ficr[20].value,
1103 ficr[21].value, ficr[22].value,
1104 ficr[23].value,
1105 ficr[24].value, ficr[25].value, ficr[26].value, ficr[27].value, ficr[28].value,
1106 ficr[29].value, ficr[30].value, ficr[31].value, ficr[32].value, ficr[33].value,
1107 (uicr[0].value == 0xFFFFFFFF) ? 0 : uicr[0].value / 1024,
1108 uicr[1].value & 0xFFFF,
1109 uicr[2].value & 0xFF,
1110 uicr[3].value & 0xFFFF);
1111
1112 return ERROR_OK;
1113 }
1114
1115 static const struct command_registration nrf5_exec_command_handlers[] = {
1116 {
1117 .name = "mass_erase",
1118 .handler = nrf5_handle_mass_erase_command,
1119 .mode = COMMAND_EXEC,
1120 .help = "Erase all flash contents of the chip.",
1121 .usage = "",
1122 },
1123 COMMAND_REGISTRATION_DONE
1124 };
1125
1126 static const struct command_registration nrf5_command_handlers[] = {
1127 {
1128 .name = "nrf5",
1129 .mode = COMMAND_ANY,
1130 .help = "nrf5 flash command group",
1131 .usage = "",
1132 .chain = nrf5_exec_command_handlers,
1133 },
1134 {
1135 .name = "nrf51",
1136 .mode = COMMAND_ANY,
1137 .help = "nrf51 flash command group",
1138 .usage = "",
1139 .chain = nrf5_exec_command_handlers,
1140 },
1141 COMMAND_REGISTRATION_DONE
1142 };
1143
1144 const struct flash_driver nrf5_flash = {
1145 .name = "nrf5",
1146 .commands = nrf5_command_handlers,
1147 .flash_bank_command = nrf5_flash_bank_command,
1148 .info = nrf5_info,
1149 .erase = nrf5_erase,
1150 .protect = nrf5_protect,
1151 .write = nrf5_write,
1152 .read = default_flash_read,
1153 .probe = nrf5_probe,
1154 .auto_probe = nrf5_auto_probe,
1155 .erase_check = default_flash_blank_check,
1156 .protect_check = nrf5_protect_check,
1157 .free_driver_priv = nrf5_free_driver_priv,
1158 };
1159
1160 /* We need to retain the flash-driver name as well as the commands
1161 * for backwards compatability */
1162 const struct flash_driver nrf51_flash = {
1163 .name = "nrf51",
1164 .commands = nrf5_command_handlers,
1165 .flash_bank_command = nrf5_flash_bank_command,
1166 .info = nrf5_info,
1167 .erase = nrf5_erase,
1168 .protect = nrf5_protect,
1169 .write = nrf5_write,
1170 .read = default_flash_read,
1171 .probe = nrf5_probe,
1172 .auto_probe = nrf5_auto_probe,
1173 .erase_check = default_flash_blank_check,
1174 .protect_check = nrf5_protect_check,
1175 .free_driver_priv = nrf5_free_driver_priv,
1176 };

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)