Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface
[openocd.git] / src / flash / nor / tcl.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
4 * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
5 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
6 * Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 ***************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "imp.h"
25 #include <helper/time_support.h>
26 #include <target/image.h>
27
28 /**
29 * @file
30 * Implements Tcl commands used to access NOR flash facilities.
31 */
32
33 static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
34 struct flash_bank **bank, bool do_probe)
35 {
36 const char *name = CMD_ARGV[name_index];
37 int retval;
38 if (do_probe) {
39 retval = get_flash_bank_by_name(name, bank);
40 } else {
41 *bank = get_flash_bank_by_name_noprobe(name);
42 retval = ERROR_OK;
43 }
44
45 if (retval != ERROR_OK)
46 return retval;
47 if (*bank)
48 return ERROR_OK;
49
50 unsigned bank_num;
51 COMMAND_PARSE_NUMBER(uint, name, bank_num);
52
53 if (do_probe) {
54 return get_flash_bank_by_num(bank_num, bank);
55 } else {
56 *bank = get_flash_bank_by_num_noprobe(bank_num);
57 retval = (bank) ? ERROR_OK : ERROR_FAIL;
58 return retval;
59 }
60 }
61
62 COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
63 struct flash_bank **bank)
64 {
65 return CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe,
66 name_index, bank, true);
67 }
68
69 COMMAND_HANDLER(handle_flash_info_command)
70 {
71 struct flash_bank *p;
72 int j = 0;
73 int retval;
74 bool show_sectors = false;
75 bool prot_block_available;
76
77 if (CMD_ARGC < 1 || CMD_ARGC > 2)
78 return ERROR_COMMAND_SYNTAX_ERROR;
79
80 if (CMD_ARGC == 2) {
81 if (strcmp("sectors", CMD_ARGV[1]) == 0)
82 show_sectors = true;
83 else
84 return ERROR_COMMAND_SYNTAX_ERROR;
85 }
86
87 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
88 if (retval != ERROR_OK)
89 return retval;
90
91 if (p != NULL) {
92 char buf[1024];
93 int num_blocks;
94 struct flash_sector *block_array;
95
96 /* attempt auto probe */
97 retval = p->driver->auto_probe(p);
98 if (retval != ERROR_OK)
99 return retval;
100
101 /* If the driver does not implement protection, we show the default
102 * state of is_protected array - usually protection state unknown */
103 if (p->driver->protect_check == NULL) {
104 retval = ERROR_FLASH_OPER_UNSUPPORTED;
105 } else {
106 /* We must query the hardware to avoid printing stale information! */
107 retval = p->driver->protect_check(p);
108 if (retval != ERROR_OK && retval != ERROR_FLASH_OPER_UNSUPPORTED)
109 return retval;
110 }
111 if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
112 LOG_INFO("Flash protection check is not implemented.");
113
114 command_print(CMD,
115 "#%u : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32
116 ", buswidth %u, chipwidth %u",
117 p->bank_number,
118 p->driver->name,
119 p->base,
120 p->size,
121 p->bus_width,
122 p->chip_width);
123
124 prot_block_available = p->num_prot_blocks && p->prot_blocks;
125 if (!show_sectors && prot_block_available) {
126 block_array = p->prot_blocks;
127 num_blocks = p->num_prot_blocks;
128 } else {
129 block_array = p->sectors;
130 num_blocks = p->num_sectors;
131 }
132
133 for (j = 0; j < num_blocks; j++) {
134 char *protect_state = "";
135
136 if (block_array[j].is_protected == 0)
137 protect_state = "not protected";
138 else if (block_array[j].is_protected == 1)
139 protect_state = "protected";
140 else if (!show_sectors || !prot_block_available)
141 protect_state = "protection state unknown";
142
143 command_print(CMD,
144 "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIu32 "kB) %s",
145 j,
146 block_array[j].offset,
147 block_array[j].size,
148 block_array[j].size >> 10,
149 protect_state);
150 }
151
152 if (p->driver->info != NULL) {
153 retval = p->driver->info(p, buf, sizeof(buf));
154 if (retval == ERROR_OK)
155 command_print(CMD, "%s", buf);
156 else
157 LOG_ERROR("error retrieving flash info");
158 }
159 }
160
161 return retval;
162 }
163
164 COMMAND_HANDLER(handle_flash_probe_command)
165 {
166 struct flash_bank *p;
167 int retval;
168
169 if (CMD_ARGC != 1)
170 return ERROR_COMMAND_SYNTAX_ERROR;
171
172 retval = CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe, 0, &p, false);
173 if (retval != ERROR_OK)
174 return retval;
175
176 if (p) {
177 retval = p->driver->probe(p);
178 if (retval == ERROR_OK)
179 command_print(CMD,
180 "flash '%s' found at " TARGET_ADDR_FMT,
181 p->driver->name,
182 p->base);
183 } else {
184 command_print(CMD, "flash bank '#%s' is out of bounds", CMD_ARGV[0]);
185 retval = ERROR_FAIL;
186 }
187
188 return retval;
189 }
190
191 COMMAND_HANDLER(handle_flash_erase_check_command)
192 {
193 bool blank = true;
194 if (CMD_ARGC != 1)
195 return ERROR_COMMAND_SYNTAX_ERROR;
196
197 struct flash_bank *p;
198 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
199 if (ERROR_OK != retval)
200 return retval;
201
202 retval = p->driver->erase_check(p);
203 if (retval == ERROR_OK)
204 command_print(CMD, "successfully checked erase state");
205 else {
206 command_print(CMD,
207 "unknown error when checking erase state of flash bank #%s at "
208 TARGET_ADDR_FMT,
209 CMD_ARGV[0],
210 p->base);
211 }
212
213 for (unsigned int j = 0; j < p->num_sectors; j++) {
214 char *erase_state;
215
216 if (p->sectors[j].is_erased == 0)
217 erase_state = "not erased";
218 else if (p->sectors[j].is_erased == 1)
219 continue;
220 else
221 erase_state = "erase state unknown";
222
223 blank = false;
224 command_print(CMD,
225 "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIu32 "kB) %s",
226 j,
227 p->sectors[j].offset,
228 p->sectors[j].size,
229 p->sectors[j].size >> 10,
230 erase_state);
231 }
232
233 if (blank)
234 command_print(CMD, "\tBank is erased");
235 return retval;
236 }
237
238 COMMAND_HANDLER(handle_flash_erase_address_command)
239 {
240 struct flash_bank *p;
241 int retval = ERROR_OK;
242 target_addr_t address;
243 uint32_t length;
244 bool do_pad = false;
245 bool do_unlock = false;
246 struct target *target = get_current_target(CMD_CTX);
247
248 while (CMD_ARGC >= 3) {
249 /* Optionally pad out the address range to block/sector
250 * boundaries. We can't know if there's data in that part
251 * of the flash; only do padding if we're told to.
252 */
253 if (strcmp("pad", CMD_ARGV[0]) == 0)
254 do_pad = true;
255 else if (strcmp("unlock", CMD_ARGV[0]) == 0)
256 do_unlock = true;
257 else
258 return ERROR_COMMAND_SYNTAX_ERROR;
259 CMD_ARGC--;
260 CMD_ARGV++;
261 }
262 if (CMD_ARGC != 2)
263 return ERROR_COMMAND_SYNTAX_ERROR;
264
265 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
266 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
267
268 if (length <= 0) {
269 command_print(CMD, "Length must be >0");
270 return ERROR_COMMAND_SYNTAX_ERROR;
271 }
272
273 retval = get_flash_bank_by_addr(target, address, true, &p);
274 if (retval != ERROR_OK)
275 return retval;
276
277 /* We can't know if we did a resume + halt, in which case we no longer know the erased state
278 **/
279 flash_set_dirty();
280
281 struct duration bench;
282 duration_start(&bench);
283
284 if (do_unlock)
285 retval = flash_unlock_address_range(target, address, length);
286
287 if (retval == ERROR_OK)
288 retval = flash_erase_address_range(target, do_pad, address, length);
289
290 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
291 command_print(CMD, "erased address " TARGET_ADDR_FMT " (length %" PRIu32 ")"
292 " in %fs (%0.3f KiB/s)", address, length,
293 duration_elapsed(&bench), duration_kbps(&bench, length));
294 }
295
296 return retval;
297 }
298
299 COMMAND_HANDLER(handle_flash_erase_command)
300 {
301 if (CMD_ARGC != 3)
302 return ERROR_COMMAND_SYNTAX_ERROR;
303
304 uint32_t first;
305 uint32_t last;
306
307 struct flash_bank *p;
308 int retval;
309
310 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
311 if (retval != ERROR_OK)
312 return retval;
313
314 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
315 if (strcmp(CMD_ARGV[2], "last") == 0)
316 last = p->num_sectors - 1;
317 else
318 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
319
320 if (!(first <= last)) {
321 command_print(CMD, "ERROR: "
322 "first sector must be <= last");
323 return ERROR_FAIL;
324 }
325
326 if (!(last <= (p->num_sectors - 1))) {
327 command_print(CMD, "ERROR: "
328 "last sector must be <= %u",
329 p->num_sectors - 1);
330 return ERROR_FAIL;
331 }
332
333 struct duration bench;
334 duration_start(&bench);
335
336 retval = flash_driver_erase(p, first, last);
337
338 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
339 command_print(CMD, "erased sectors %" PRIu32 " "
340 "through %" PRIu32 " on flash bank %u "
341 "in %fs", first, last, p->bank_number, duration_elapsed(&bench));
342 }
343
344 return retval;
345 }
346
347 COMMAND_HANDLER(handle_flash_protect_command)
348 {
349 if (CMD_ARGC != 4)
350 return ERROR_COMMAND_SYNTAX_ERROR;
351
352 uint32_t first;
353 uint32_t last;
354
355 struct flash_bank *p;
356 int retval;
357 int num_blocks;
358
359 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
360 if (retval != ERROR_OK)
361 return retval;
362
363 if (p->num_prot_blocks)
364 num_blocks = p->num_prot_blocks;
365 else
366 num_blocks = p->num_sectors;
367
368 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
369 if (strcmp(CMD_ARGV[2], "last") == 0)
370 last = num_blocks - 1;
371 else
372 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
373
374 bool set;
375 COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
376
377 if (!(first <= last)) {
378 command_print(CMD, "ERROR: "
379 "first %s must be <= last",
380 (p->num_prot_blocks) ? "block" : "sector");
381 return ERROR_FAIL;
382 }
383
384 if (!(last <= (uint32_t)(num_blocks - 1))) {
385 command_print(CMD, "ERROR: "
386 "last %s must be <= %d",
387 (p->num_prot_blocks) ? "block" : "sector",
388 num_blocks - 1);
389 return ERROR_FAIL;
390 }
391
392 retval = flash_driver_protect(p, set, first, last);
393 if (retval == ERROR_OK) {
394 command_print(CMD, "%s protection for %s %" PRIu32
395 " through %" PRIu32 " on flash bank %d",
396 (set) ? "set" : "cleared",
397 (p->num_prot_blocks) ? "blocks" : "sectors",
398 first, last, p->bank_number);
399 }
400
401 return retval;
402 }
403
404 COMMAND_HANDLER(handle_flash_write_image_command)
405 {
406 struct target *target = get_current_target(CMD_CTX);
407
408 struct image image;
409 uint32_t written;
410
411 int retval;
412
413 /* flash auto-erase is disabled by default*/
414 int auto_erase = 0;
415 bool auto_unlock = false;
416
417 while (CMD_ARGC) {
418 if (strcmp(CMD_ARGV[0], "erase") == 0) {
419 auto_erase = 1;
420 CMD_ARGV++;
421 CMD_ARGC--;
422 command_print(CMD, "auto erase enabled");
423 } else if (strcmp(CMD_ARGV[0], "unlock") == 0) {
424 auto_unlock = true;
425 CMD_ARGV++;
426 CMD_ARGC--;
427 command_print(CMD, "auto unlock enabled");
428 } else
429 break;
430 }
431
432 if (CMD_ARGC < 1)
433 return ERROR_COMMAND_SYNTAX_ERROR;
434
435 if (!target) {
436 LOG_ERROR("no target selected");
437 return ERROR_FAIL;
438 }
439
440 struct duration bench;
441 duration_start(&bench);
442
443 if (CMD_ARGC >= 2) {
444 image.base_address_set = true;
445 COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address);
446 } else {
447 image.base_address_set = false;
448 image.base_address = 0x0;
449 }
450
451 image.start_address_set = false;
452
453 retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL);
454 if (retval != ERROR_OK)
455 return retval;
456
457 retval = flash_write_unlock_verify(target, &image, &written, auto_erase,
458 auto_unlock, true, false);
459 if (retval != ERROR_OK) {
460 image_close(&image);
461 return retval;
462 }
463
464 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
465 command_print(CMD, "wrote %" PRIu32 " bytes from file %s "
466 "in %fs (%0.3f KiB/s)", written, CMD_ARGV[0],
467 duration_elapsed(&bench), duration_kbps(&bench, written));
468 }
469
470 image_close(&image);
471
472 return retval;
473 }
474
475 COMMAND_HANDLER(handle_flash_verify_image_command)
476 {
477 struct target *target = get_current_target(CMD_CTX);
478
479 struct image image;
480 uint32_t verified;
481
482 int retval;
483
484 if (CMD_ARGC < 1)
485 return ERROR_COMMAND_SYNTAX_ERROR;
486
487 if (!target) {
488 LOG_ERROR("no target selected");
489 return ERROR_FAIL;
490 }
491
492 struct duration bench;
493 duration_start(&bench);
494
495 if (CMD_ARGC >= 2) {
496 image.base_address_set = 1;
497 COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address);
498 } else {
499 image.base_address_set = 0;
500 image.base_address = 0x0;
501 }
502
503 image.start_address_set = 0;
504
505 retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL);
506 if (retval != ERROR_OK)
507 return retval;
508
509 retval = flash_write_unlock_verify(target, &image, &verified, false,
510 false, false, true);
511 if (retval != ERROR_OK) {
512 image_close(&image);
513 return retval;
514 }
515
516 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
517 command_print(CMD, "verified %" PRIu32 " bytes from file %s "
518 "in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0],
519 duration_elapsed(&bench), duration_kbps(&bench, verified));
520 }
521
522 image_close(&image);
523
524 return retval;
525 }
526
527 COMMAND_HANDLER(handle_flash_fill_command)
528 {
529 target_addr_t address;
530 uint64_t pattern;
531 uint32_t count;
532 struct target *target = get_current_target(CMD_CTX);
533 unsigned i;
534 uint32_t wordsize;
535 int retval;
536
537 if (CMD_ARGC != 3)
538 return ERROR_COMMAND_SYNTAX_ERROR;
539
540 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
541 COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern);
542 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
543
544 struct flash_bank *bank;
545 retval = get_flash_bank_by_addr(target, address, true, &bank);
546 if (retval != ERROR_OK)
547 return retval;
548
549 switch (CMD_NAME[4]) {
550 case 'd':
551 wordsize = 8;
552 break;
553 case 'w':
554 wordsize = 4;
555 break;
556 case 'h':
557 wordsize = 2;
558 break;
559 case 'b':
560 wordsize = 1;
561 break;
562 default:
563 return ERROR_COMMAND_SYNTAX_ERROR;
564 }
565
566 if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) {
567 command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize);
568 return ERROR_FAIL;
569 }
570
571 if (count == 0)
572 return ERROR_OK;
573
574 if (address + count * wordsize > bank->base + bank->size) {
575 LOG_ERROR("Cannot cross flash bank borders");
576 return ERROR_FAIL;
577 }
578
579 uint32_t size_bytes = count * wordsize;
580 target_addr_t aligned_start = flash_write_align_start(bank, address);
581 target_addr_t end_addr = address + size_bytes - 1;
582 target_addr_t aligned_end = flash_write_align_end(bank, end_addr);
583 uint32_t aligned_size = aligned_end + 1 - aligned_start;
584 uint32_t padding_at_start = address - aligned_start;
585 uint32_t padding_at_end = aligned_end - end_addr;
586
587 uint8_t *buffer = malloc(aligned_size);
588 if (buffer == NULL)
589 return ERROR_FAIL;
590
591 if (padding_at_start) {
592 memset(buffer, bank->default_padded_value, padding_at_start);
593 LOG_WARNING("Start address " TARGET_ADDR_FMT
594 " breaks the required alignment of flash bank %s",
595 address, bank->name);
596 LOG_WARNING("Padding %" PRIu32 " bytes from " TARGET_ADDR_FMT,
597 padding_at_start, aligned_start);
598 }
599
600 uint8_t *ptr = buffer + padding_at_start;
601
602 switch (wordsize) {
603 case 8:
604 for (i = 0; i < count; i++, ptr += wordsize)
605 target_buffer_set_u64(target, ptr, pattern);
606 break;
607 case 4:
608 for (i = 0; i < count; i++, ptr += wordsize)
609 target_buffer_set_u32(target, ptr, pattern);
610 break;
611 case 2:
612 for (i = 0; i < count; i++, ptr += wordsize)
613 target_buffer_set_u16(target, ptr, pattern);
614 break;
615 case 1:
616 memset(ptr, pattern, count);
617 ptr += count;
618 break;
619 default:
620 LOG_ERROR("BUG: can't happen");
621 exit(-1);
622 }
623
624 if (padding_at_end) {
625 memset(ptr, bank->default_padded_value, padding_at_end);
626 LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRIu32
627 " bytes (bank write end alignment)",
628 end_addr + 1, padding_at_end);
629 }
630
631 struct duration bench;
632 duration_start(&bench);
633
634 retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size);
635 if (retval != ERROR_OK)
636 goto done;
637
638 retval = flash_driver_read(bank, buffer, address - bank->base, size_bytes);
639 if (retval != ERROR_OK)
640 goto done;
641
642 for (i = 0, ptr = buffer; i < count; i++) {
643 uint64_t readback = 0;
644
645 switch (wordsize) {
646 case 8:
647 readback = target_buffer_get_u64(target, ptr);
648 break;
649 case 4:
650 readback = target_buffer_get_u32(target, ptr);
651 break;
652 case 2:
653 readback = target_buffer_get_u16(target, ptr);
654 break;
655 case 1:
656 readback = *ptr;
657 break;
658 }
659 if (readback != pattern) {
660 LOG_ERROR(
661 "Verification error address " TARGET_ADDR_FMT
662 ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64,
663 address + i * wordsize, readback, pattern);
664 retval = ERROR_FAIL;
665 goto done;
666 }
667 ptr += wordsize;
668 }
669
670 if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
671 command_print(CMD, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT
672 " in %fs (%0.3f KiB/s)", size_bytes, address,
673 duration_elapsed(&bench), duration_kbps(&bench, size_bytes));
674 }
675
676 done:
677 free(buffer);
678
679 return retval;
680 }
681
682 COMMAND_HANDLER(handle_flash_md_command)
683 {
684 int retval;
685
686 if (CMD_ARGC < 1 || CMD_ARGC > 2)
687 return ERROR_COMMAND_SYNTAX_ERROR;
688
689 target_addr_t address;
690 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
691
692 uint32_t count = 1;
693 if (CMD_ARGC == 2)
694 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count);
695
696 unsigned int wordsize;
697 switch (CMD_NAME[2]) {
698 case 'w':
699 wordsize = 4;
700 break;
701 case 'h':
702 wordsize = 2;
703 break;
704 case 'b':
705 wordsize = 1;
706 break;
707 default:
708 return ERROR_COMMAND_SYNTAX_ERROR;
709 }
710
711 if (count == 0)
712 return ERROR_OK;
713
714 struct target *target = get_current_target(CMD_CTX);
715 struct flash_bank *bank;
716 retval = get_flash_bank_by_addr(target, address, true, &bank);
717 if (retval != ERROR_OK)
718 return retval;
719
720 uint32_t offset = address - bank->base;
721 uint32_t sizebytes = count * wordsize;
722 if (offset + sizebytes > bank->size) {
723 command_print(CMD, "Cannot cross flash bank borders");
724 return ERROR_FAIL;
725 }
726
727 uint8_t *buffer = calloc(count, wordsize);
728 if (buffer == NULL) {
729 command_print(CMD, "No memory for flash read buffer");
730 return ERROR_FAIL;
731 }
732
733 retval = flash_driver_read(bank, buffer, offset, sizebytes);
734 if (retval == ERROR_OK)
735 target_handle_md_output(CMD, target, address, wordsize, count, buffer);
736
737 free(buffer);
738
739 return retval;
740 }
741
742
743 COMMAND_HANDLER(handle_flash_write_bank_command)
744 {
745 uint32_t offset;
746 uint8_t *buffer;
747 size_t length;
748 struct fileio *fileio;
749
750 if (CMD_ARGC < 2 || CMD_ARGC > 3)
751 return ERROR_COMMAND_SYNTAX_ERROR;
752
753 struct duration bench;
754 duration_start(&bench);
755
756 struct flash_bank *bank;
757 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
758 if (ERROR_OK != retval)
759 return retval;
760
761 offset = 0;
762
763 if (CMD_ARGC > 2)
764 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
765
766 if (offset > bank->size) {
767 LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
768 offset);
769 return ERROR_COMMAND_ARGUMENT_INVALID;
770 }
771
772 if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
773 return ERROR_FAIL;
774
775 size_t filesize;
776 retval = fileio_size(fileio, &filesize);
777 if (retval != ERROR_OK) {
778 fileio_close(fileio);
779 return retval;
780 }
781
782 length = MIN(filesize, bank->size - offset);
783
784 if (!length) {
785 LOG_INFO("Nothing to write to flash bank");
786 fileio_close(fileio);
787 return ERROR_OK;
788 }
789
790 if (length != filesize)
791 LOG_INFO("File content exceeds flash bank size. Only writing the "
792 "first %zu bytes of the file", length);
793
794 target_addr_t start_addr = bank->base + offset;
795 target_addr_t aligned_start = flash_write_align_start(bank, start_addr);
796 target_addr_t end_addr = start_addr + length - 1;
797 target_addr_t aligned_end = flash_write_align_end(bank, end_addr);
798 uint32_t aligned_size = aligned_end + 1 - aligned_start;
799 uint32_t padding_at_start = start_addr - aligned_start;
800 uint32_t padding_at_end = aligned_end - end_addr;
801
802 buffer = malloc(aligned_size);
803 if (buffer == NULL) {
804 fileio_close(fileio);
805 LOG_ERROR("Out of memory");
806 return ERROR_FAIL;
807 }
808
809 if (padding_at_start) {
810 memset(buffer, bank->default_padded_value, padding_at_start);
811 LOG_WARNING("Start offset 0x%08" PRIx32
812 " breaks the required alignment of flash bank %s",
813 offset, bank->name);
814 LOG_WARNING("Padding %" PRIu32 " bytes from " TARGET_ADDR_FMT,
815 padding_at_start, aligned_start);
816 }
817
818 uint8_t *ptr = buffer + padding_at_start;
819 size_t buf_cnt;
820 if (fileio_read(fileio, length, ptr, &buf_cnt) != ERROR_OK) {
821 free(buffer);
822 fileio_close(fileio);
823 return ERROR_FAIL;
824 }
825
826 if (buf_cnt != length) {
827 LOG_ERROR("Short read");
828 free(buffer);
829 return ERROR_FAIL;
830 }
831
832 ptr += length;
833
834 if (padding_at_end) {
835 memset(ptr, bank->default_padded_value, padding_at_end);
836 LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRIu32
837 " bytes (bank write end alignment)",
838 end_addr + 1, padding_at_end);
839 }
840
841 retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size);
842
843 free(buffer);
844
845 if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
846 command_print(CMD, "wrote %zu bytes from file %s to flash bank %u"
847 " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
848 length, CMD_ARGV[1], bank->bank_number, offset,
849 duration_elapsed(&bench), duration_kbps(&bench, length));
850 }
851
852 fileio_close(fileio);
853
854 return retval;
855 }
856
857 COMMAND_HANDLER(handle_flash_read_bank_command)
858 {
859 uint32_t offset;
860 uint8_t *buffer;
861 struct fileio *fileio;
862 uint32_t length;
863 size_t written;
864
865 if (CMD_ARGC < 2 || CMD_ARGC > 4)
866 return ERROR_COMMAND_SYNTAX_ERROR;
867
868 struct duration bench;
869 duration_start(&bench);
870
871 struct flash_bank *p;
872 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
873
874 if (ERROR_OK != retval)
875 return retval;
876
877 offset = 0;
878
879 if (CMD_ARGC > 2)
880 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
881
882 if (offset > p->size) {
883 LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
884 offset);
885 return ERROR_COMMAND_ARGUMENT_INVALID;
886 }
887
888 length = p->size - offset;
889
890 if (CMD_ARGC > 3)
891 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length);
892
893 if (offset + length > p->size) {
894 LOG_ERROR("Length of %" PRIu32 " bytes with offset 0x%8.8" PRIx32
895 " is out of range of the flash bank", length, offset);
896 return ERROR_COMMAND_ARGUMENT_INVALID;
897 }
898
899 buffer = malloc(length);
900 if (buffer == NULL) {
901 LOG_ERROR("Out of memory");
902 return ERROR_FAIL;
903 }
904
905 retval = flash_driver_read(p, buffer, offset, length);
906 if (retval != ERROR_OK) {
907 LOG_ERROR("Read error");
908 free(buffer);
909 return retval;
910 }
911
912 retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY);
913 if (retval != ERROR_OK) {
914 LOG_ERROR("Could not open file");
915 free(buffer);
916 return retval;
917 }
918
919 retval = fileio_write(fileio, length, buffer, &written);
920 fileio_close(fileio);
921 free(buffer);
922 if (retval != ERROR_OK) {
923 LOG_ERROR("Could not write file");
924 return ERROR_FAIL;
925 }
926
927 if (duration_measure(&bench) == ERROR_OK)
928 command_print(CMD, "wrote %zd bytes to file %s from flash bank %u"
929 " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
930 written, CMD_ARGV[1], p->bank_number, offset,
931 duration_elapsed(&bench), duration_kbps(&bench, written));
932
933 return retval;
934 }
935
936
937 COMMAND_HANDLER(handle_flash_verify_bank_command)
938 {
939 uint32_t offset;
940 uint8_t *buffer_file, *buffer_flash;
941 struct fileio *fileio;
942 size_t read_cnt;
943 size_t filesize;
944 size_t length;
945 int differ;
946
947 if (CMD_ARGC < 2 || CMD_ARGC > 3)
948 return ERROR_COMMAND_SYNTAX_ERROR;
949
950 struct duration bench;
951 duration_start(&bench);
952
953 struct flash_bank *p;
954 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
955 if (ERROR_OK != retval)
956 return retval;
957
958 offset = 0;
959
960 if (CMD_ARGC > 2)
961 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
962
963 if (offset > p->size) {
964 LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
965 offset);
966 return ERROR_COMMAND_ARGUMENT_INVALID;
967 }
968
969 retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY);
970 if (retval != ERROR_OK) {
971 LOG_ERROR("Could not open file");
972 return retval;
973 }
974
975 retval = fileio_size(fileio, &filesize);
976 if (retval != ERROR_OK) {
977 fileio_close(fileio);
978 return retval;
979 }
980
981 length = MIN(filesize, p->size - offset);
982
983 if (!length) {
984 LOG_INFO("Nothing to compare with flash bank");
985 fileio_close(fileio);
986 return ERROR_OK;
987 }
988
989 if (length != filesize)
990 LOG_INFO("File content exceeds flash bank size. Only comparing the "
991 "first %zu bytes of the file", length);
992
993 buffer_file = malloc(length);
994 if (buffer_file == NULL) {
995 LOG_ERROR("Out of memory");
996 fileio_close(fileio);
997 return ERROR_FAIL;
998 }
999
1000 retval = fileio_read(fileio, length, buffer_file, &read_cnt);
1001 fileio_close(fileio);
1002 if (retval != ERROR_OK) {
1003 LOG_ERROR("File read failure");
1004 free(buffer_file);
1005 return retval;
1006 }
1007
1008 if (read_cnt != length) {
1009 LOG_ERROR("Short read");
1010 free(buffer_file);
1011 return ERROR_FAIL;
1012 }
1013
1014 buffer_flash = malloc(length);
1015 if (buffer_flash == NULL) {
1016 LOG_ERROR("Out of memory");
1017 free(buffer_file);
1018 return ERROR_FAIL;
1019 }
1020
1021 retval = flash_driver_read(p, buffer_flash, offset, length);
1022 if (retval != ERROR_OK) {
1023 LOG_ERROR("Flash read error");
1024 free(buffer_flash);
1025 free(buffer_file);
1026 return retval;
1027 }
1028
1029 if (duration_measure(&bench) == ERROR_OK)
1030 command_print(CMD, "read %zd bytes from file %s and flash bank %u"
1031 " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
1032 length, CMD_ARGV[1], p->bank_number, offset,
1033 duration_elapsed(&bench), duration_kbps(&bench, length));
1034
1035 differ = memcmp(buffer_file, buffer_flash, length);
1036 command_print(CMD, "contents %s", differ ? "differ" : "match");
1037 if (differ) {
1038 uint32_t t;
1039 int diffs = 0;
1040 for (t = 0; t < length; t++) {
1041 if (buffer_flash[t] == buffer_file[t])
1042 continue;
1043 command_print(CMD, "diff %d address 0x%08" PRIx32 ". Was 0x%02x instead of 0x%02x",
1044 diffs, t + offset, buffer_flash[t], buffer_file[t]);
1045 if (diffs++ >= 127) {
1046 command_print(CMD, "More than 128 errors, the rest are not printed.");
1047 break;
1048 }
1049 keep_alive();
1050 }
1051 }
1052 free(buffer_flash);
1053 free(buffer_file);
1054
1055 return differ ? ERROR_FAIL : ERROR_OK;
1056 }
1057
1058 void flash_set_dirty(void)
1059 {
1060 struct flash_bank *c;
1061
1062 /* set all flash to require erasing */
1063 for (c = flash_bank_list(); c; c = c->next) {
1064 for (unsigned int i = 0; i < c->num_sectors; i++)
1065 c->sectors[i].is_erased = 0;
1066 }
1067 }
1068
1069 COMMAND_HANDLER(handle_flash_padded_value_command)
1070 {
1071 if (CMD_ARGC != 2)
1072 return ERROR_COMMAND_SYNTAX_ERROR;
1073
1074 struct flash_bank *p;
1075 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
1076 if (ERROR_OK != retval)
1077 return retval;
1078
1079 COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value);
1080
1081 command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u",
1082 p->default_padded_value, p->bank_number);
1083
1084 return retval;
1085 }
1086
1087 static const struct command_registration flash_exec_command_handlers[] = {
1088 {
1089 .name = "probe",
1090 .handler = handle_flash_probe_command,
1091 .mode = COMMAND_EXEC,
1092 .usage = "bank_id",
1093 .help = "Identify a flash bank.",
1094 },
1095 {
1096 .name = "info",
1097 .handler = handle_flash_info_command,
1098 .mode = COMMAND_EXEC,
1099 .usage = "bank_id ['sectors']",
1100 .help = "Print information about a flash bank.",
1101 },
1102 {
1103 .name = "erase_check",
1104 .handler = handle_flash_erase_check_command,
1105 .mode = COMMAND_EXEC,
1106 .usage = "bank_id",
1107 .help = "Check erase state of all blocks in a "
1108 "flash bank.",
1109 },
1110 {
1111 .name = "erase_sector",
1112 .handler = handle_flash_erase_command,
1113 .mode = COMMAND_EXEC,
1114 .usage = "bank_id first_sector_num (last_sector_num|'last')",
1115 .help = "Erase a range of sectors in a flash bank.",
1116 },
1117 {
1118 .name = "erase_address",
1119 .handler = handle_flash_erase_address_command,
1120 .mode = COMMAND_EXEC,
1121 .usage = "['pad'] ['unlock'] address length",
1122 .help = "Erase flash sectors starting at address and "
1123 "continuing for length bytes. If 'pad' is specified, "
1124 "data outside that range may also be erased: the start "
1125 "address may be decreased, and length increased, so "
1126 "that all of the first and last sectors are erased. "
1127 "If 'unlock' is specified, then the flash is unprotected "
1128 "before erasing.",
1129
1130 },
1131 {
1132 .name = "filld",
1133 .handler = handle_flash_fill_command,
1134 .mode = COMMAND_EXEC,
1135 .usage = "address value n",
1136 .help = "Fill n double-words with 64-bit value, starting at "
1137 "word address. (No autoerase.)",
1138 },
1139 {
1140 .name = "fillw",
1141 .handler = handle_flash_fill_command,
1142 .mode = COMMAND_EXEC,
1143 .usage = "address value n",
1144 .help = "Fill n words with 32-bit value, starting at "
1145 "word address. (No autoerase.)",
1146 },
1147 {
1148 .name = "fillh",
1149 .handler = handle_flash_fill_command,
1150 .mode = COMMAND_EXEC,
1151 .usage = "address value n",
1152 .help = "Fill n halfwords with 16-bit value, starting at "
1153 "word address. (No autoerase.)",
1154 },
1155 {
1156 .name = "fillb",
1157 .handler = handle_flash_fill_command,
1158 .mode = COMMAND_EXEC,
1159 .usage = "address value n",
1160 .help = "Fill n bytes with 8-bit value, starting at "
1161 "word address. (No autoerase.)",
1162 },
1163 {
1164 .name = "mdb",
1165 .handler = handle_flash_md_command,
1166 .mode = COMMAND_EXEC,
1167 .usage = "address [count]",
1168 .help = "Display bytes from flash.",
1169 },
1170 {
1171 .name = "mdh",
1172 .handler = handle_flash_md_command,
1173 .mode = COMMAND_EXEC,
1174 .usage = "address [count]",
1175 .help = "Display half-words from flash.",
1176 },
1177 {
1178 .name = "mdw",
1179 .handler = handle_flash_md_command,
1180 .mode = COMMAND_EXEC,
1181 .usage = "address [count]",
1182 .help = "Display words from flash.",
1183 },
1184 {
1185 .name = "write_bank",
1186 .handler = handle_flash_write_bank_command,
1187 .mode = COMMAND_EXEC,
1188 .usage = "bank_id filename [offset]",
1189 .help = "Write binary data from file to flash bank. Allow optional "
1190 "offset from beginning of the bank (defaults to zero).",
1191 },
1192 {
1193 .name = "write_image",
1194 .handler = handle_flash_write_image_command,
1195 .mode = COMMAND_EXEC,
1196 .usage = "[erase] [unlock] filename [offset [file_type]]",
1197 .help = "Write an image to flash. Optionally first unprotect "
1198 "and/or erase the region to be used. Allow optional "
1199 "offset from beginning of bank (defaults to zero)",
1200 },
1201 {
1202 .name = "verify_image",
1203 .handler = handle_flash_verify_image_command,
1204 .mode = COMMAND_EXEC,
1205 .usage = "filename [offset [file_type]]",
1206 .help = "Verify an image against flash. Allow optional "
1207 "offset from beginning of bank (defaults to zero)",
1208 },
1209 {
1210 .name = "read_bank",
1211 .handler = handle_flash_read_bank_command,
1212 .mode = COMMAND_EXEC,
1213 .usage = "bank_id filename [offset [length]]",
1214 .help = "Read binary data from flash bank to file. Allow optional "
1215 "offset from beginning of the bank (defaults to zero).",
1216 },
1217 {
1218 .name = "verify_bank",
1219 .handler = handle_flash_verify_bank_command,
1220 .mode = COMMAND_EXEC,
1221 .usage = "bank_id filename [offset]",
1222 .help = "Compare the contents of a file with the contents of the "
1223 "flash bank. Allow optional offset from beginning of the bank "
1224 "(defaults to zero).",
1225 },
1226 {
1227 .name = "protect",
1228 .handler = handle_flash_protect_command,
1229 .mode = COMMAND_EXEC,
1230 .usage = "bank_id first_block [last_block|'last'] "
1231 "('on'|'off')",
1232 .help = "Turn protection on or off for a range of protection "
1233 "blocks or sectors in a given flash bank. "
1234 "See 'flash info' output for a list of blocks.",
1235 },
1236 {
1237 .name = "padded_value",
1238 .handler = handle_flash_padded_value_command,
1239 .mode = COMMAND_EXEC,
1240 .usage = "bank_id value",
1241 .help = "Set default flash padded value",
1242 },
1243 COMMAND_REGISTRATION_DONE
1244 };
1245
1246 static int flash_init_drivers(struct command_context *cmd_ctx)
1247 {
1248 if (!flash_bank_list())
1249 return ERROR_OK;
1250
1251 struct command *parent = command_find_in_context(cmd_ctx, "flash");
1252 return register_commands(cmd_ctx, parent, flash_exec_command_handlers);
1253 }
1254
1255 COMMAND_HANDLER(handle_flash_bank_command)
1256 {
1257 if (CMD_ARGC < 7) {
1258 LOG_ERROR("usage: flash bank <name> <driver> "
1259 "<base> <size> <chip_width> <bus_width> <target>");
1260 return ERROR_COMMAND_SYNTAX_ERROR;
1261 }
1262 /* save bank name and advance arguments for compatibility */
1263 const char *bank_name = *CMD_ARGV++;
1264 CMD_ARGC--;
1265
1266 struct target *target = get_target(CMD_ARGV[5]);
1267 if (target == NULL) {
1268 LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
1269 return ERROR_FAIL;
1270 }
1271
1272 const char *driver_name = CMD_ARGV[0];
1273 const struct flash_driver *driver = flash_driver_find_by_name(driver_name);
1274 if (NULL == driver) {
1275 /* no matching flash driver found */
1276 LOG_ERROR("flash driver '%s' not found", driver_name);
1277 return ERROR_FAIL;
1278 }
1279
1280 /* check the flash bank name is unique */
1281 if (get_flash_bank_by_name_noprobe(bank_name) != NULL) {
1282 /* flash bank name already exists */
1283 LOG_ERROR("flash bank name '%s' already exists", bank_name);
1284 return ERROR_FAIL;
1285 }
1286
1287 /* register flash specific commands */
1288 if (NULL != driver->commands) {
1289 int retval = register_commands(CMD_CTX, NULL,
1290 driver->commands);
1291 if (ERROR_OK != retval) {
1292 LOG_ERROR("couldn't register '%s' commands",
1293 driver_name);
1294 return ERROR_FAIL;
1295 }
1296 }
1297
1298 struct flash_bank *c = calloc(1, sizeof(*c));
1299 c->name = strdup(bank_name);
1300 c->target = target;
1301 c->driver = driver;
1302 COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], c->base);
1303 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size);
1304 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], c->chip_width);
1305 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[4], c->bus_width);
1306 c->default_padded_value = c->erased_value = 0xff;
1307 c->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
1308
1309 int retval;
1310 retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c);
1311 if (ERROR_OK != retval) {
1312 LOG_ERROR("'%s' driver rejected flash bank at " TARGET_ADDR_FMT
1313 "; usage: %s", driver_name, c->base, driver->usage);
1314 free(c);
1315 return retval;
1316 }
1317
1318 if (driver->usage == NULL)
1319 LOG_DEBUG("'%s' driver usage field missing", driver_name);
1320
1321 flash_bank_add(c);
1322
1323 return ERROR_OK;
1324 }
1325
1326 COMMAND_HANDLER(handle_flash_banks_command)
1327 {
1328 if (CMD_ARGC != 0)
1329 return ERROR_COMMAND_SYNTAX_ERROR;
1330
1331 unsigned n = 0;
1332 for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) {
1333 command_print(CMD, "#%d : %s (%s) at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", "
1334 "buswidth %u, chipwidth %u", p->bank_number,
1335 p->name, p->driver->name, p->base, p->size,
1336 p->bus_width, p->chip_width);
1337 }
1338 return ERROR_OK;
1339 }
1340
1341 static int jim_flash_list(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
1342 {
1343 if (argc != 1) {
1344 Jim_WrongNumArgs(interp, 1, argv,
1345 "no arguments to 'flash list' command");
1346 return JIM_ERR;
1347 }
1348
1349 Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
1350
1351 for (struct flash_bank *p = flash_bank_list(); p; p = p->next) {
1352 Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0);
1353
1354 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
1355 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
1356 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
1357 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
1358 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
1359 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
1360 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
1361 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
1362 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
1363 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
1364
1365 Jim_ListAppendElement(interp, list, elem);
1366 }
1367
1368 Jim_SetResult(interp, list);
1369
1370 return JIM_OK;
1371 }
1372
1373 COMMAND_HANDLER(handle_flash_init_command)
1374 {
1375 if (CMD_ARGC != 0)
1376 return ERROR_COMMAND_SYNTAX_ERROR;
1377
1378 static bool flash_initialized;
1379 if (flash_initialized) {
1380 LOG_INFO("'flash init' has already been called");
1381 return ERROR_OK;
1382 }
1383 flash_initialized = true;
1384
1385 LOG_DEBUG("Initializing flash devices...");
1386 return flash_init_drivers(CMD_CTX);
1387 }
1388
1389 static const struct command_registration flash_config_command_handlers[] = {
1390 {
1391 .name = "bank",
1392 .handler = handle_flash_bank_command,
1393 .mode = COMMAND_CONFIG,
1394 .usage = "bank_id driver_name base_address size_bytes "
1395 "chip_width_bytes bus_width_bytes target "
1396 "[driver_options ...]",
1397 .help = "Define a new bank with the given name, "
1398 "using the specified NOR flash driver.",
1399 },
1400 {
1401 .name = "init",
1402 .mode = COMMAND_CONFIG,
1403 .handler = handle_flash_init_command,
1404 .help = "Initialize flash devices.",
1405 .usage = "",
1406 },
1407 {
1408 .name = "banks",
1409 .mode = COMMAND_ANY,
1410 .handler = handle_flash_banks_command,
1411 .help = "Display table with information about flash banks.",
1412 .usage = "",
1413 },
1414 {
1415 .name = "list",
1416 .mode = COMMAND_ANY,
1417 .jim_handler = jim_flash_list,
1418 .help = "Returns a list of details about the flash banks.",
1419 },
1420 COMMAND_REGISTRATION_DONE
1421 };
1422 static const struct command_registration flash_command_handlers[] = {
1423 {
1424 .name = "flash",
1425 .mode = COMMAND_ANY,
1426 .help = "NOR flash command group",
1427 .chain = flash_config_command_handlers,
1428 .usage = "",
1429 },
1430 COMMAND_REGISTRATION_DONE
1431 };
1432
1433 int flash_register_commands(struct command_context *cmd_ctx)
1434 {
1435 return register_commands(cmd_ctx, NULL, flash_command_handlers);
1436 }

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)