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> *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
26 #include <helper/time_support.h>
27 #include <target/image.h>
31 * Implements Tcl commands used to access NOR flash facilities.
34 COMMAND_HELPER(flash_command_get_bank
, unsigned name_index
,
35 struct flash_bank
**bank
)
37 const char *name
= CMD_ARGV
[name_index
];
38 int retval
= get_flash_bank_by_name(name
, bank
);
39 if (retval
!= ERROR_OK
)
45 COMMAND_PARSE_NUMBER(uint
, name
, bank_num
);
47 return get_flash_bank_by_num(bank_num
, bank
);
50 COMMAND_HANDLER(handle_flash_info_command
)
57 return ERROR_COMMAND_SYNTAX_ERROR
;
59 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
60 if (retval
!= ERROR_OK
)
66 /* attempt auto probe */
67 retval
= p
->driver
->auto_probe(p
);
68 if (retval
!= ERROR_OK
)
71 /* We must query the hardware to avoid printing stale information! */
72 retval
= p
->driver
->protect_check(p
);
73 if (retval
!= ERROR_OK
)
76 command_print(CMD_CTX
,
77 "#%" PRIu32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
78 ", buswidth %i, chipwidth %i",
85 for (j
= 0; j
< p
->num_sectors
; j
++) {
88 if (p
->sectors
[j
].is_protected
== 0)
89 protect_state
= "not protected";
90 else if (p
->sectors
[j
].is_protected
== 1)
91 protect_state
= "protected";
93 protect_state
= "protection state unknown";
95 command_print(CMD_CTX
,
96 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
100 p
->sectors
[j
].size
>> 10,
104 *buf
= '\0'; /* initialize buffer, otherwise it migh contain garbage if driver
106 retval
= p
->driver
->info(p
, buf
, sizeof(buf
));
107 command_print(CMD_CTX
, "%s", buf
);
108 if (retval
!= ERROR_OK
)
109 LOG_ERROR("error retrieving flash info");
115 COMMAND_HANDLER(handle_flash_probe_command
)
117 struct flash_bank
*p
;
121 return ERROR_COMMAND_SYNTAX_ERROR
;
123 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
124 if (retval
!= ERROR_OK
)
128 retval
= p
->driver
->probe(p
);
129 if (retval
== ERROR_OK
)
130 command_print(CMD_CTX
,
131 "flash '%s' found at 0x%8.8" PRIx32
,
135 command_print(CMD_CTX
, "flash bank '#%s' is out of bounds", CMD_ARGV
[0]);
142 COMMAND_HANDLER(handle_flash_erase_check_command
)
145 return ERROR_COMMAND_SYNTAX_ERROR
;
147 struct flash_bank
*p
;
148 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
149 if (ERROR_OK
!= retval
)
153 retval
= p
->driver
->erase_check(p
);
154 if (retval
== ERROR_OK
)
155 command_print(CMD_CTX
, "successfully checked erase state");
157 command_print(CMD_CTX
,
158 "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32
,
163 for (j
= 0; j
< p
->num_sectors
; j
++) {
166 if (p
->sectors
[j
].is_erased
== 0)
167 erase_state
= "not erased";
168 else if (p
->sectors
[j
].is_erased
== 1)
169 erase_state
= "erased";
171 erase_state
= "erase state unknown";
173 command_print(CMD_CTX
,
174 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
176 p
->sectors
[j
].offset
,
178 p
->sectors
[j
].size
>> 10,
185 COMMAND_HANDLER(handle_flash_erase_address_command
)
187 struct flash_bank
*p
;
188 int retval
= ERROR_OK
;
192 bool do_unlock
= false;
193 struct target
*target
= get_current_target(CMD_CTX
);
195 while (CMD_ARGC
>= 3) {
196 /* Optionally pad out the address range to block/sector
197 * boundaries. We can't know if there's data in that part
198 * of the flash; only do padding if we're told to.
200 if (strcmp("pad", CMD_ARGV
[0]) == 0)
202 else if (strcmp("unlock", CMD_ARGV
[0]) == 0)
205 return ERROR_COMMAND_SYNTAX_ERROR
;
210 return ERROR_COMMAND_SYNTAX_ERROR
;
212 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
213 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], length
);
216 command_print(CMD_CTX
, "Length must be >0");
217 return ERROR_COMMAND_SYNTAX_ERROR
;
220 retval
= get_flash_bank_by_addr(target
, address
, true, &p
);
221 if (retval
!= ERROR_OK
)
224 /* We can't know if we did a resume + halt, in which case we no longer know the erased state
228 struct duration bench
;
229 duration_start(&bench
);
232 retval
= flash_unlock_address_range(target
, address
, length
);
234 if (retval
== ERROR_OK
)
235 retval
= flash_erase_address_range(target
, do_pad
, address
, length
);
237 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
)) {
238 command_print(CMD_CTX
, "erased address 0x%8.8x (length %i)"
239 " in %fs (%0.3f KiB/s)", address
, length
,
240 duration_elapsed(&bench
), duration_kbps(&bench
, length
));
246 static int flash_check_sector_parameters(struct command_context
*cmd_ctx
,
247 uint32_t first
, uint32_t last
, uint32_t num_sectors
)
249 if (!(first
<= last
)) {
250 command_print(cmd_ctx
, "ERROR: "
251 "first sector must be <= last sector");
255 if (!(last
<= (num_sectors
- 1))) {
256 command_print(cmd_ctx
, "ERROR: last sector must be <= %d",
257 (int) num_sectors
- 1);
264 COMMAND_HANDLER(handle_flash_erase_command
)
267 return ERROR_COMMAND_SYNTAX_ERROR
;
272 struct flash_bank
*p
;
275 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
276 if (retval
!= ERROR_OK
)
279 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
280 if (strcmp(CMD_ARGV
[2], "last") == 0)
281 last
= p
->num_sectors
- 1;
283 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
285 retval
= flash_check_sector_parameters(CMD_CTX
, first
, last
, p
->num_sectors
);
286 if (retval
!= ERROR_OK
)
289 struct duration bench
;
290 duration_start(&bench
);
292 retval
= flash_driver_erase(p
, first
, last
);
294 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
)) {
295 command_print(CMD_CTX
, "erased sectors %" PRIu32
" "
296 "through %" PRIu32
" on flash bank %" PRIu32
" "
297 "in %fs", first
, last
, p
->bank_number
, duration_elapsed(&bench
));
303 COMMAND_HANDLER(handle_flash_protect_command
)
306 return ERROR_COMMAND_SYNTAX_ERROR
;
311 struct flash_bank
*p
;
314 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
315 if (retval
!= ERROR_OK
)
318 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
319 if (strcmp(CMD_ARGV
[2], "last") == 0)
320 last
= p
->num_sectors
- 1;
322 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
325 COMMAND_PARSE_ON_OFF(CMD_ARGV
[3], set
);
327 retval
= flash_check_sector_parameters(CMD_CTX
, first
, last
, p
->num_sectors
);
328 if (retval
!= ERROR_OK
)
331 retval
= flash_driver_protect(p
, set
, first
, last
);
332 if (retval
== ERROR_OK
) {
333 command_print(CMD_CTX
, "%s protection for sectors %i "
334 "through %i on flash bank %" PRIu32
"",
335 (set
) ? "set" : "cleared", (int) first
,
336 (int) last
, p
->bank_number
);
342 COMMAND_HANDLER(handle_flash_write_image_command
)
344 struct target
*target
= get_current_target(CMD_CTX
);
352 return ERROR_COMMAND_SYNTAX_ERROR
;
354 /* flash auto-erase is disabled by default*/
356 bool auto_unlock
= false;
359 if (strcmp(CMD_ARGV
[0], "erase") == 0) {
363 command_print(CMD_CTX
, "auto erase enabled");
364 } else if (strcmp(CMD_ARGV
[0], "unlock") == 0) {
368 command_print(CMD_CTX
, "auto unlock enabled");
374 return ERROR_COMMAND_SYNTAX_ERROR
;
377 LOG_ERROR("no target selected");
381 struct duration bench
;
382 duration_start(&bench
);
385 image
.base_address_set
= 1;
386 COMMAND_PARSE_NUMBER(llong
, CMD_ARGV
[1], image
.base_address
);
388 image
.base_address_set
= 0;
389 image
.base_address
= 0x0;
392 image
.start_address_set
= 0;
394 retval
= image_open(&image
, CMD_ARGV
[0], (CMD_ARGC
== 3) ? CMD_ARGV
[2] : NULL
);
395 if (retval
!= ERROR_OK
)
398 retval
= flash_write_unlock(target
, &image
, &written
, auto_erase
, auto_unlock
);
399 if (retval
!= ERROR_OK
) {
404 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
)) {
405 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes from file %s "
406 "in %fs (%0.3f KiB/s)", written
, CMD_ARGV
[0],
407 duration_elapsed(&bench
), duration_kbps(&bench
, written
));
415 COMMAND_HANDLER(handle_flash_fill_command
)
422 uint32_t cur_size
= 0;
423 uint32_t chunk_count
;
424 struct target
*target
= get_current_target(CMD_CTX
);
427 int retval
= ERROR_OK
;
429 static size_t const chunksize
= 1024;
430 uint8_t *chunk
= NULL
, *readback
= NULL
;
433 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
437 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
438 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], pattern
);
439 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], count
);
441 chunk
= malloc(chunksize
);
445 readback
= malloc(chunksize
);
446 if (readback
== NULL
) {
454 switch (CMD_NAME
[4]) {
465 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
469 chunk_count
= MIN(count
, (chunksize
/ wordsize
));
472 for (i
= 0; i
< chunk_count
; i
++)
473 target_buffer_set_u32(target
, chunk
+ i
* wordsize
, pattern
);
476 for (i
= 0; i
< chunk_count
; i
++)
477 target_buffer_set_u16(target
, chunk
+ i
* wordsize
, pattern
);
480 memset(chunk
, pattern
, chunk_count
);
483 LOG_ERROR("BUG: can't happen");
487 struct duration bench
;
488 duration_start(&bench
);
490 for (wrote
= 0; wrote
< (count
*wordsize
); wrote
+= cur_size
) {
491 struct flash_bank
*bank
;
493 retval
= get_flash_bank_by_addr(target
, address
, true, &bank
);
494 if (retval
!= ERROR_OK
)
497 cur_size
= MIN((count
* wordsize
- wrote
), chunksize
);
498 err
= flash_driver_write(bank
, chunk
, address
- bank
->base
+ wrote
, cur_size
);
499 if (err
!= ERROR_OK
) {
504 err
= flash_driver_read(bank
, readback
, address
- bank
->base
+ wrote
, cur_size
);
505 if (err
!= ERROR_OK
) {
510 for (i
= 0; i
< cur_size
; i
++) {
511 if (readback
[i
] != chunk
[i
]) {
513 "Verification error address 0x%08" PRIx32
", read back 0x%02x, expected 0x%02x",
523 if ((retval
== ERROR_OK
) && (duration_measure(&bench
) == ERROR_OK
)) {
524 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes to 0x%8.8" PRIx32
525 " in %fs (%0.3f KiB/s)", wrote
, address
,
526 duration_elapsed(&bench
), duration_kbps(&bench
, wrote
));
536 COMMAND_HANDLER(handle_flash_write_bank_command
)
540 struct fileio fileio
;
543 return ERROR_COMMAND_SYNTAX_ERROR
;
545 struct duration bench
;
546 duration_start(&bench
);
548 struct flash_bank
*p
;
549 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
550 if (ERROR_OK
!= retval
)
553 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], offset
);
555 if (fileio_open(&fileio
, CMD_ARGV
[1], FILEIO_READ
, FILEIO_BINARY
) != ERROR_OK
)
559 retval
= fileio_size(&fileio
, &filesize
);
560 if (retval
!= ERROR_OK
) {
561 fileio_close(&fileio
);
565 buffer
= malloc(filesize
);
566 if (buffer
== NULL
) {
567 fileio_close(&fileio
);
568 LOG_ERROR("Out of memory");
572 if (fileio_read(&fileio
, filesize
, buffer
, &buf_cnt
) != ERROR_OK
) {
574 fileio_close(&fileio
);
578 retval
= flash_driver_write(p
, buffer
, offset
, buf_cnt
);
583 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
)) {
584 command_print(CMD_CTX
, "wrote %ld bytes from file %s to flash bank %u"
585 " at offset 0x%8.8" PRIx32
" in %fs (%0.3f KiB/s)",
586 (long)filesize
, CMD_ARGV
[1], p
->bank_number
, offset
,
587 duration_elapsed(&bench
), duration_kbps(&bench
, filesize
));
590 fileio_close(&fileio
);
595 void flash_set_dirty(void)
597 struct flash_bank
*c
;
600 /* set all flash to require erasing */
601 for (c
= flash_bank_list(); c
; c
= c
->next
) {
602 for (i
= 0; i
< c
->num_sectors
; i
++)
603 c
->sectors
[i
].is_erased
= 0;
607 static const struct command_registration flash_exec_command_handlers
[] = {
610 .handler
= handle_flash_probe_command
,
611 .mode
= COMMAND_EXEC
,
613 .help
= "Identify a flash bank.",
617 .handler
= handle_flash_info_command
,
618 .mode
= COMMAND_EXEC
,
620 .help
= "Print information about a flash bank.",
623 .name
= "erase_check",
624 .handler
= handle_flash_erase_check_command
,
625 .mode
= COMMAND_EXEC
,
627 .help
= "Check erase state of all blocks in a "
631 .name
= "erase_sector",
632 .handler
= handle_flash_erase_command
,
633 .mode
= COMMAND_EXEC
,
634 .usage
= "bank_id first_sector_num last_sector_num",
635 .help
= "Erase a range of sectors in a flash bank.",
638 .name
= "erase_address",
639 .handler
= handle_flash_erase_address_command
,
640 .mode
= COMMAND_EXEC
,
641 .usage
= "['pad'] ['unlock'] address length",
642 .help
= "Erase flash sectors starting at address and "
643 "continuing for length bytes. If 'pad' is specified, "
644 "data outside that range may also be erased: the start "
645 "address may be decreased, and length increased, so "
646 "that all of the first and last sectors are erased. "
647 "If 'unlock' is specified, then the flash is unprotected "
653 .handler
= handle_flash_fill_command
,
654 .mode
= COMMAND_EXEC
,
655 .usage
= "address value n",
656 .help
= "Fill n words with 32-bit value, starting at "
657 "word address. (No autoerase.)",
661 .handler
= handle_flash_fill_command
,
662 .mode
= COMMAND_EXEC
,
663 .usage
= "address value n",
664 .help
= "Fill n halfwords with 16-bit value, starting at "
665 "word address. (No autoerase.)",
669 .handler
= handle_flash_fill_command
,
670 .mode
= COMMAND_EXEC
,
671 .usage
= "address value n",
672 .help
= "Fill n bytes with 8-bit value, starting at "
673 "word address. (No autoerase.)",
676 .name
= "write_bank",
677 .handler
= handle_flash_write_bank_command
,
678 .mode
= COMMAND_EXEC
,
679 .usage
= "bank_id filename offset",
680 .help
= "Write binary data from file to flash bank, "
681 "starting at specified byte offset from the "
682 "beginning of the bank.",
685 .name
= "write_image",
686 .handler
= handle_flash_write_image_command
,
687 .mode
= COMMAND_EXEC
,
688 .usage
= "[erase] [unlock] filename [offset [file_type]]",
689 .help
= "Write an image to flash. Optionally first unprotect "
690 "and/or erase the region to be used. Allow optional "
691 "offset from beginning of bank (defaults to zero)",
695 .handler
= handle_flash_protect_command
,
696 .mode
= COMMAND_EXEC
,
697 .usage
= "bank_id first_sector [last_sector|'last'] "
699 .help
= "Turn protection on or off for a range of sectors "
700 "in a given flash bank.",
702 COMMAND_REGISTRATION_DONE
705 static int flash_init_drivers(struct command_context
*cmd_ctx
)
707 if (!flash_bank_list())
710 struct command
*parent
= command_find_in_context(cmd_ctx
, "flash");
711 return register_commands(cmd_ctx
, parent
, flash_exec_command_handlers
);
715 COMMAND_HANDLER(handle_flash_bank_command
)
718 LOG_ERROR("usage: flash bank <name> <driver> "
719 "<base> <size> <chip_width> <bus_width> <target>");
720 return ERROR_COMMAND_SYNTAX_ERROR
;
722 /* save bank name and advance arguments for compatibility */
723 const char *bank_name
= *CMD_ARGV
++;
726 struct target
*target
= get_target(CMD_ARGV
[5]);
727 if (target
== NULL
) {
728 LOG_ERROR("target '%s' not defined", CMD_ARGV
[5]);
732 const char *driver_name
= CMD_ARGV
[0];
733 struct flash_driver
*driver
= flash_driver_find_by_name(driver_name
);
734 if (NULL
== driver
) {
735 /* no matching flash driver found */
736 LOG_ERROR("flash driver '%s' not found", driver_name
);
740 /* check the flash bank name is unique */
741 if (get_flash_bank_by_name_noprobe(bank_name
) != NULL
) {
742 /* flash bank name already exists */
743 LOG_ERROR("flash bank name '%s' already exists", bank_name
);
747 /* register flash specific commands */
748 if (NULL
!= driver
->commands
) {
749 int retval
= register_commands(CMD_CTX
, NULL
,
751 if (ERROR_OK
!= retval
) {
752 LOG_ERROR("couldn't register '%s' commands",
758 struct flash_bank
*c
= malloc(sizeof(*c
));
759 c
->name
= strdup(bank_name
);
762 c
->driver_priv
= NULL
;
763 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], c
->base
);
764 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], c
->size
);
765 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], c
->chip_width
);
766 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[4], c
->bus_width
);
772 retval
= CALL_COMMAND_HANDLER(driver
->flash_bank_command
, c
);
773 if (ERROR_OK
!= retval
) {
774 LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32
"Usage %s",
775 driver_name
, c
->base
, driver
->usage
);
780 if (driver
->usage
== NULL
)
781 LOG_DEBUG("'%s' driver usage field missing", driver_name
);
788 COMMAND_HANDLER(handle_flash_banks_command
)
791 return ERROR_COMMAND_SYNTAX_ERROR
;
794 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
, n
++) {
795 LOG_USER("#%" PRIu32
" : %s (%s) at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", "
796 "buswidth %u, chipwidth %u", p
->bank_number
,
797 p
->name
, p
->driver
->name
, p
->base
, p
->size
,
798 p
->bus_width
, p
->chip_width
);
803 static int jim_flash_list(Jim_Interp
*interp
, int argc
, Jim_Obj
* const *argv
)
806 Jim_WrongNumArgs(interp
, 1, argv
,
807 "no arguments to 'flash list' command");
811 Jim_Obj
*list
= Jim_NewListObj(interp
, NULL
, 0);
813 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
) {
814 Jim_Obj
*elem
= Jim_NewListObj(interp
, NULL
, 0);
816 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "name", -1));
817 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, p
->driver
->name
, -1));
818 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "base", -1));
819 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->base
));
820 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "size", -1));
821 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->size
));
822 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "bus_width", -1));
823 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->bus_width
));
824 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "chip_width", -1));
825 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->chip_width
));
827 Jim_ListAppendElement(interp
, list
, elem
);
830 Jim_SetResult(interp
, list
);
835 COMMAND_HANDLER(handle_flash_init_command
)
838 return ERROR_COMMAND_SYNTAX_ERROR
;
840 static bool flash_initialized
;
841 if (flash_initialized
) {
842 LOG_INFO("'flash init' has already been called");
845 flash_initialized
= true;
847 LOG_DEBUG("Initializing flash devices...");
848 return flash_init_drivers(CMD_CTX
);
851 static const struct command_registration flash_config_command_handlers
[] = {
854 .handler
= handle_flash_bank_command
,
855 .mode
= COMMAND_CONFIG
,
856 .usage
= "bank_id driver_name base_address size_bytes "
857 "chip_width_bytes bus_width_bytes target "
858 "[driver_options ...]",
859 .help
= "Define a new bank with the given name, "
860 "using the specified NOR flash driver.",
864 .mode
= COMMAND_CONFIG
,
865 .handler
= handle_flash_init_command
,
866 .help
= "Initialize flash devices.",
871 .handler
= handle_flash_banks_command
,
872 .help
= "Display table with information about flash banks.",
877 .jim_handler
= jim_flash_list
,
878 .help
= "Returns a list of details about the flash banks.",
880 COMMAND_REGISTRATION_DONE
882 static const struct command_registration flash_command_handlers
[] = {
886 .help
= "NOR flash command group",
887 .chain
= flash_config_command_handlers
,
889 COMMAND_REGISTRATION_DONE
892 int flash_register_commands(struct command_context
*cmd_ctx
)
894 return register_commands(cmd_ctx
, NULL
, flash_command_handlers
);
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)