67533fc1e5b891d1a6ed5dd03b0b7f8b96dcbeb7
[openocd.git] / src / flash / nor / atsamv.c
1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code)
2
3 /*
4 * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com>
5 *
6 * at91sam3s* support
7 * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de>
8 *
9 * at91sam3x* & at91sam4 support
10 * Copyright (C) 2011 by Olivier Schonken and Jim Norris
11 *
12 * atsamv, atsams, and atsame support
13 * Copyright (C) 2015 Morgan Quigley
14 *
15 * Some of the lower level code was based on code supplied by
16 * ATMEL under BSD-Source-Code License and this copyright.
17 * ATMEL Microcontroller Software Support
18 * Copyright (c) 2009, Atmel Corporation. All rights reserved.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "imp.h"
26 #include <helper/time_support.h>
27
28 #define REG_NAME_WIDTH (12)
29
30 #define SAMV_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */
31 #define SAMV_EFC_FCMD_WP (0x1) /* (EFC) Write Page */
32 #define SAMV_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */
33 #define SAMV_EFC_FCMD_EWP (0x3) /* (EFC) Erase Page and Write Page */
34 #define SAMV_EFC_FCMD_EWPL (0x4) /* (EFC) Erase Page, Write Page then Lock*/
35 #define SAMV_EFC_FCMD_EA (0x5) /* (EFC) Erase All */
36 #define SAMV_EFC_FCMD_EPA (0x7) /* (EFC) Erase pages */
37 #define SAMV_EFC_FCMD_SLB (0x8) /* (EFC) Set Lock Bit */
38 #define SAMV_EFC_FCMD_CLB (0x9) /* (EFC) Clear Lock Bit */
39 #define SAMV_EFC_FCMD_GLB (0xA) /* (EFC) Get Lock Bit */
40 #define SAMV_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */
41 #define SAMV_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */
42 #define SAMV_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */
43
44 #define OFFSET_EFC_FMR 0
45 #define OFFSET_EFC_FCR 4
46 #define OFFSET_EFC_FSR 8
47 #define OFFSET_EFC_FRR 12
48
49 #define SAMV_CHIPID_CIDR (0x400E0940)
50 #define SAMV_NUM_GPNVM_BITS 9
51 #define SAMV_CONTROLLER_ADDR (0x400e0c00)
52 #define SAMV_SECTOR_SIZE 16384
53 #define SAMV_PAGE_SIZE 512
54 #define SAMV_FLASH_BASE 0x00400000
55
56 extern const struct flash_driver atsamv_flash;
57
58 struct samv_flash_bank {
59 bool probed;
60 unsigned size_bytes;
61 unsigned gpnvm[SAMV_NUM_GPNVM_BITS];
62 };
63
64 /* The actual sector size of the SAMV7 flash memory is 128K bytes.
65 * 16 sectors for a 2048KB device. The lock regions are 16KB per lock
66 * region, with a 2048KB device having 128 lock regions.
67 * For the best results, num_sectors is thus set to the number of lock
68 * regions, and the sector_size set to the lock region size. Page
69 * erases are used to erase 16KB sections when programming */
70
71 static int samv_efc_get_status(struct target *target, uint32_t *v)
72 {
73 int r = target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FSR, v);
74 return r;
75 }
76
77 static int samv_efc_get_result(struct target *target, uint32_t *v)
78 {
79 uint32_t rv;
80 int r = target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FRR, &rv);
81 if (v)
82 *v = rv;
83 return r;
84 }
85
86 static int samv_efc_start_command(struct target *target,
87 unsigned command, unsigned argument)
88 {
89 uint32_t v;
90 samv_efc_get_status(target, &v);
91 if (!(v & 1)) {
92 LOG_ERROR("flash controller is not ready");
93 return ERROR_FAIL;
94 }
95
96 v = (0x5A << 24) | (argument << 8) | command;
97 LOG_DEBUG("starting flash command: 0x%08x", (unsigned int)(v));
98 int r = target_write_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FCR, v);
99 if (r != ERROR_OK)
100 LOG_DEBUG("write failed");
101 return r;
102 }
103
104 static int samv_efc_perform_command(struct target *target,
105 unsigned command, unsigned argument, uint32_t *status)
106 {
107 int r;
108 uint32_t v;
109 int64_t ms_now, ms_end;
110
111 if (status)
112 *status = 0;
113
114 r = samv_efc_start_command(target, command, argument);
115 if (r != ERROR_OK)
116 return r;
117
118 ms_end = 10000 + timeval_ms();
119
120 do {
121 r = samv_efc_get_status(target, &v);
122 if (r != ERROR_OK)
123 return r;
124 ms_now = timeval_ms();
125 if (ms_now > ms_end) {
126 /* error */
127 LOG_ERROR("Command timeout");
128 return ERROR_FAIL;
129 }
130 } while ((v & 1) == 0);
131
132 /* if requested, copy the flash controller error bits back to the caller */
133 if (status)
134 *status = (v & 0x6);
135 return ERROR_OK;
136 }
137
138 static int samv_erase_pages(struct target *target,
139 int first_page, int num_pages, uint32_t *status)
140 {
141 uint8_t erase_pages;
142 switch (num_pages) {
143 case 4:
144 erase_pages = 0x00;
145 break;
146 case 8:
147 erase_pages = 0x01;
148 break;
149 case 16:
150 erase_pages = 0x02;
151 break;
152 case 32:
153 erase_pages = 0x03;
154 break;
155 default:
156 erase_pages = 0x00;
157 break;
158 }
159
160 /* SAMV_EFC_FCMD_EPA
161 * According to the datasheet FARG[15:2] defines the page from which
162 * the erase will start.This page must be modulo 4, 8, 16 or 32
163 * according to the number of pages to erase. FARG[1:0] defines the
164 * number of pages to be erased. Previously (firstpage << 2) was used
165 * to conform to this, seems it should not be shifted...
166 */
167 return samv_efc_perform_command(target, SAMV_EFC_FCMD_EPA,
168 first_page | erase_pages, status);
169 }
170
171 static int samv_get_gpnvm(struct target *target, unsigned gpnvm, unsigned *out)
172 {
173 uint32_t v;
174 int r;
175
176 if (gpnvm >= SAMV_NUM_GPNVM_BITS) {
177 LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS);
178 return ERROR_FAIL;
179 }
180
181 r = samv_efc_perform_command(target, SAMV_EFC_FCMD_GFB, 0, NULL);
182 if (r != ERROR_OK) {
183 LOG_ERROR("samv_get_gpnvm failed");
184 return r;
185 }
186
187 r = samv_efc_get_result(target, &v);
188
189 if (out)
190 *out = (v >> gpnvm) & 1;
191
192 return r;
193 }
194
195 static int samv_clear_gpnvm(struct target *target, unsigned gpnvm)
196 {
197 int r;
198 unsigned v;
199
200 if (gpnvm >= SAMV_NUM_GPNVM_BITS) {
201 LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS);
202 return ERROR_FAIL;
203 }
204 r = samv_get_gpnvm(target, gpnvm, &v);
205 if (r != ERROR_OK) {
206 LOG_DEBUG("get gpnvm failed: %d", r);
207 return r;
208 }
209 r = samv_efc_perform_command(target, SAMV_EFC_FCMD_CFB, gpnvm, NULL);
210 LOG_DEBUG("clear gpnvm result: %d", r);
211 return r;
212 }
213
214 static int samv_set_gpnvm(struct target *target, unsigned gpnvm)
215 {
216 int r;
217 unsigned v;
218 if (gpnvm >= SAMV_NUM_GPNVM_BITS) {
219 LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS);
220 return ERROR_FAIL;
221 }
222
223 r = samv_get_gpnvm(target, gpnvm, &v);
224 if (r != ERROR_OK)
225 return r;
226 if (v) {
227 r = ERROR_OK; /* the gpnvm bit is already set */
228 } else {
229 /* we need to set it */
230 r = samv_efc_perform_command(target, SAMV_EFC_FCMD_SFB, gpnvm, NULL);
231 }
232 return r;
233 }
234
235 static int samv_flash_unlock(struct target *target,
236 unsigned start_sector, unsigned end_sector)
237 {
238 int r;
239 uint32_t status;
240 uint32_t pg;
241 uint32_t pages_per_sector;
242
243 /* todo: look into this... i think this should be done on lock regions */
244 pages_per_sector = SAMV_SECTOR_SIZE / SAMV_PAGE_SIZE;
245 while (start_sector <= end_sector) {
246 pg = start_sector * pages_per_sector;
247 r = samv_efc_perform_command(target, SAMV_EFC_FCMD_CLB, pg, &status);
248 if (r != ERROR_OK)
249 return r;
250 start_sector++;
251 }
252 return ERROR_OK;
253 }
254
255 static int samv_flash_lock(struct target *target,
256 unsigned start_sector, unsigned end_sector)
257 {
258 uint32_t status;
259 uint32_t pg;
260 uint32_t pages_per_sector;
261 int r;
262
263 /* todo: look into this... i think this should be done on lock regions */
264 pages_per_sector = SAMV_SECTOR_SIZE / SAMV_PAGE_SIZE;
265 while (start_sector <= end_sector) {
266 pg = start_sector * pages_per_sector;
267 r = samv_efc_perform_command(target, SAMV_EFC_FCMD_SLB, pg, &status);
268 if (r != ERROR_OK)
269 return r;
270 start_sector++;
271 }
272 return ERROR_OK;
273 }
274
275 static int samv_protect_check(struct flash_bank *bank)
276 {
277 int r;
278 uint32_t v[4] = {0};
279
280 r = samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_GLB, 0, NULL);
281 if (r == ERROR_OK) {
282 samv_efc_get_result(bank->target, &v[0]);
283 samv_efc_get_result(bank->target, &v[1]);
284 samv_efc_get_result(bank->target, &v[2]);
285 r = samv_efc_get_result(bank->target, &v[3]);
286 }
287 if (r != ERROR_OK)
288 return r;
289
290 for (unsigned int x = 0; x < bank->num_sectors; x++)
291 bank->sectors[x].is_protected = (!!(v[x >> 5] & (1 << (x % 32))));
292 return ERROR_OK;
293 }
294
295 FLASH_BANK_COMMAND_HANDLER(samv_flash_bank_command)
296 {
297 LOG_INFO("flash bank command");
298 struct samv_flash_bank *samv_info;
299 samv_info = calloc(1, sizeof(struct samv_flash_bank));
300 bank->driver_priv = samv_info;
301 return ERROR_OK;
302 }
303
304 static int samv_get_device_id(struct flash_bank *bank, uint32_t *device_id)
305 {
306 return target_read_u32(bank->target, SAMV_CHIPID_CIDR, device_id);
307 }
308
309 static int samv_probe(struct flash_bank *bank)
310 {
311 uint32_t device_id;
312 int r = samv_get_device_id(bank, &device_id);
313 if (r != ERROR_OK)
314 return r;
315 LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
316
317 uint8_t eproc = (device_id >> 5) & 0x7;
318 if (eproc != 0) {
319 LOG_ERROR("unexpected eproc code: %d was expecting 0 (Cortex-M7)", eproc);
320 return ERROR_FAIL;
321 }
322
323 uint8_t nvm_size_code = (device_id >> 8) & 0xf;
324 switch (nvm_size_code) {
325 case 10:
326 bank->size = 512 * 1024;
327 break;
328 case 12:
329 bank->size = 1024 * 1024;
330 break;
331 case 14:
332 bank->size = 2048 * 1024;
333 break;
334 default:
335 LOG_ERROR("unrecognized flash size code: %d", nvm_size_code);
336 return ERROR_FAIL;
337 }
338
339 struct samv_flash_bank *samv_info = bank->driver_priv;
340 samv_info->size_bytes = bank->size;
341 samv_info->probed = true;
342
343 bank->base = SAMV_FLASH_BASE;
344 bank->num_sectors = bank->size / SAMV_SECTOR_SIZE;
345 bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
346 for (unsigned int s = 0; s < bank->num_sectors; s++) {
347 bank->sectors[s].size = SAMV_SECTOR_SIZE;
348 bank->sectors[s].offset = s * SAMV_SECTOR_SIZE;
349 bank->sectors[s].is_erased = -1;
350 bank->sectors[s].is_protected = -1;
351 }
352
353 r = samv_protect_check(bank);
354 if (r != ERROR_OK)
355 return r;
356
357 return ERROR_OK;
358 }
359
360 static int samv_auto_probe(struct flash_bank *bank)
361 {
362 struct samv_flash_bank *samv_info = bank->driver_priv;
363 if (samv_info->probed)
364 return ERROR_OK;
365 return samv_probe(bank);
366 }
367
368 static int samv_erase(struct flash_bank *bank, unsigned int first,
369 unsigned int last)
370 {
371 const int page_count = 32; /* 32 pages equals 16 KB lock region */
372
373 if (bank->target->state != TARGET_HALTED) {
374 LOG_ERROR("Target not halted");
375 return ERROR_TARGET_NOT_HALTED;
376 }
377
378 int r = samv_auto_probe(bank);
379 if (r != ERROR_OK)
380 return r;
381
382 /* easy case: we've been requested to erase the entire flash */
383 if ((first == 0) && ((last + 1) == bank->num_sectors))
384 return samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_EA, 0, NULL);
385
386 LOG_INFO("erasing lock regions %u-%u...", first, last);
387
388 for (unsigned int i = first; i <= last; i++) {
389 uint32_t status;
390 r = samv_erase_pages(bank->target, (i * page_count), page_count, &status);
391 LOG_INFO("erasing lock region %u", i);
392 if (r != ERROR_OK)
393 LOG_ERROR("error performing erase page @ lock region number %u", i);
394 if (status & (1 << 2)) {
395 LOG_ERROR("lock region %u is locked", i);
396 return ERROR_FAIL;
397 }
398 if (status & (1 << 1)) {
399 LOG_ERROR("flash command error @lock region %u", i);
400 return ERROR_FAIL;
401 }
402 }
403 return ERROR_OK;
404 }
405
406 static int samv_protect(struct flash_bank *bank, int set, unsigned int first,
407 unsigned int last)
408 {
409 if (bank->target->state != TARGET_HALTED) {
410 LOG_ERROR("Target not halted");
411 return ERROR_TARGET_NOT_HALTED;
412 }
413
414 int r;
415 if (set)
416 r = samv_flash_lock(bank->target, first, last);
417 else
418 r = samv_flash_unlock(bank->target, first, last);
419
420 return r;
421 }
422
423 static int samv_page_read(struct target *target,
424 unsigned page_num, uint8_t *buf)
425 {
426 uint32_t addr = SAMV_FLASH_BASE + page_num * SAMV_PAGE_SIZE;
427 int r = target_read_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf);
428 if (r != ERROR_OK)
429 LOG_ERROR("flash program failed to read page @ 0x%08x",
430 (unsigned int)(addr));
431 return r;
432 }
433
434 static int samv_page_write(struct target *target,
435 unsigned pagenum, const uint8_t *buf)
436 {
437 uint32_t status;
438 const uint32_t addr = SAMV_FLASH_BASE + pagenum * SAMV_PAGE_SIZE;
439 int r;
440
441 LOG_DEBUG("write page %u at address 0x%08x", pagenum, (unsigned int)addr);
442 r = target_write_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf);
443 if (r != ERROR_OK) {
444 LOG_ERROR("failed to buffer page at 0x%08x", (unsigned int)addr);
445 return r;
446 }
447
448 r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WP, pagenum, &status);
449 if (r != ERROR_OK)
450 LOG_ERROR("error performing write page at 0x%08x", (unsigned int)addr);
451 if (status & (1 << 2)) {
452 LOG_ERROR("page at 0x%08x is locked", (unsigned int)addr);
453 return ERROR_FAIL;
454 }
455 if (status & (1 << 1)) {
456 LOG_ERROR("flash command error at 0x%08x", (unsigned int)addr);
457 return ERROR_FAIL;
458 }
459 return ERROR_OK;
460 }
461
462 static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
463 uint32_t offset, uint32_t count)
464 {
465 if (bank->target->state != TARGET_HALTED) {
466 LOG_ERROR("target not halted");
467 return ERROR_TARGET_NOT_HALTED;
468 }
469
470 if (count == 0)
471 return ERROR_OK;
472
473 if ((offset + count) > bank->size) {
474 LOG_ERROR("flash write error - past end of bank");
475 LOG_ERROR(" offset: 0x%08x, count 0x%08x, bank end: 0x%08x",
476 (unsigned int)(offset),
477 (unsigned int)(count),
478 (unsigned int)(bank->size));
479 return ERROR_FAIL;
480 }
481
482 uint8_t pagebuffer[SAMV_PAGE_SIZE] = {0};
483 uint32_t page_cur = offset / SAMV_PAGE_SIZE;
484 uint32_t page_end = (offset + count - 1) / SAMV_PAGE_SIZE;
485
486 LOG_DEBUG("offset: 0x%08x, count: 0x%08x",
487 (unsigned int)(offset), (unsigned int)(count));
488 LOG_DEBUG("page start: %d, page end: %d", (int)(page_cur), (int)(page_end));
489
490 /* Special case: all one page */
491 /* Otherwise: */
492 /* (1) non-aligned start */
493 /* (2) body pages */
494 /* (3) non-aligned end. */
495
496 int r;
497 uint32_t page_offset;
498
499 /* handle special case - all one page. */
500 if (page_cur == page_end) {
501 LOG_DEBUG("special case, all in one page");
502 r = samv_page_read(bank->target, page_cur, pagebuffer);
503 if (r != ERROR_OK)
504 return r;
505
506 page_offset = offset & (SAMV_PAGE_SIZE-1);
507 memcpy(pagebuffer + page_offset, buffer, count);
508
509 r = samv_page_write(bank->target, page_cur, pagebuffer);
510 if (r != ERROR_OK)
511 return r;
512 return ERROR_OK;
513 }
514
515 /* step 1) handle the non-aligned starting address */
516 page_offset = offset & (SAMV_PAGE_SIZE - 1);
517 if (page_offset) {
518 LOG_DEBUG("non-aligned start");
519 /* read the partial page */
520 r = samv_page_read(bank->target, page_cur, pagebuffer);
521 if (r != ERROR_OK)
522 return r;
523
524 /* over-write with new data */
525 uint32_t n = SAMV_PAGE_SIZE - page_offset;
526 memcpy(pagebuffer + page_offset, buffer, n);
527
528 r = samv_page_write(bank->target, page_cur, pagebuffer);
529 if (r != ERROR_OK)
530 return r;
531
532 count -= n;
533 offset += n;
534 buffer += n;
535 page_cur++;
536 }
537
538 /* By checking that offset is correct here, we also fix a clang warning */
539 assert(offset % SAMV_PAGE_SIZE == 0);
540
541 /* step 2) handle the full pages */
542 LOG_DEBUG("full page loop: cur=%d, end=%d, count = 0x%08x",
543 (int)page_cur, (int)page_end, (unsigned int)(count));
544
545 while ((page_cur < page_end) && (count >= SAMV_PAGE_SIZE)) {
546 r = samv_page_write(bank->target, page_cur, buffer);
547 if (r != ERROR_OK)
548 return r;
549 count -= SAMV_PAGE_SIZE;
550 buffer += SAMV_PAGE_SIZE;
551 page_cur += 1;
552 }
553
554 /* step 3) write final page, if it's partial (otherwise it's already done) */
555 if (count) {
556 LOG_DEBUG("final partial page, count = 0x%08x", (unsigned int)(count));
557 /* we have a partial page */
558 r = samv_page_read(bank->target, page_cur, pagebuffer);
559 if (r != ERROR_OK)
560 return r;
561 memcpy(pagebuffer, buffer, count); /* data goes at start of page */
562 r = samv_page_write(bank->target, page_cur, pagebuffer);
563 if (r != ERROR_OK)
564 return r;
565 }
566 return ERROR_OK;
567 }
568
569 static int samv_get_info(struct flash_bank *bank, struct command_invocation *cmd)
570 {
571 struct samv_flash_bank *samv_info = bank->driver_priv;
572 if (!samv_info->probed) {
573 int r = samv_probe(bank);
574 if (r != ERROR_OK)
575 return r;
576 }
577 command_print_sameline(cmd, "Cortex-M7 detected with %" PRIu32 " kB flash\n",
578 bank->size / 1024);
579 return ERROR_OK;
580 }
581
582 COMMAND_HANDLER(samv_handle_gpnvm_command)
583 {
584 struct flash_bank *bank = get_flash_bank_by_num_noprobe(0);
585 if (!bank)
586 return ERROR_FAIL;
587 struct samv_flash_bank *samv_info = bank->driver_priv;
588 struct target *target = bank->target;
589
590 if (target->state != TARGET_HALTED) {
591 LOG_ERROR("target not halted");
592 return ERROR_TARGET_NOT_HALTED;
593 }
594
595 int r;
596 if (!samv_info->probed) {
597 r = samv_auto_probe(bank);
598 if (r != ERROR_OK)
599 return r;
600 }
601
602 int who = 0;
603
604 switch (CMD_ARGC) {
605 case 0:
606 goto showall;
607 case 1:
608 who = -1;
609 break;
610 case 2:
611 if (!strcmp(CMD_ARGV[0], "show") && !strcmp(CMD_ARGV[1], "all"))
612 who = -1;
613 else {
614 uint32_t v32;
615 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32);
616 who = v32;
617 }
618 break;
619 default:
620 return ERROR_COMMAND_SYNTAX_ERROR;
621 }
622
623 unsigned v = 0;
624 if (!strcmp("show", CMD_ARGV[0])) {
625 if (who == -1) {
626 showall:
627 r = ERROR_OK;
628 for (int x = 0; x < SAMV_NUM_GPNVM_BITS; x++) {
629 r = samv_get_gpnvm(target, x, &v);
630 if (r != ERROR_OK)
631 break;
632 command_print(CMD, "samv-gpnvm%u: %u", x, v);
633 }
634 return r;
635 }
636 if ((who >= 0) && (((unsigned)who) < SAMV_NUM_GPNVM_BITS)) {
637 r = samv_get_gpnvm(target, who, &v);
638 if (r != ERROR_OK)
639 return r;
640
641 command_print(CMD, "samv-gpnvm%u: %u", who, v);
642 return r;
643 } else {
644 command_print(CMD, "invalid gpnvm: %u", who);
645 return ERROR_COMMAND_SYNTAX_ERROR;
646 }
647 }
648
649 if (who == -1) {
650 command_print(CMD, "missing gpnvm number");
651 return ERROR_COMMAND_SYNTAX_ERROR;
652 }
653
654 if (!strcmp("set", CMD_ARGV[0]))
655 r = samv_set_gpnvm(target, who);
656 else if (!strcmp("clr", CMD_ARGV[0]) || !strcmp("clear", CMD_ARGV[0]))
657 r = samv_clear_gpnvm(target, who);
658 else {
659 command_print(CMD, "unknown command: %s", CMD_ARGV[0]);
660 r = ERROR_COMMAND_SYNTAX_ERROR;
661 }
662 return r;
663 }
664
665 static const struct command_registration atsamv_exec_command_handlers[] = {
666 {
667 .name = "gpnvm",
668 .handler = samv_handle_gpnvm_command,
669 .mode = COMMAND_EXEC,
670 .usage = "[('clr'|'set'|'show') bitnum]",
671 .help = "Without arguments, shows all bits in the gpnvm "
672 "register. Otherwise, clears, sets, or shows one "
673 "General Purpose Non-Volatile Memory (gpnvm) bit.",
674 },
675 COMMAND_REGISTRATION_DONE
676 };
677
678 static const struct command_registration atsamv_command_handlers[] = {
679 {
680 .name = "atsamv",
681 .mode = COMMAND_ANY,
682 .help = "atsamv flash command group",
683 .usage = "",
684 .chain = atsamv_exec_command_handlers,
685 },
686 COMMAND_REGISTRATION_DONE
687 };
688
689 const struct flash_driver atsamv_flash = {
690 .name = "atsamv",
691 .commands = atsamv_command_handlers,
692 .flash_bank_command = samv_flash_bank_command,
693 .erase = samv_erase,
694 .protect = samv_protect,
695 .write = samv_write,
696 .read = default_flash_read,
697 .probe = samv_probe,
698 .auto_probe = samv_auto_probe,
699 .erase_check = default_flash_blank_check,
700 .protect_check = samv_protect_check,
701 .info = samv_get_info,
702 .free_driver_priv = default_flash_free_driver_priv,
703 };

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)