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

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)