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