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 *bank
= get_flash_bank_by_name(name
);
43 COMMAND_PARSE_NUMBER(uint
, name
, bank_num
);
45 *bank
= get_flash_bank_by_num(bank_num
);
48 command_print(CMD_CTX
, "flash bank '%s' not found", name
);
49 return ERROR_INVALID_ARGUMENTS
;
55 COMMAND_HANDLER(handle_flash_info_command
)
63 return ERROR_COMMAND_SYNTAX_ERROR
;
66 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
68 for (p
= flash_bank_list(); p
; p
= p
->next
, i
++)
75 /* attempt auto probe */
76 if ((retval
= p
->driver
->auto_probe(p
)) != ERROR_OK
)
79 command_print(CMD_CTX
,
80 "#%" PRIi32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", buswidth %i, chipwidth %i",
87 for (j
= 0; j
< p
->num_sectors
; j
++)
91 if (p
->sectors
[j
].is_protected
== 0)
92 protect_state
= "not protected";
93 else if (p
->sectors
[j
].is_protected
== 1)
94 protect_state
= "protected";
96 protect_state
= "protection state unknown";
98 command_print(CMD_CTX
,
99 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
101 p
->sectors
[j
].offset
,
103 p
->sectors
[j
].size
>> 10,
107 *buf
= '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
108 retval
= p
->driver
->info(p
, buf
, sizeof(buf
));
109 command_print(CMD_CTX
, "%s", buf
);
110 if (retval
!= ERROR_OK
)
111 LOG_ERROR("error retrieving flash info (%d)", retval
);
117 COMMAND_HANDLER(handle_flash_probe_command
)
123 return ERROR_COMMAND_SYNTAX_ERROR
;
127 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
128 struct flash_bank
*p
= get_flash_bank_by_num_noprobe(bank_nr
);
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
;
207 struct target
*target
= get_current_target(CMD_CTX
);
210 return ERROR_COMMAND_SYNTAX_ERROR
;
212 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], address
);
213 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], length
);
216 command_print(CMD_CTX
, "Length must be >0");
217 return ERROR_COMMAND_SYNTAX_ERROR
;
220 p
= get_flash_bank_by_addr(target
, address
);
226 /* We can't know if we did a resume + halt, in which case we no longer know the erased state */
229 struct duration bench
;
230 duration_start(&bench
);
232 retval
= flash_erase_address_range(target
, address
, length
);
234 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
236 command_print(CMD_CTX
, "erased address 0x%8.8x (length %i)"
237 " in %fs (%0.3f kb/s)", address
, length
,
238 duration_elapsed(&bench
), duration_kbps(&bench
, length
));
244 COMMAND_HANDLER(handle_flash_protect_check_command
)
247 return ERROR_COMMAND_SYNTAX_ERROR
;
249 struct flash_bank
*p
;
250 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
251 if (ERROR_OK
!= retval
)
254 if ((retval
= p
->driver
->protect_check(p
)) == ERROR_OK
)
256 command_print(CMD_CTX
, "successfully checked protect state");
258 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
260 command_print(CMD_CTX
, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8" PRIx32
, CMD_ARGV
[0], p
->base
);
264 command_print(CMD_CTX
, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8" PRIx32
, CMD_ARGV
[0], p
->base
);
270 static int flash_check_sector_parameters(struct command_context
*cmd_ctx
,
271 uint32_t first
, uint32_t last
, uint32_t num_sectors
)
273 if (!(first
<= last
)) {
274 command_print(cmd_ctx
, "ERROR: "
275 "first sector must be <= last sector");
279 if (!(last
<= (num_sectors
- 1))) {
280 command_print(cmd_ctx
, "ERROR: last sector must be <= %d",
281 (int) num_sectors
- 1);
288 COMMAND_HANDLER(handle_flash_erase_command
)
291 return ERROR_COMMAND_SYNTAX_ERROR
;
297 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
298 struct flash_bank
*p
= get_flash_bank_by_num(bank_nr
);
302 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
303 if (strcmp(CMD_ARGV
[2], "last") == 0)
304 last
= p
->num_sectors
- 1;
306 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
309 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
310 first
, last
, p
->num_sectors
)) != ERROR_OK
)
313 struct duration bench
;
314 duration_start(&bench
);
316 retval
= flash_driver_erase(p
, first
, last
);
318 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
320 command_print(CMD_CTX
, "erased sectors %" PRIu32
" "
321 "through %" PRIu32
" on flash bank %" PRIu32
" "
322 "in %fs", first
, last
, bank_nr
, duration_elapsed(&bench
));
328 COMMAND_HANDLER(handle_flash_protect_command
)
331 return ERROR_COMMAND_SYNTAX_ERROR
;
337 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
338 struct flash_bank
*p
= get_flash_bank_by_num(bank_nr
);
342 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
343 if (strcmp(CMD_ARGV
[2], "last") == 0)
344 last
= p
->num_sectors
- 1;
346 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
349 COMMAND_PARSE_ON_OFF(CMD_ARGV
[3], set
);
352 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
353 first
, last
, p
->num_sectors
)) != ERROR_OK
)
356 retval
= flash_driver_protect(p
, set
, first
, last
);
357 if (retval
== ERROR_OK
) {
358 command_print(CMD_CTX
, "%s protection for sectors %i "
359 "through %i on flash bank %i",
360 (set
) ? "set" : "cleared", (int) first
,
361 (int) last
, (int) bank_nr
);
367 COMMAND_HANDLER(handle_flash_write_image_command
)
369 struct target
*target
= get_current_target(CMD_CTX
);
378 return ERROR_COMMAND_SYNTAX_ERROR
;
381 /* flash auto-erase is disabled by default*/
383 bool auto_unlock
= false;
387 if (strcmp(CMD_ARGV
[0], "erase") == 0)
392 command_print(CMD_CTX
, "auto erase enabled");
393 } else if (strcmp(CMD_ARGV
[0], "unlock") == 0)
398 command_print(CMD_CTX
, "auto unlock enabled");
407 return ERROR_COMMAND_SYNTAX_ERROR
;
412 LOG_ERROR("no target selected");
416 struct duration bench
;
417 duration_start(&bench
);
421 image
.base_address_set
= 1;
422 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], image
.base_address
);
426 image
.base_address_set
= 0;
427 image
.base_address
= 0x0;
430 image
.start_address_set
= 0;
432 retval
= image_open(&image
, CMD_ARGV
[0], (CMD_ARGC
== 3) ? CMD_ARGV
[2] : NULL
);
433 if (retval
!= ERROR_OK
)
438 retval
= flash_write_unlock(target
, &image
, &written
, auto_erase
, auto_unlock
);
439 if (retval
!= ERROR_OK
)
445 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
447 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes from file %s "
448 "in %fs (%0.3f kb/s)", written
, CMD_ARGV
[0],
449 duration_elapsed(&bench
), duration_kbps(&bench
, written
));
457 COMMAND_HANDLER(handle_flash_fill_command
)
464 uint32_t cur_size
= 0;
465 uint32_t chunk_count
;
466 struct target
*target
= get_current_target(CMD_CTX
);
469 int retval
= ERROR_OK
;
471 static size_t const chunksize
= 1024;
472 uint8_t *chunk
= malloc(chunksize
);
476 uint8_t *readback
= malloc(chunksize
);
477 if (readback
== NULL
)
486 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
491 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
492 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], pattern
);
493 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], count
);
510 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
514 chunk_count
= MIN(count
, (chunksize
/ wordsize
));
518 for (i
= 0; i
< chunk_count
; i
++)
520 target_buffer_set_u32(target
, chunk
+ i
* wordsize
, pattern
);
524 for (i
= 0; i
< chunk_count
; i
++)
526 target_buffer_set_u16(target
, chunk
+ i
* wordsize
, pattern
);
530 memset(chunk
, pattern
, chunk_count
);
533 LOG_ERROR("BUG: can't happen");
537 struct duration bench
;
538 duration_start(&bench
);
540 for (wrote
= 0; wrote
< (count
*wordsize
); wrote
+= cur_size
)
542 struct flash_bank
*bank
;
544 bank
= get_flash_bank_by_addr(target
, address
);
551 cur_size
= MIN((count
* wordsize
- wrote
), chunksize
);
552 err
= flash_driver_write(bank
, chunk
, address
- bank
->base
+ wrote
, cur_size
);
559 err
= target_read_buffer(target
, address
+ wrote
, cur_size
, readback
);
567 for (i
= 0; i
< cur_size
; i
++)
569 if (readback
[i
]!=chunk
[i
])
571 LOG_ERROR("Verfication error address 0x%08" PRIx32
", read back 0x%02x, expected 0x%02x",
572 address
+ wrote
+ i
, readback
[i
], chunk
[i
]);
579 if (duration_measure(&bench
) == ERROR_OK
)
581 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes to 0x%8.8" PRIx32
582 " in %fs (%0.3f kb/s)", wrote
, address
,
583 duration_elapsed(&bench
), duration_kbps(&bench
, wrote
));
593 COMMAND_HANDLER(handle_flash_write_bank_command
)
597 struct fileio fileio
;
600 return ERROR_COMMAND_SYNTAX_ERROR
;
602 struct duration bench
;
603 duration_start(&bench
);
605 struct flash_bank
*p
;
606 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
607 if (ERROR_OK
!= retval
)
610 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], offset
);
612 if (fileio_open(&fileio
, CMD_ARGV
[1], FILEIO_READ
, FILEIO_BINARY
) != ERROR_OK
)
617 buffer
= malloc(fileio
.size
);
619 if (fileio_read(&fileio
, fileio
.size
, buffer
, &buf_cnt
) != ERROR_OK
)
622 fileio_close(&fileio
);
626 retval
= flash_driver_write(p
, buffer
, offset
, buf_cnt
);
631 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
633 command_print(CMD_CTX
, "wrote %ld bytes from file %s to flash bank %u"
634 " at offset 0x%8.8" PRIx32
" in %fs (%0.3f kb/s)",
635 (long)fileio
.size
, CMD_ARGV
[1], p
->bank_number
, offset
,
636 duration_elapsed(&bench
), duration_kbps(&bench
, fileio
.size
));
639 fileio_close(&fileio
);
644 void flash_set_dirty(void)
646 struct flash_bank
*c
;
649 /* set all flash to require erasing */
650 for (c
= flash_bank_list(); c
; c
= c
->next
)
652 for (i
= 0; i
< c
->num_sectors
; i
++)
654 c
->sectors
[i
].is_erased
= 0;
659 static const struct command_registration flash_exec_command_handlers
[] = {
662 .handler
= handle_flash_probe_command
,
663 .mode
= COMMAND_EXEC
,
665 .help
= "Identify a flash bank.",
669 .handler
= handle_flash_info_command
,
670 .mode
= COMMAND_EXEC
,
672 .help
= "Print information about a flash bank.",
675 .name
= "erase_check",
676 .handler
= handle_flash_erase_check_command
,
677 .mode
= COMMAND_EXEC
,
679 .help
= "Check erase state of all blocks in a "
683 .name
= "protect_check",
684 .handler
= handle_flash_protect_check_command
,
685 .mode
= COMMAND_EXEC
,
687 .help
= "Check protection state of all blocks in a "
691 .name
= "erase_sector",
692 .handler
= handle_flash_erase_command
,
693 .mode
= COMMAND_EXEC
,
694 .usage
= "bank_id first_sector_num last_sector_num",
695 .help
= "Erase a range of sectors in a flash bank.",
698 .name
= "erase_address",
699 .handler
= handle_flash_erase_address_command
,
700 .mode
= COMMAND_EXEC
,
701 .usage
= "address length",
702 .help
= "Erase flash blocks starting at address "
703 "and continuing for length bytes.",
707 .handler
= handle_flash_fill_command
,
708 .mode
= COMMAND_EXEC
,
709 .usage
= "address value n",
710 .help
= "Fill n words with 32-bit value, starting at "
711 "word address. (No autoerase.)",
715 .handler
= handle_flash_fill_command
,
716 .mode
= COMMAND_EXEC
,
717 .usage
= "address value n",
718 .help
= "Fill n halfwords with 16-bit value, starting at "
719 "word address. (No autoerase.)",
723 .handler
= handle_flash_fill_command
,
724 .mode
= COMMAND_EXEC
,
725 .usage
= "address value n",
726 .help
= "Fill n bytes with 8-bit value, starting at "
727 "word address. (No autoerase.)",
730 .name
= "write_bank",
731 .handler
= handle_flash_write_bank_command
,
732 .mode
= COMMAND_EXEC
,
733 .usage
= "bank_id filename offset",
734 .help
= "Write binary data from file to flash bank, "
735 "starting at specified byte offset from the "
736 "beginning of the bank.",
739 .name
= "write_image",
740 .handler
= handle_flash_write_image_command
,
741 .mode
= COMMAND_EXEC
,
742 .usage
= "[erase] [unlock] filename [offset [file_type]]",
743 .help
= "Write an image to flash. Optionally first unprotect "
744 "and/or erase the region to be used. Allow optional "
745 "offset from beginning of bank (defaults to zero)",
749 .handler
= handle_flash_protect_command
,
750 .mode
= COMMAND_EXEC
,
751 .usage
= "bank_id first_sector [last_sector|'last'] "
753 .help
= "Turn protection on or off for a range of sectors "
754 "in a given flash bank.",
756 COMMAND_REGISTRATION_DONE
759 int flash_init_drivers(struct command_context
*cmd_ctx
)
761 if (!flash_bank_list())
764 struct command
*parent
= command_find_in_context(cmd_ctx
, "flash");
765 return register_commands(cmd_ctx
, parent
, flash_exec_command_handlers
);
769 COMMAND_HANDLER(handle_flash_bank_command
)
773 LOG_ERROR("usage: flash bank <name> <driver> "
774 "<base> <size> <chip_width> <bus_width>");
775 return ERROR_COMMAND_SYNTAX_ERROR
;
777 // save bank name and advance arguments for compatibility
778 const char *bank_name
= *CMD_ARGV
++;
781 struct target
*target
;
782 if ((target
= get_target(CMD_ARGV
[5])) == NULL
)
784 LOG_ERROR("target '%s' not defined", CMD_ARGV
[5]);
788 const char *driver_name
= CMD_ARGV
[0];
789 struct flash_driver
*driver
= flash_driver_find_by_name(driver_name
);
792 /* no matching flash driver found */
793 LOG_ERROR("flash driver '%s' not found", driver_name
);
797 /* register flash specific commands */
798 if (NULL
!= driver
->commands
)
800 int retval
= register_commands(CMD_CTX
, NULL
,
802 if (ERROR_OK
!= retval
)
804 LOG_ERROR("couldn't register '%s' commands",
810 struct flash_bank
*c
= malloc(sizeof(*c
));
811 c
->name
= strdup(bank_name
);
814 c
->driver_priv
= NULL
;
815 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], c
->base
);
816 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], c
->size
);
817 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], c
->chip_width
);
818 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[4], c
->bus_width
);
824 retval
= CALL_COMMAND_HANDLER(driver
->flash_bank_command
, c
);
825 if (ERROR_OK
!= retval
)
827 LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32
,
828 driver_name
, c
->base
);
838 COMMAND_HANDLER(handle_flash_banks_command
)
841 return ERROR_INVALID_ARGUMENTS
;
844 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
, n
++)
846 LOG_USER("#%u: %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", "
847 "buswidth %u, chipwidth %u", n
,
848 p
->driver
->name
, p
->base
, p
->size
,
849 p
->bus_width
, p
->chip_width
);
854 static int jim_flash_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
858 Jim_WrongNumArgs(interp
, 1, argv
,
859 "no arguments to 'flash list' command");
863 Jim_Obj
*list
= Jim_NewListObj(interp
, NULL
, 0);
865 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
)
867 Jim_Obj
*elem
= Jim_NewListObj(interp
, NULL
, 0);
869 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "name", -1));
870 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, p
->driver
->name
, -1));
871 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "base", -1));
872 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->base
));
873 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "size", -1));
874 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->size
));
875 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "bus_width", -1));
876 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->bus_width
));
877 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "chip_width", -1));
878 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->chip_width
));
880 Jim_ListAppendElement(interp
, list
, elem
);
883 Jim_SetResult(interp
, list
);
889 COMMAND_HANDLER(handle_flash_init_command
)
892 return ERROR_COMMAND_SYNTAX_ERROR
;
894 static bool flash_initialized
= false;
895 if (flash_initialized
)
897 LOG_INFO("'flash init' has already been called");
900 flash_initialized
= true;
902 LOG_DEBUG("Initializing flash devices...");
903 return flash_init_drivers(CMD_CTX
);
906 static const struct command_registration flash_config_command_handlers
[] = {
909 .handler
= &handle_flash_bank_command
,
910 .mode
= COMMAND_CONFIG
,
911 .usage
= "bank_id driver_name base_address size_bytes "
912 "chip_width_bytes bus_width_bytes target "
913 "[driver_options ...]",
914 .help
= "Define a new bank with the given name, "
915 "using the specified NOR flash driver.",
919 .mode
= COMMAND_CONFIG
,
920 .handler
= &handle_flash_init_command
,
921 .help
= "Initialize flash devices.",
926 .handler
= &handle_flash_banks_command
,
927 .help
= "Display table with information about flash banks.",
932 .jim_handler
= &jim_flash_list
,
933 .help
= "Returns a list of details about the flash banks.",
935 COMMAND_REGISTRATION_DONE
937 static const struct command_registration flash_command_handlers
[] = {
941 .help
= "NOR flash command group",
942 .chain
= flash_config_command_handlers
,
944 COMMAND_REGISTRATION_DONE
947 int flash_register_commands(struct command_context
*cmd_ctx
)
949 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)