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
);
51 COMMAND_HANDLER(handle_flash_info_command
)
58 return ERROR_COMMAND_SYNTAX_ERROR
;
60 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
61 if (retval
!= ERROR_OK
)
68 /* attempt auto probe */
69 if ((retval
= p
->driver
->auto_probe(p
)) != ERROR_OK
)
72 /* We must query the hardware to avoid printing stale information! */
73 retval
= p
->driver
->protect_check(p
);
74 if (retval
!= ERROR_OK
)
77 command_print(CMD_CTX
,
78 "#%" PRIu32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", buswidth %i, chipwidth %i",
85 for (j
= 0; j
< p
->num_sectors
; j
++)
89 if (p
->sectors
[j
].is_protected
== 0)
90 protect_state
= "not protected";
91 else if (p
->sectors
[j
].is_protected
== 1)
92 protect_state
= "protected";
94 protect_state
= "protection state unknown";
96 command_print(CMD_CTX
,
97 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
101 p
->sectors
[j
].size
>> 10,
105 *buf
= '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
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 (%d)", retval
);
115 COMMAND_HANDLER(handle_flash_probe_command
)
117 struct flash_bank
*p
;
122 return ERROR_COMMAND_SYNTAX_ERROR
;
125 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
126 if (retval
!= ERROR_OK
)
131 if ((retval
= p
->driver
->probe(p
)) == ERROR_OK
)
133 command_print(CMD_CTX
, "flash '%s' found at 0x%8.8" PRIx32
, p
->driver
->name
, p
->base
);
135 else if (retval
== ERROR_FLASH_BANK_INVALID
)
137 command_print(CMD_CTX
, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32
,
138 CMD_ARGV
[0], p
->base
);
142 command_print(CMD_CTX
, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32
,
143 CMD_ARGV
[0], p
->base
);
148 command_print(CMD_CTX
, "flash bank '#%s' is out of bounds", CMD_ARGV
[0]);
154 COMMAND_HANDLER(handle_flash_erase_check_command
)
158 return ERROR_COMMAND_SYNTAX_ERROR
;
161 struct flash_bank
*p
;
162 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
163 if (ERROR_OK
!= retval
)
167 if ((retval
= p
->driver
->erase_check(p
)) == ERROR_OK
)
169 command_print(CMD_CTX
, "successfully checked erase state");
173 command_print(CMD_CTX
, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32
,
174 CMD_ARGV
[0], p
->base
);
177 for (j
= 0; j
< p
->num_sectors
; j
++)
181 if (p
->sectors
[j
].is_erased
== 0)
182 erase_state
= "not erased";
183 else if (p
->sectors
[j
].is_erased
== 1)
184 erase_state
= "erased";
186 erase_state
= "erase state unknown";
188 command_print(CMD_CTX
,
189 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
191 p
->sectors
[j
].offset
,
193 p
->sectors
[j
].size
>> 10,
200 COMMAND_HANDLER(handle_flash_erase_address_command
)
202 struct flash_bank
*p
;
203 int retval
= ERROR_OK
;
207 bool do_unlock
= false;
208 struct target
*target
= get_current_target(CMD_CTX
);
210 while (CMD_ARGC
>= 3)
212 /* Optionally pad out the address range to block/sector
213 * boundaries. We can't know if there's data in that part
214 * of the flash; only do padding if we're told to.
216 if (strcmp("pad", CMD_ARGV
[0]) == 0)
219 } else if (strcmp("unlock", CMD_ARGV
[0]) == 0)
224 return ERROR_COMMAND_SYNTAX_ERROR
;
231 return ERROR_COMMAND_SYNTAX_ERROR
;
234 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
235 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], length
);
239 command_print(CMD_CTX
, "Length must be >0");
240 return ERROR_COMMAND_SYNTAX_ERROR
;
243 retval
= get_flash_bank_by_addr(target
, address
, true, &p
);
244 if (retval
!= ERROR_OK
)
247 /* We can't know if we did a resume + halt, in which case we no longer know the erased state */
250 struct duration bench
;
251 duration_start(&bench
);
255 retval
= flash_unlock_address_range(target
, address
, length
);
258 if (retval
== ERROR_OK
)
260 retval
= flash_erase_address_range(target
, do_pad
, address
, length
);
263 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
265 command_print(CMD_CTX
, "erased address 0x%8.8x (length %i)"
266 " in %fs (%0.3f KiB/s)", address
, length
,
267 duration_elapsed(&bench
), duration_kbps(&bench
, length
));
273 static int flash_check_sector_parameters(struct command_context
*cmd_ctx
,
274 uint32_t first
, uint32_t last
, uint32_t num_sectors
)
276 if (!(first
<= last
)) {
277 command_print(cmd_ctx
, "ERROR: "
278 "first sector must be <= last sector");
282 if (!(last
<= (num_sectors
- 1))) {
283 command_print(cmd_ctx
, "ERROR: last sector must be <= %d",
284 (int) num_sectors
- 1);
291 COMMAND_HANDLER(handle_flash_erase_command
)
294 return ERROR_COMMAND_SYNTAX_ERROR
;
299 struct flash_bank
*p
;
302 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
303 if (retval
!= ERROR_OK
)
306 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
307 if (strcmp(CMD_ARGV
[2], "last") == 0)
308 last
= p
->num_sectors
- 1;
310 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
312 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
313 first
, last
, p
->num_sectors
)) != ERROR_OK
)
316 struct duration bench
;
317 duration_start(&bench
);
319 retval
= flash_driver_erase(p
, first
, last
);
321 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
323 command_print(CMD_CTX
, "erased sectors %" PRIu32
" "
324 "through %" PRIu32
" on flash bank %" PRIu32
" "
325 "in %fs", first
, last
, p
->bank_number
, duration_elapsed(&bench
));
331 COMMAND_HANDLER(handle_flash_protect_command
)
334 return ERROR_COMMAND_SYNTAX_ERROR
;
339 struct flash_bank
*p
;
342 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
343 if (retval
!= ERROR_OK
)
346 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
347 if (strcmp(CMD_ARGV
[2], "last") == 0)
348 last
= p
->num_sectors
- 1;
350 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
353 COMMAND_PARSE_ON_OFF(CMD_ARGV
[3], set
);
355 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
356 first
, last
, p
->num_sectors
)) != ERROR_OK
)
359 retval
= flash_driver_protect(p
, set
, first
, last
);
360 if (retval
== ERROR_OK
) {
361 command_print(CMD_CTX
, "%s protection for sectors %i "
362 "through %i on flash bank %" PRIu32
"",
363 (set
) ? "set" : "cleared", (int) first
,
364 (int) last
, p
->bank_number
);
370 COMMAND_HANDLER(handle_flash_write_image_command
)
372 struct target
*target
= get_current_target(CMD_CTX
);
381 return ERROR_COMMAND_SYNTAX_ERROR
;
384 /* flash auto-erase is disabled by default*/
386 bool auto_unlock
= false;
390 if (strcmp(CMD_ARGV
[0], "erase") == 0)
395 command_print(CMD_CTX
, "auto erase enabled");
396 } else if (strcmp(CMD_ARGV
[0], "unlock") == 0)
401 command_print(CMD_CTX
, "auto unlock enabled");
410 return ERROR_COMMAND_SYNTAX_ERROR
;
415 LOG_ERROR("no target selected");
419 struct duration bench
;
420 duration_start(&bench
);
424 image
.base_address_set
= 1;
425 COMMAND_PARSE_NUMBER(llong
, CMD_ARGV
[1], image
.base_address
);
429 image
.base_address_set
= 0;
430 image
.base_address
= 0x0;
433 image
.start_address_set
= 0;
435 retval
= image_open(&image
, CMD_ARGV
[0], (CMD_ARGC
== 3) ? CMD_ARGV
[2] : NULL
);
436 if (retval
!= ERROR_OK
)
441 retval
= flash_write_unlock(target
, &image
, &written
, auto_erase
, auto_unlock
);
442 if (retval
!= ERROR_OK
)
448 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
450 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes from file %s "
451 "in %fs (%0.3f KiB/s)", written
, CMD_ARGV
[0],
452 duration_elapsed(&bench
), duration_kbps(&bench
, written
));
460 COMMAND_HANDLER(handle_flash_fill_command
)
467 uint32_t cur_size
= 0;
468 uint32_t chunk_count
;
469 struct target
*target
= get_current_target(CMD_CTX
);
472 int retval
= ERROR_OK
;
474 static size_t const chunksize
= 1024;
475 uint8_t *chunk
= malloc(chunksize
);
479 uint8_t *readback
= malloc(chunksize
);
480 if (readback
== NULL
)
489 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
494 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
495 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], pattern
);
496 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], count
);
513 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
517 chunk_count
= MIN(count
, (chunksize
/ wordsize
));
521 for (i
= 0; i
< chunk_count
; i
++)
523 target_buffer_set_u32(target
, chunk
+ i
* wordsize
, pattern
);
527 for (i
= 0; i
< chunk_count
; i
++)
529 target_buffer_set_u16(target
, chunk
+ i
* wordsize
, pattern
);
533 memset(chunk
, pattern
, chunk_count
);
536 LOG_ERROR("BUG: can't happen");
540 struct duration bench
;
541 duration_start(&bench
);
543 for (wrote
= 0; wrote
< (count
*wordsize
); wrote
+= cur_size
)
545 struct flash_bank
*bank
;
547 retval
= get_flash_bank_by_addr(target
, address
, true, &bank
);
548 if (retval
!= ERROR_OK
)
551 cur_size
= MIN((count
* wordsize
- wrote
), chunksize
);
552 err
= flash_driver_write(bank
, chunk
, address
- bank
->base
+ wrote
, cur_size
);
559 err
= flash_driver_read(bank
, readback
, address
- bank
->base
+ wrote
, cur_size
);
566 for (i
= 0; i
< cur_size
; i
++)
568 if (readback
[i
]!=chunk
[i
])
570 LOG_ERROR("Verification error address 0x%08" PRIx32
", read back 0x%02x, expected 0x%02x",
571 address
+ wrote
+ i
, readback
[i
], chunk
[i
]);
578 if ((retval
== ERROR_OK
) && (duration_measure(&bench
) == ERROR_OK
))
580 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes to 0x%8.8" PRIx32
581 " in %fs (%0.3f KiB/s)", wrote
, address
,
582 duration_elapsed(&bench
), duration_kbps(&bench
, wrote
));
592 COMMAND_HANDLER(handle_flash_write_bank_command
)
596 struct fileio fileio
;
599 return ERROR_COMMAND_SYNTAX_ERROR
;
601 struct duration bench
;
602 duration_start(&bench
);
604 struct flash_bank
*p
;
605 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
606 if (ERROR_OK
!= retval
)
609 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], offset
);
611 if (fileio_open(&fileio
, CMD_ARGV
[1], FILEIO_READ
, FILEIO_BINARY
) != ERROR_OK
)
616 buffer
= malloc(fileio
.size
);
618 if (fileio_read(&fileio
, fileio
.size
, buffer
, &buf_cnt
) != ERROR_OK
)
621 fileio_close(&fileio
);
625 retval
= flash_driver_write(p
, buffer
, offset
, buf_cnt
);
630 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
632 command_print(CMD_CTX
, "wrote %ld bytes from file %s to flash bank %u"
633 " at offset 0x%8.8" PRIx32
" in %fs (%0.3f KiB/s)",
634 (long)fileio
.size
, CMD_ARGV
[1], p
->bank_number
, offset
,
635 duration_elapsed(&bench
), duration_kbps(&bench
, fileio
.size
));
638 fileio_close(&fileio
);
643 void flash_set_dirty(void)
645 struct flash_bank
*c
;
648 /* set all flash to require erasing */
649 for (c
= flash_bank_list(); c
; c
= c
->next
)
651 for (i
= 0; i
< c
->num_sectors
; i
++)
653 c
->sectors
[i
].is_erased
= 0;
658 static const struct command_registration flash_exec_command_handlers
[] = {
661 .handler
= handle_flash_probe_command
,
662 .mode
= COMMAND_EXEC
,
664 .help
= "Identify a flash bank.",
668 .handler
= handle_flash_info_command
,
669 .mode
= COMMAND_EXEC
,
671 .help
= "Print information about a flash bank.",
674 .name
= "erase_check",
675 .handler
= handle_flash_erase_check_command
,
676 .mode
= COMMAND_EXEC
,
678 .help
= "Check erase state of all blocks in a "
682 .name
= "erase_sector",
683 .handler
= handle_flash_erase_command
,
684 .mode
= COMMAND_EXEC
,
685 .usage
= "bank_id first_sector_num last_sector_num",
686 .help
= "Erase a range of sectors in a flash bank.",
689 .name
= "erase_address",
690 .handler
= handle_flash_erase_address_command
,
691 .mode
= COMMAND_EXEC
,
692 .usage
= "['pad'] ['unlock'] address length",
693 .help
= "Erase flash sectors starting at address and "
694 "continuing for length bytes. If 'pad' is specified, "
695 "data outside that range may also be erased: the start "
696 "address may be decreased, and length increased, so "
697 "that all of the first and last sectors are erased. "
698 "If 'unlock' is specified, then the flash is unprotected "
704 .handler
= handle_flash_fill_command
,
705 .mode
= COMMAND_EXEC
,
706 .usage
= "address value n",
707 .help
= "Fill n words with 32-bit value, starting at "
708 "word address. (No autoerase.)",
712 .handler
= handle_flash_fill_command
,
713 .mode
= COMMAND_EXEC
,
714 .usage
= "address value n",
715 .help
= "Fill n halfwords with 16-bit value, starting at "
716 "word address. (No autoerase.)",
720 .handler
= handle_flash_fill_command
,
721 .mode
= COMMAND_EXEC
,
722 .usage
= "address value n",
723 .help
= "Fill n bytes with 8-bit value, starting at "
724 "word address. (No autoerase.)",
727 .name
= "write_bank",
728 .handler
= handle_flash_write_bank_command
,
729 .mode
= COMMAND_EXEC
,
730 .usage
= "bank_id filename offset",
731 .help
= "Write binary data from file to flash bank, "
732 "starting at specified byte offset from the "
733 "beginning of the bank.",
736 .name
= "write_image",
737 .handler
= handle_flash_write_image_command
,
738 .mode
= COMMAND_EXEC
,
739 .usage
= "[erase] [unlock] filename [offset [file_type]]",
740 .help
= "Write an image to flash. Optionally first unprotect "
741 "and/or erase the region to be used. Allow optional "
742 "offset from beginning of bank (defaults to zero)",
746 .handler
= handle_flash_protect_command
,
747 .mode
= COMMAND_EXEC
,
748 .usage
= "bank_id first_sector [last_sector|'last'] "
750 .help
= "Turn protection on or off for a range of sectors "
751 "in a given flash bank.",
753 COMMAND_REGISTRATION_DONE
756 static int flash_init_drivers(struct command_context
*cmd_ctx
)
758 if (!flash_bank_list())
761 struct command
*parent
= command_find_in_context(cmd_ctx
, "flash");
762 return register_commands(cmd_ctx
, parent
, flash_exec_command_handlers
);
766 COMMAND_HANDLER(handle_flash_bank_command
)
770 LOG_ERROR("usage: flash bank <name> <driver> "
771 "<base> <size> <chip_width> <bus_width> <target>");
772 return ERROR_COMMAND_SYNTAX_ERROR
;
774 // save bank name and advance arguments for compatibility
775 const char *bank_name
= *CMD_ARGV
++;
778 struct target
*target
;
779 if ((target
= get_target(CMD_ARGV
[5])) == NULL
)
781 LOG_ERROR("target '%s' not defined", CMD_ARGV
[5]);
785 const char *driver_name
= CMD_ARGV
[0];
786 struct flash_driver
*driver
= flash_driver_find_by_name(driver_name
);
789 /* no matching flash driver found */
790 LOG_ERROR("flash driver '%s' not found", driver_name
);
794 /* check the flash bank name is unique */
795 if (get_flash_bank_by_name_noprobe(bank_name
) != NULL
)
797 /* flash bank name already exists */
798 LOG_ERROR("flash bank name '%s' already exists", bank_name
);
802 /* register flash specific commands */
803 if (NULL
!= driver
->commands
)
805 int retval
= register_commands(CMD_CTX
, NULL
,
807 if (ERROR_OK
!= retval
)
809 LOG_ERROR("couldn't register '%s' commands",
815 struct flash_bank
*c
= malloc(sizeof(*c
));
816 c
->name
= strdup(bank_name
);
819 c
->driver_priv
= NULL
;
820 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], c
->base
);
821 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], c
->size
);
822 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], c
->chip_width
);
823 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[4], c
->bus_width
);
829 retval
= CALL_COMMAND_HANDLER(driver
->flash_bank_command
, c
);
830 if (ERROR_OK
!= retval
)
832 LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32
,
833 driver_name
, c
->base
);
843 COMMAND_HANDLER(handle_flash_banks_command
)
846 return ERROR_INVALID_ARGUMENTS
;
849 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
, n
++)
851 LOG_USER("#%" PRIu32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", "
852 "buswidth %u, chipwidth %u", p
->bank_number
,
853 p
->driver
->name
, p
->base
, p
->size
,
854 p
->bus_width
, p
->chip_width
);
859 static int jim_flash_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
863 Jim_WrongNumArgs(interp
, 1, argv
,
864 "no arguments to 'flash list' command");
868 Jim_Obj
*list
= Jim_NewListObj(interp
, NULL
, 0);
870 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
)
872 Jim_Obj
*elem
= Jim_NewListObj(interp
, NULL
, 0);
874 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "name", -1));
875 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, p
->driver
->name
, -1));
876 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "base", -1));
877 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->base
));
878 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "size", -1));
879 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->size
));
880 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "bus_width", -1));
881 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->bus_width
));
882 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "chip_width", -1));
883 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->chip_width
));
885 Jim_ListAppendElement(interp
, list
, elem
);
888 Jim_SetResult(interp
, list
);
894 COMMAND_HANDLER(handle_flash_init_command
)
897 return ERROR_COMMAND_SYNTAX_ERROR
;
899 static bool flash_initialized
= false;
900 if (flash_initialized
)
902 LOG_INFO("'flash init' has already been called");
905 flash_initialized
= true;
907 LOG_DEBUG("Initializing flash devices...");
908 return flash_init_drivers(CMD_CTX
);
911 static const struct command_registration flash_config_command_handlers
[] = {
914 .handler
= handle_flash_bank_command
,
915 .mode
= COMMAND_CONFIG
,
916 .usage
= "bank_id driver_name base_address size_bytes "
917 "chip_width_bytes bus_width_bytes target "
918 "[driver_options ...]",
919 .help
= "Define a new bank with the given name, "
920 "using the specified NOR flash driver.",
924 .mode
= COMMAND_CONFIG
,
925 .handler
= handle_flash_init_command
,
926 .help
= "Initialize flash devices.",
931 .handler
= handle_flash_banks_command
,
932 .help
= "Display table with information about flash banks.",
937 .jim_handler
= jim_flash_list
,
938 .help
= "Returns a list of details about the flash banks.",
940 COMMAND_REGISTRATION_DONE
942 static const struct command_registration flash_command_handlers
[] = {
946 .help
= "NOR flash command group",
947 .chain
= flash_config_command_handlers
,
949 COMMAND_REGISTRATION_DONE
952 int flash_register_commands(struct command_context
*cmd_ctx
)
954 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)