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

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)