]> git.sur5r.net Git - openocd/blob - src/flash/nor/atsamv.c
77fb7e68b86a454eb6f2b4ee36f62c42e60a0900
[openocd] / 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 };