9f1319b663754c9af4102bc81fbea57f74a9ec50
[openocd.git] / src / flash / nor / at91sam4l.c
1 /***************************************************************************
2 * Copyright (C) 2013 by Andrey Yurovsky *
3 * Andrey Yurovsky <yurovsky@gmail.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "imp.h"
26
27 /* At this time, the SAM4L Flash is available in these capacities:
28 * ATSAM4Lx4xx: 256KB (512 pages)
29 * ATSAM4Lx2xx: 128KB (256 pages)
30 * ATSAM4Lx8xx: 512KB (1024 pages)
31 */
32
33 /* There are 16 lockable regions regardless of overall capacity. The number
34 * of pages per sector is therefore dependant on capacity. */
35 #define SAM4L_NUM_SECTORS 16
36
37 /* Locations in memory map */
38 #define SAM4L_FLASH 0x00000000 /* Flash region */
39 #define SAM4L_FLASH_USER 0x00800000 /* Flash user page region */
40 #define SAM4L_FLASHCALW 0x400A0000 /* Flash controller */
41 #define SAM4L_CHIPID 0x400E0740 /* Chip Identification */
42
43 /* Offsets from SAM4L_FLASHCALW */
44 #define SAM4L_FCR 0x00 /* Flash Control Register (RW) */
45 #define SAM4L_FCMD 0x04 /* Flash Command Register (RW) */
46 #define SAM4L_FSR 0x08 /* Flash Status Register (RO) */
47 #define SAM4L_FPR 0x0C /* Flash Parameter Register (RO) */
48 #define SAM4L_FVR 0x10 /* Flash Version Register (RO) */
49 #define SAM4L_FGPFRHI 0x14 /* Flash General Purpose Register High (RO) */
50 #define SAM4L_FGPFRLO 0x18 /* Flash General Purpose Register Low (RO) */
51
52 /* Offsets from SAM4L_CHIPID */
53 #define SAM4L_CIDR 0x00 /* Chip ID Register (RO) */
54 #define SAM4L_EXID 0x04 /* Chip ID Extension Register (RO) */
55
56 /* Flash commands (for SAM4L_FCMD), see Table 14-5 */
57 #define SAM4L_FCMD_NOP 0 /* No Operation */
58 #define SAM4L_FCMD_WP 1 /* Write Page */
59 #define SAM4L_FCMD_EP 2 /* Erase Page */
60 #define SAM4L_FCMD_CPB 3 /* Clear Page Buffer */
61 #define SAM4L_FCMD_LP 4 /* Lock region containing given page */
62 #define SAM4L_FCMD_UP 5 /* Unlock region containing given page */
63 #define SAM4L_FCMD_EA 6 /* Erase All */
64 #define SAM4L_FCMD_WGPB 7 /* Write general-purpose fuse bit */
65 #define SAM4L_FCMD_EGPB 8 /* Erase general-purpose fuse bit */
66 #define SAM4L_FCMD_SSB 9 /* Set security fuses */
67 #define SAM4L_FCMD_PGPFB 10 /* Program general-purpose fuse byte */
68 #define SAM4L_FCMD_EAGPF 11 /* Erase all general-purpose fuse bits */
69 #define SAM4L_FCMD_QPR 12 /* Quick page read */
70 #define SAM4L_FCMD_WUP 13 /* Write user page */
71 #define SAM4L_FCMD_EUP 14 /* Erase user page */
72 #define SAM4L_FCMD_QPRUP 15 /* Quick page read (user page) */
73 #define SAM4L_FCMD_HSEN 16 /* High speed mode enable */
74 #define SAM4L_FCMD_HSDIS 17 /* High speed mode disable */
75
76 #define SAM4L_FMCD_CMDKEY 0xA5UL /* 'key' to issue commands, see 14.10.2 */
77
78 struct sam4l_chip_info {
79 uint32_t id;
80 uint32_t exid;
81 const char *name;
82 };
83
84 /* These are taken from Table 9-1 in 42023E-SAM-07/2013 */
85 static const struct sam4l_chip_info sam4l_known_chips[] = {
86 { 0xAB0B0AE0, 0x1400000F, "ATSAM4LC8C" },
87 { 0xAB0A09E0, 0x0400000F, "ATSAM4LC4C" },
88 { 0xAB0A07E0, 0x0400000F, "ATSAM4LC2C" },
89 { 0xAB0B0AE0, 0x1300000F, "ATSAM4LC8B" },
90 { 0xAB0A09E0, 0x0300000F, "ATSAM4LC4B" },
91 { 0xAB0A07E0, 0x0300000F, "ATSAM4LC2B" },
92 { 0xAB0B0AE0, 0x1200000F, "ATSAM4LC8A" },
93 { 0xAB0A09E0, 0x0200000F, "ATSAM4LC4A" },
94 { 0xAB0A07E0, 0x0200000F, "ATSAM4LC2A" },
95 { 0xAB0B0AE0, 0x14000002, "ATSAM4LS8C" },
96 { 0xAB0A09E0, 0x04000002, "ATSAM4LS4C" },
97 { 0xAB0A07E0, 0x04000002, "ATSAM4LS2C" },
98 { 0xAB0B0AE0, 0x13000002, "ATSAM4LS8B" },
99 { 0xAB0A09E0, 0x03000002, "ATSAM4LS4B" },
100 { 0xAB0A07E0, 0x03000002, "ATSAM4LS2B" },
101 { 0xAB0B0AE0, 0x12000002, "ATSAM4LS8A" },
102 { 0xAB0A09E0, 0x02000002, "ATSAM4LS4A" },
103 { 0xAB0A07E0, 0x02000002, "ATSAM4LS2A" },
104 };
105
106 /* Meaning of SRAMSIZ field in CHIPID, see 9.3.1 in 42023E-SAM-07/2013 */
107 static const uint16_t sam4l_ram_sizes[16] = { 48, 1, 2, 6, 24, 4, 80, 160, 8, 16, 32, 64, 128, 256, 96, 512 };
108
109 /* Meaning of PSZ field in FPR, see 14.10.4 in 42023E-SAM-07/2013 */
110 static const uint16_t sam4l_page_sizes[8] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
111
112 struct sam4l_info {
113 const struct sam4l_chip_info *details;
114
115 uint32_t flash_kb;
116 uint32_t ram_kb;
117 uint32_t page_size;
118 int num_pages;
119 int sector_size;
120 int pages_per_sector;
121
122 bool probed;
123 struct target *target;
124 struct sam4l_info *next;
125 };
126
127 static struct sam4l_info *sam4l_chips;
128
129 static int sam4l_flash_wait_until_ready(struct target *target)
130 {
131 volatile unsigned int t = 0;
132 uint32_t st;
133 int res;
134
135 /* Poll the status register until the FRDY bit is set */
136 do {
137 res = target_read_u32(target, SAM4L_FLASHCALW + SAM4L_FSR, &st);
138 } while (res == ERROR_OK && !(st & (1<<0)) && ++t < 10);
139
140 return res;
141 }
142
143 static int sam4l_flash_check_error(struct target *target, uint32_t *err)
144 {
145 uint32_t st;
146 int res;
147
148 res = target_read_u32(target, SAM4L_FLASHCALW + SAM4L_FSR, &st);
149
150 if (res == ERROR_OK)
151 *err = st & ((1<<3) | (1<<2)); /* grab PROGE and LOCKE bits */
152
153 return res;
154 }
155
156 static int sam4l_flash_command(struct target *target, uint8_t cmd, int page)
157 {
158 int res;
159 uint32_t fcmd;
160 uint32_t err;
161
162 res = sam4l_flash_wait_until_ready(target);
163 if (res != ERROR_OK)
164 return res;
165
166 if (page >= 0) {
167 /* Set the page number. For some commands, the page number is just an
168 * argument (ex: fuse bit number). */
169 fcmd = (SAM4L_FMCD_CMDKEY << 24) | ((page & 0xFFFF) << 8) | (cmd & 0x3F);
170 } else {
171 /* Reuse the page number that was read from the flash command register. */
172 res = target_read_u32(target, SAM4L_FLASHCALW + SAM4L_FCMD, &fcmd);
173 if (res != ERROR_OK)
174 return res;
175
176 fcmd &= ~0x3F; /* clear out the command code */
177 fcmd |= (SAM4L_FMCD_CMDKEY << 24) | (cmd & 0x3F);
178 }
179
180 /* Send the command */
181 res = target_write_u32(target, SAM4L_FLASHCALW + SAM4L_FCMD, fcmd);
182 if (res != ERROR_OK)
183 return res;
184
185 res = sam4l_flash_check_error(target, &err);
186 if (res != ERROR_OK)
187 return res;
188
189 if (err != 0)
190 LOG_ERROR("%s got error status 0x%08" PRIx32, __func__, err);
191
192 res = sam4l_flash_wait_until_ready(target);
193
194 return res;
195 }
196
197 FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command)
198 {
199 struct sam4l_info *chip = sam4l_chips;
200
201 while (chip) {
202 if (chip->target == bank->target)
203 break;
204 chip = chip->next;
205 }
206
207 if (!chip) {
208 /* Create a new chip */
209 chip = calloc(1, sizeof(*chip));
210 if (!chip)
211 return ERROR_FAIL;
212
213 chip->target = bank->target;
214 chip->probed = false;
215
216 bank->driver_priv = chip;
217
218 /* Insert it into the chips list (at head) */
219 chip->next = sam4l_chips;
220 sam4l_chips = chip;
221 }
222
223 if (bank->base != SAM4L_FLASH) {
224 LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32
225 "[at91sam4l series] )",
226 bank->base, SAM4L_FLASH);
227 return ERROR_FAIL;
228 }
229
230 return ERROR_OK;
231 }
232
233 static const struct sam4l_chip_info *sam4l_find_chip_name(uint32_t id, uint32_t exid)
234 {
235 unsigned int i;
236
237 id &= ~0xF;
238
239 for (i = 0; i < ARRAY_SIZE(sam4l_known_chips); i++) {
240 if (sam4l_known_chips[i].id == id && sam4l_known_chips[i].exid == exid)
241 return &sam4l_known_chips[i];
242 }
243
244 return NULL;
245 }
246
247 static int sam4l_check_page_erased(struct flash_bank *bank, uint32_t pn,
248 bool *is_erased_p)
249 {
250 int res;
251 uint32_t st;
252
253 /* Issue a quick page read to verify that we've erased this page */
254 res = sam4l_flash_command(bank->target, SAM4L_FCMD_QPR, pn);
255 if (res != ERROR_OK) {
256 LOG_ERROR("Quick page read %d failed", pn);
257 return res;
258 }
259
260 /* Retrieve the flash status */
261 res = target_read_u32(bank->target, SAM4L_FLASHCALW + SAM4L_FSR, &st);
262 if (res != ERROR_OK) {
263 LOG_ERROR("Couldn't read erase status");
264 return res;
265 }
266
267 /* Is the page in question really erased? */
268 *is_erased_p = !!(st & (1<<5));
269
270 return ERROR_OK;
271 }
272
273 static int sam4l_probe(struct flash_bank *bank)
274 {
275 uint32_t id, exid, param;
276 int res;
277 struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
278
279 if (chip->probed)
280 return ERROR_OK;
281
282 res = target_read_u32(bank->target, SAM4L_CHIPID + SAM4L_CIDR, &id);
283 if (res != ERROR_OK) {
284 LOG_ERROR("Couldn't read chip ID");
285 return res;
286 }
287
288 res = target_read_u32(bank->target, SAM4L_CHIPID + SAM4L_EXID, &exid);
289 if (res != ERROR_OK) {
290 LOG_ERROR("Couldn't read extended chip ID");
291 return res;
292 }
293
294 chip->details = sam4l_find_chip_name(id, exid);
295
296 /* The RAM capacity is in a lookup table. */
297 chip->ram_kb = sam4l_ram_sizes[0xF & (id >> 16)];
298
299 switch (0xF & (id >> 8)) {
300 case 0x07:
301 chip->flash_kb = 128;
302 break;
303 case 0x09:
304 chip->flash_kb = 256;
305 break;
306 case 0x0A:
307 chip->flash_kb = 512;
308 break;
309 default:
310 LOG_ERROR("Unknown flash size (chip ID is %08X), assuming 128K", id);
311 chip->flash_kb = 128;
312 break;
313 }
314
315 /* Retrieve the Flash parameters */
316 res = target_read_u32(bank->target, SAM4L_FLASHCALW + SAM4L_FPR, &param);
317 if (res != ERROR_OK) {
318 LOG_ERROR("Couldn't read Flash parameters");
319 return res;
320 }
321
322 /* Fetch the page size from the parameter register. Technically the flash
323 * capacity is there too though the manual mentions that not all parts will
324 * have it set so we use the Chip ID capacity information instead. */
325 chip->page_size = sam4l_page_sizes[0x7 & (param >> 8)];
326 assert(chip->page_size);
327 chip->num_pages = chip->flash_kb * 1024 / chip->page_size;
328
329 chip->sector_size = (chip->flash_kb * 1024) / SAM4L_NUM_SECTORS;
330 chip->pages_per_sector = chip->sector_size / chip->page_size;
331
332 /* Make sure the bank size is correct */
333 bank->size = chip->flash_kb * 1024;
334
335 /* Allocate the sector table. */
336 bank->num_sectors = SAM4L_NUM_SECTORS;
337 bank->sectors = calloc(bank->num_sectors, (sizeof((bank->sectors)[0])));
338 if (!bank->sectors)
339 return ERROR_FAIL;
340
341 /* Fill out the sector information: all SAM4L sectors are the same size and
342 * there is always a fixed number of them. */
343 for (int i = 0; i < bank->num_sectors; i++) {
344 bank->sectors[i].size = chip->sector_size;
345 bank->sectors[i].offset = i * chip->sector_size;
346 /* mark as unknown */
347 bank->sectors[i].is_erased = -1;
348 bank->sectors[i].is_protected = -1;
349 }
350
351 /* Done */
352 chip->probed = true;
353
354 LOG_INFO("SAM4L MCU: %s (Rev %c) (%uKB Flash with %d %dB pages, %uKB RAM)",
355 chip->details ? chip->details->name : "unknown", 'A' + (id & 0xF),
356 chip->flash_kb, chip->num_pages, chip->page_size, chip->ram_kb);
357
358 return ERROR_OK;
359 }
360
361 static int sam4l_protect_check(struct flash_bank *bank)
362 {
363 int res;
364 uint32_t st;
365 struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
366
367 if (bank->target->state != TARGET_HALTED) {
368 LOG_ERROR("Target not halted");
369
370 return ERROR_TARGET_NOT_HALTED;
371 }
372
373 if (!chip->probed) {
374 if (sam4l_probe(bank) != ERROR_OK)
375 return ERROR_FLASH_BANK_NOT_PROBED;
376 }
377
378 res = target_read_u32(bank->target, SAM4L_FLASHCALW + SAM4L_FSR, &st);
379 if (res != ERROR_OK)
380 return res;
381
382 st >>= 16; /* There are 16 lock region bits in the upper half word */
383 for (int i = 0; i < bank->num_sectors; i++)
384 bank->sectors[i].is_protected = !!(st & (1<<i));
385
386 return ERROR_OK;
387 }
388
389 static int sam4l_protect(struct flash_bank *bank, int set, int first, int last)
390 {
391 struct sam4l_info *chip = sam4l_chips;
392
393 if (bank->target->state != TARGET_HALTED) {
394 LOG_ERROR("Target not halted");
395
396 return ERROR_TARGET_NOT_HALTED;
397 }
398
399 if (!chip->probed) {
400 if (sam4l_probe(bank) != ERROR_OK)
401 return ERROR_FLASH_BANK_NOT_PROBED;
402 }
403
404 /* Make sure the pages make sense. */
405 if (first >= bank->num_sectors || last >= bank->num_sectors) {
406 LOG_ERROR("Protect range %d - %d not valid (%d sectors total)", first, last,
407 bank->num_sectors);
408 return ERROR_FAIL;
409 }
410
411 /* Try to lock or unlock each sector in the range. This is done by locking
412 * a region containing one page in that sector, we arbitrarily choose the 0th
413 * page in the sector. */
414 for (int i = first; i <= last; i++) {
415 int res;
416
417 res = sam4l_flash_command(bank->target,
418 set ? SAM4L_FCMD_LP : SAM4L_FCMD_UP, i * chip->pages_per_sector);
419 if (res != ERROR_OK) {
420 LOG_ERROR("Can't %slock region containing page %d", set ? "" : "un", i);
421 return res;
422 }
423 }
424
425 return ERROR_OK;
426 }
427
428 static int sam4l_erase(struct flash_bank *bank, int first, int last)
429 {
430 int ret;
431 struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
432
433 if (bank->target->state != TARGET_HALTED) {
434 LOG_ERROR("Target not halted");
435
436 return ERROR_TARGET_NOT_HALTED;
437 }
438
439 if (!chip->probed) {
440 if (sam4l_probe(bank) != ERROR_OK)
441 return ERROR_FLASH_BANK_NOT_PROBED;
442 }
443
444 /* Make sure the pages make sense. */
445 if (first >= bank->num_sectors || last >= bank->num_sectors) {
446 LOG_ERROR("Erase range %d - %d not valid (%d sectors total)", first, last,
447 bank->num_sectors);
448 return ERROR_FAIL;
449 }
450
451 /* Erase */
452 if ((first == 0) && ((last + 1) == bank->num_sectors)) {
453 LOG_DEBUG("Erasing the whole chip");
454
455 ret = sam4l_flash_command(bank->target, SAM4L_FCMD_EA, -1);
456 if (ret != ERROR_OK) {
457 LOG_ERROR("Erase All failed");
458 return ret;
459 }
460 } else {
461 LOG_DEBUG("Erasing sectors %d through %d...\n", first, last);
462
463 /* For each sector... */
464 for (int i = first; i <= last; i++) {
465 /* For each page in that sector... */
466 for (int j = 0; j < chip->pages_per_sector; j++) {
467 int pn = i * chip->pages_per_sector + j;
468 bool is_erased = false;
469
470 /* Issue the page erase */
471 ret = sam4l_flash_command(bank->target, SAM4L_FCMD_EP, pn);
472 if (ret != ERROR_OK) {
473 LOG_ERROR("Erasing page %d failed", pn);
474 return ret;
475 }
476
477 ret = sam4l_check_page_erased(bank, pn, &is_erased);
478 if (ret != ERROR_OK)
479 return ret;
480
481 if (!is_erased) {
482 LOG_DEBUG("Page %d was not erased.", pn);
483 return ERROR_FAIL;
484 }
485 }
486
487 /* This sector is definitely erased. */
488 bank->sectors[i].is_erased = 1;
489 }
490 }
491
492 return ERROR_OK;
493 }
494
495 /* Write an entire page from host buffer 'buf' to page-aligned 'address' in the
496 * Flash. */
497 static int sam4l_write_page(struct sam4l_info *chip, struct target *target,
498 uint32_t address, const uint8_t *buf)
499 {
500 int res;
501
502 /* Clear the page buffer before we write to it */
503 res = sam4l_flash_command(target, SAM4L_FCMD_CPB, -1);
504 if (res != ERROR_OK) {
505 LOG_ERROR("%s: can't clear page buffer", __func__);
506 return res;
507 }
508
509 /* Write the modified page back to the target's page buffer */
510 res = target_write_memory(target, address, 4, chip->page_size / 4, buf);
511
512 if (res != ERROR_OK) {
513 LOG_ERROR("%s: %d", __func__, __LINE__);
514 return res;
515 }
516
517 /* Commit the page contents to Flash: erase the current page and then
518 * write it out. */
519 res = sam4l_flash_command(target, SAM4L_FCMD_EP, -1);
520 if (res != ERROR_OK)
521 return res;
522 res = sam4l_flash_command(target, SAM4L_FCMD_WP, -1);
523
524 return res;
525 }
526
527 /* Write partial contents into page-aligned 'address' on the Flash from host
528 * buffer 'buf' by writing 'nb' of 'buf' at 'offset' into the Flash page. */
529 static int sam4l_write_page_partial(struct sam4l_info *chip,
530 struct flash_bank *bank, uint32_t address, const uint8_t *buf,
531 uint32_t page_offset, uint32_t nb)
532 {
533 int res;
534 uint8_t *pg = malloc(chip->page_size);
535 if (!pg)
536 return ERROR_FAIL;
537
538 assert(page_offset + nb < chip->page_size);
539 assert((address % chip->page_size) == 0);
540
541 /* Retrieve the full page contents from Flash */
542 res = target_read_memory(bank->target, address, 4,
543 chip->page_size / 4, pg);
544 if (res != ERROR_OK) {
545 free(pg);
546 return res;
547 }
548
549 /* Insert our partial page over the data from Flash */
550 memcpy(pg + (page_offset % chip->page_size), buf, nb);
551
552 /* Write the page back out */
553 res = sam4l_write_page(chip, bank->target, address, pg);
554 free(pg);
555
556 return res;
557 }
558
559 static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer,
560 uint32_t offset, uint32_t count)
561 {
562 int res;
563 uint32_t nb = 0;
564 struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
565
566 if (bank->target->state != TARGET_HALTED) {
567 LOG_ERROR("Target not halted");
568
569 return ERROR_TARGET_NOT_HALTED;
570 }
571
572 if (!chip->probed) {
573 if (sam4l_probe(bank) != ERROR_OK)
574 return ERROR_FLASH_BANK_NOT_PROBED;
575 }
576
577 if (offset % chip->page_size) {
578 /* We're starting at an unaligned offset so we'll write a partial page
579 * comprising that offset and up to the end of that page. */
580 nb = chip->page_size - (offset % chip->page_size);
581 if (nb > count)
582 nb = count;
583 } else if (count < chip->page_size) {
584 /* We're writing an aligned but partial page. */
585 nb = count;
586 }
587
588 if (nb > 0) {
589 res = sam4l_write_page_partial(chip, bank,
590 (offset / chip->page_size) * chip->page_size + bank->base,
591 buffer,
592 offset % chip->page_size, nb);
593 if (res != ERROR_OK)
594 return res;
595
596 /* We're done with the page contents */
597 count -= nb;
598 offset += nb;
599 }
600
601 /* There's at least one aligned page to write out. */
602 if (count >= chip->page_size) {
603 int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0);
604
605 for (int i = 0; i < np; i++) {
606 if (count >= chip->page_size) {
607 res = sam4l_write_page(chip, bank->target,
608 bank->base + (i * chip->page_size),
609 buffer + (i * chip->page_size));
610 /* Advance one page */
611 offset += chip->page_size;
612 count -= chip->page_size;
613 } else {
614 res = sam4l_write_page_partial(chip, bank,
615 bank->base + (i * chip->page_size),
616 buffer + (i * chip->page_size), 0, count);
617 /* We're done after this. */
618 offset += count;
619 count = 0;
620 }
621
622 if (res != ERROR_OK)
623 return res;
624 }
625 }
626
627 return ERROR_OK;
628 }
629
630 COMMAND_HANDLER(sam4l_handle_info_command)
631 {
632 return ERROR_OK;
633 }
634
635 static const struct command_registration at91sam4l_exec_command_handlers[] = {
636 {
637 .name = "info",
638 .handler = sam4l_handle_info_command,
639 .mode = COMMAND_EXEC,
640 .help = "Print information about the current at91sam4l chip"
641 "and its flash configuration.",
642 },
643 COMMAND_REGISTRATION_DONE
644 };
645 static const struct command_registration at91sam4l_command_handlers[] = {
646 {
647 .name = "at91sam4l",
648 .mode = COMMAND_ANY,
649 .help = "at91sam4l flash command group",
650 .usage = "",
651 .chain = at91sam4l_exec_command_handlers,
652 },
653 COMMAND_REGISTRATION_DONE
654 };
655
656 struct flash_driver at91sam4l_flash = {
657 .name = "at91sam4l",
658 .commands = at91sam4l_command_handlers,
659 .flash_bank_command = sam4l_flash_bank_command,
660 .erase = sam4l_erase,
661 .protect = sam4l_protect,
662 .write = sam4l_write,
663 .read = default_flash_read,
664 .probe = sam4l_probe,
665 .auto_probe = sam4l_probe,
666 .erase_check = default_flash_blank_check,
667 .protect_check = sam4l_protect_check,
668 };

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)