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 return get_flash_bank_by_num(bank_num
, bank
);
49 COMMAND_HANDLER(handle_flash_info_command
)
57 return ERROR_COMMAND_SYNTAX_ERROR
;
60 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
62 for (p
= flash_bank_list(); p
; p
= p
->next
, i
++)
69 /* attempt auto probe */
70 if ((retval
= p
->driver
->auto_probe(p
)) != ERROR_OK
)
73 /* We must query the hardware to avoid printing stale information! */
74 retval
= p
->driver
->protect_check(p
);
75 if (retval
!= ERROR_OK
)
78 command_print(CMD_CTX
,
79 "#%" PRIi32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", buswidth %i, chipwidth %i",
86 for (j
= 0; j
< p
->num_sectors
; j
++)
90 if (p
->sectors
[j
].is_protected
== 0)
91 protect_state
= "not protected";
92 else if (p
->sectors
[j
].is_protected
== 1)
93 protect_state
= "protected";
95 protect_state
= "protection state unknown";
97 command_print(CMD_CTX
,
98 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
100 p
->sectors
[j
].offset
,
102 p
->sectors
[j
].size
>> 10,
106 *buf
= '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
107 retval
= p
->driver
->info(p
, buf
, sizeof(buf
));
108 command_print(CMD_CTX
, "%s", buf
);
109 if (retval
!= ERROR_OK
)
110 LOG_ERROR("error retrieving flash info (%d)", retval
);
116 COMMAND_HANDLER(handle_flash_probe_command
)
122 return ERROR_COMMAND_SYNTAX_ERROR
;
126 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
127 struct flash_bank
*p
= get_flash_bank_by_num_noprobe(bank_nr
);
130 if ((retval
= p
->driver
->probe(p
)) == ERROR_OK
)
132 command_print(CMD_CTX
, "flash '%s' found at 0x%8.8" PRIx32
, p
->driver
->name
, p
->base
);
134 else if (retval
== ERROR_FLASH_BANK_INVALID
)
136 command_print(CMD_CTX
, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32
,
137 CMD_ARGV
[0], p
->base
);
141 command_print(CMD_CTX
, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32
,
142 CMD_ARGV
[0], p
->base
);
147 command_print(CMD_CTX
, "flash bank '#%s' is out of bounds", CMD_ARGV
[0]);
153 COMMAND_HANDLER(handle_flash_erase_check_command
)
157 return ERROR_COMMAND_SYNTAX_ERROR
;
160 struct flash_bank
*p
;
161 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
162 if (ERROR_OK
!= retval
)
166 if ((retval
= p
->driver
->erase_check(p
)) == ERROR_OK
)
168 command_print(CMD_CTX
, "successfully checked erase state");
172 command_print(CMD_CTX
, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32
,
173 CMD_ARGV
[0], p
->base
);
176 for (j
= 0; j
< p
->num_sectors
; j
++)
180 if (p
->sectors
[j
].is_erased
== 0)
181 erase_state
= "not erased";
182 else if (p
->sectors
[j
].is_erased
== 1)
183 erase_state
= "erased";
185 erase_state
= "erase state unknown";
187 command_print(CMD_CTX
,
188 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
190 p
->sectors
[j
].offset
,
192 p
->sectors
[j
].size
>> 10,
199 COMMAND_HANDLER(handle_flash_erase_address_command
)
201 struct flash_bank
*p
;
202 int retval
= ERROR_OK
;
206 bool do_unlock
= false;
207 struct target
*target
= get_current_target(CMD_CTX
);
209 while (CMD_ARGC
>= 3)
211 /* Optionally pad out the address range to block/sector
212 * boundaries. We can't know if there's data in that part
213 * of the flash; only do padding if we're told to.
215 if (strcmp("pad", CMD_ARGV
[0]) == 0)
218 } else if (strcmp("unlock", CMD_ARGV
[0]) == 0)
223 return ERROR_COMMAND_SYNTAX_ERROR
;
230 return ERROR_COMMAND_SYNTAX_ERROR
;
233 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], address
);
234 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], length
);
238 command_print(CMD_CTX
, "Length must be >0");
239 return ERROR_COMMAND_SYNTAX_ERROR
;
242 p
= get_flash_bank_by_addr(target
, address
);
248 /* We can't know if we did a resume + halt, in which case we no longer know the erased state */
251 struct duration bench
;
252 duration_start(&bench
);
256 retval
= flash_unlock_address_range(target
, address
, length
);
259 if (retval
== ERROR_OK
)
261 retval
= flash_erase_address_range(target
, do_pad
, address
, length
);
264 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
266 command_print(CMD_CTX
, "erased address 0x%8.8x (length %i)"
267 " in %fs (%0.3f kb/s)", address
, length
,
268 duration_elapsed(&bench
), duration_kbps(&bench
, length
));
274 static int flash_check_sector_parameters(struct command_context
*cmd_ctx
,
275 uint32_t first
, uint32_t last
, uint32_t num_sectors
)
277 if (!(first
<= last
)) {
278 command_print(cmd_ctx
, "ERROR: "
279 "first sector must be <= last sector");
283 if (!(last
<= (num_sectors
- 1))) {
284 command_print(cmd_ctx
, "ERROR: last sector must be <= %d",
285 (int) num_sectors
- 1);
292 COMMAND_HANDLER(handle_flash_erase_command
)
295 return ERROR_COMMAND_SYNTAX_ERROR
;
301 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
303 struct flash_bank
*p
;
305 retval
= get_flash_bank_by_num(bank_nr
, &p
);
306 if (retval
!= ERROR_OK
)
309 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
310 if (strcmp(CMD_ARGV
[2], "last") == 0)
311 last
= p
->num_sectors
- 1;
313 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
315 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
316 first
, last
, p
->num_sectors
)) != ERROR_OK
)
319 struct duration bench
;
320 duration_start(&bench
);
322 retval
= flash_driver_erase(p
, first
, last
);
324 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
326 command_print(CMD_CTX
, "erased sectors %" PRIu32
" "
327 "through %" PRIu32
" on flash bank %" PRIu32
" "
328 "in %fs", first
, last
, bank_nr
, duration_elapsed(&bench
));
334 COMMAND_HANDLER(handle_flash_protect_command
)
337 return ERROR_COMMAND_SYNTAX_ERROR
;
343 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
344 struct flash_bank
*p
;
345 int retval
= get_flash_bank_by_num(bank_nr
, &p
);
346 if (retval
!= ERROR_OK
)
349 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
350 if (strcmp(CMD_ARGV
[2], "last") == 0)
351 last
= p
->num_sectors
- 1;
353 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
356 COMMAND_PARSE_ON_OFF(CMD_ARGV
[3], set
);
358 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
359 first
, last
, p
->num_sectors
)) != ERROR_OK
)
362 retval
= flash_driver_protect(p
, set
, first
, last
);
363 if (retval
== ERROR_OK
) {
364 command_print(CMD_CTX
, "%s protection for sectors %i "
365 "through %i on flash bank %i",
366 (set
) ? "set" : "cleared", (int) first
,
367 (int) last
, (int) bank_nr
);
373 COMMAND_HANDLER(handle_flash_write_image_command
)
375 struct target
*target
= get_current_target(CMD_CTX
);
384 return ERROR_COMMAND_SYNTAX_ERROR
;
387 /* flash auto-erase is disabled by default*/
389 bool auto_unlock
= false;
393 if (strcmp(CMD_ARGV
[0], "erase") == 0)
398 command_print(CMD_CTX
, "auto erase enabled");
399 } else if (strcmp(CMD_ARGV
[0], "unlock") == 0)
404 command_print(CMD_CTX
, "auto unlock enabled");
413 return ERROR_COMMAND_SYNTAX_ERROR
;
418 LOG_ERROR("no target selected");
422 struct duration bench
;
423 duration_start(&bench
);
427 image
.base_address_set
= 1;
428 COMMAND_PARSE_NUMBER(llong
, CMD_ARGV
[1], image
.base_address
);
432 image
.base_address_set
= 0;
433 image
.base_address
= 0x0;
436 image
.start_address_set
= 0;
438 retval
= image_open(&image
, CMD_ARGV
[0], (CMD_ARGC
== 3) ? CMD_ARGV
[2] : NULL
);
439 if (retval
!= ERROR_OK
)
444 retval
= flash_write_unlock(target
, &image
, &written
, auto_erase
, auto_unlock
);
445 if (retval
!= ERROR_OK
)
451 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
453 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes from file %s "
454 "in %fs (%0.3f kb/s)", written
, CMD_ARGV
[0],
455 duration_elapsed(&bench
), duration_kbps(&bench
, written
));
463 COMMAND_HANDLER(handle_flash_fill_command
)
470 uint32_t cur_size
= 0;
471 uint32_t chunk_count
;
472 struct target
*target
= get_current_target(CMD_CTX
);
475 int retval
= ERROR_OK
;
477 static size_t const chunksize
= 1024;
478 uint8_t *chunk
= malloc(chunksize
);
482 uint8_t *readback
= malloc(chunksize
);
483 if (readback
== NULL
)
492 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
497 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
498 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], pattern
);
499 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], count
);
516 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
520 chunk_count
= MIN(count
, (chunksize
/ wordsize
));
524 for (i
= 0; i
< chunk_count
; i
++)
526 target_buffer_set_u32(target
, chunk
+ i
* wordsize
, pattern
);
530 for (i
= 0; i
< chunk_count
; i
++)
532 target_buffer_set_u16(target
, chunk
+ i
* wordsize
, pattern
);
536 memset(chunk
, pattern
, chunk_count
);
539 LOG_ERROR("BUG: can't happen");
543 struct duration bench
;
544 duration_start(&bench
);
546 for (wrote
= 0; wrote
< (count
*wordsize
); wrote
+= cur_size
)
548 struct flash_bank
*bank
;
550 bank
= get_flash_bank_by_addr(target
, address
);
557 cur_size
= MIN((count
* wordsize
- wrote
), chunksize
);
558 err
= flash_driver_write(bank
, chunk
, address
- bank
->base
+ wrote
, cur_size
);
565 err
= target_read_buffer(target
, address
+ wrote
, cur_size
, readback
);
573 for (i
= 0; i
< cur_size
; i
++)
575 if (readback
[i
]!=chunk
[i
])
577 LOG_ERROR("Verfication error address 0x%08" PRIx32
", read back 0x%02x, expected 0x%02x",
578 address
+ wrote
+ i
, readback
[i
], chunk
[i
]);
585 if (duration_measure(&bench
) == ERROR_OK
)
587 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes to 0x%8.8" PRIx32
588 " in %fs (%0.3f kb/s)", wrote
, address
,
589 duration_elapsed(&bench
), duration_kbps(&bench
, wrote
));
599 COMMAND_HANDLER(handle_flash_write_bank_command
)
603 struct fileio fileio
;
606 return ERROR_COMMAND_SYNTAX_ERROR
;
608 struct duration bench
;
609 duration_start(&bench
);
611 struct flash_bank
*p
;
612 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
613 if (ERROR_OK
!= retval
)
616 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], offset
);
618 if (fileio_open(&fileio
, CMD_ARGV
[1], FILEIO_READ
, FILEIO_BINARY
) != ERROR_OK
)
623 buffer
= malloc(fileio
.size
);
625 if (fileio_read(&fileio
, fileio
.size
, buffer
, &buf_cnt
) != ERROR_OK
)
628 fileio_close(&fileio
);
632 retval
= flash_driver_write(p
, buffer
, offset
, buf_cnt
);
637 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
639 command_print(CMD_CTX
, "wrote %ld bytes from file %s to flash bank %u"
640 " at offset 0x%8.8" PRIx32
" in %fs (%0.3f kb/s)",
641 (long)fileio
.size
, CMD_ARGV
[1], p
->bank_number
, offset
,
642 duration_elapsed(&bench
), duration_kbps(&bench
, fileio
.size
));
645 fileio_close(&fileio
);
650 void flash_set_dirty(void)
652 struct flash_bank
*c
;
655 /* set all flash to require erasing */
656 for (c
= flash_bank_list(); c
; c
= c
->next
)
658 for (i
= 0; i
< c
->num_sectors
; i
++)
660 c
->sectors
[i
].is_erased
= 0;
665 static const struct command_registration flash_exec_command_handlers
[] = {
668 .handler
= handle_flash_probe_command
,
669 .mode
= COMMAND_EXEC
,
671 .help
= "Identify a flash bank.",
675 .handler
= handle_flash_info_command
,
676 .mode
= COMMAND_EXEC
,
678 .help
= "Print information about a flash bank.",
681 .name
= "erase_check",
682 .handler
= handle_flash_erase_check_command
,
683 .mode
= COMMAND_EXEC
,
685 .help
= "Check erase state of all blocks in a "
689 .name
= "erase_sector",
690 .handler
= handle_flash_erase_command
,
691 .mode
= COMMAND_EXEC
,
692 .usage
= "bank_id first_sector_num last_sector_num",
693 .help
= "Erase a range of sectors in a flash bank.",
696 .name
= "erase_address",
697 .handler
= handle_flash_erase_address_command
,
698 .mode
= COMMAND_EXEC
,
699 .usage
= "['pad'] ['unlock'] address length",
700 .help
= "Erase flash sectors starting at address and "
701 "continuing for length bytes. If 'pad' is specified, "
702 "data outside that range may also be erased: the start "
703 "address may be decreased, and length increased, so "
704 "that all of the first and last sectors are erased. "
705 "If 'unlock' is specified, then the flash is unprotected "
711 .handler
= handle_flash_fill_command
,
712 .mode
= COMMAND_EXEC
,
713 .usage
= "address value n",
714 .help
= "Fill n words with 32-bit value, starting at "
715 "word address. (No autoerase.)",
719 .handler
= handle_flash_fill_command
,
720 .mode
= COMMAND_EXEC
,
721 .usage
= "address value n",
722 .help
= "Fill n halfwords with 16-bit value, starting at "
723 "word address. (No autoerase.)",
727 .handler
= handle_flash_fill_command
,
728 .mode
= COMMAND_EXEC
,
729 .usage
= "address value n",
730 .help
= "Fill n bytes with 8-bit value, starting at "
731 "word address. (No autoerase.)",
734 .name
= "write_bank",
735 .handler
= handle_flash_write_bank_command
,
736 .mode
= COMMAND_EXEC
,
737 .usage
= "bank_id filename offset",
738 .help
= "Write binary data from file to flash bank, "
739 "starting at specified byte offset from the "
740 "beginning of the bank.",
743 .name
= "write_image",
744 .handler
= handle_flash_write_image_command
,
745 .mode
= COMMAND_EXEC
,
746 .usage
= "[erase] [unlock] filename [offset [file_type]]",
747 .help
= "Write an image to flash. Optionally first unprotect "
748 "and/or erase the region to be used. Allow optional "
749 "offset from beginning of bank (defaults to zero)",
753 .handler
= handle_flash_protect_command
,
754 .mode
= COMMAND_EXEC
,
755 .usage
= "bank_id first_sector [last_sector|'last'] "
757 .help
= "Turn protection on or off for a range of sectors "
758 "in a given flash bank.",
760 COMMAND_REGISTRATION_DONE
763 static int flash_init_drivers(struct command_context
*cmd_ctx
)
765 if (!flash_bank_list())
768 struct command
*parent
= command_find_in_context(cmd_ctx
, "flash");
769 return register_commands(cmd_ctx
, parent
, flash_exec_command_handlers
);
773 COMMAND_HANDLER(handle_flash_bank_command
)
777 LOG_ERROR("usage: flash bank <name> <driver> "
778 "<base> <size> <chip_width> <bus_width> <target>");
779 return ERROR_COMMAND_SYNTAX_ERROR
;
781 // save bank name and advance arguments for compatibility
782 const char *bank_name
= *CMD_ARGV
++;
785 struct target
*target
;
786 if ((target
= get_target(CMD_ARGV
[5])) == NULL
)
788 LOG_ERROR("target '%s' not defined", CMD_ARGV
[5]);
792 const char *driver_name
= CMD_ARGV
[0];
793 struct flash_driver
*driver
= flash_driver_find_by_name(driver_name
);
796 /* no matching flash driver found */
797 LOG_ERROR("flash driver '%s' not found", driver_name
);
801 /* register flash specific commands */
802 if (NULL
!= driver
->commands
)
804 int retval
= register_commands(CMD_CTX
, NULL
,
806 if (ERROR_OK
!= retval
)
808 LOG_ERROR("couldn't register '%s' commands",
814 struct flash_bank
*c
= malloc(sizeof(*c
));
815 c
->name
= strdup(bank_name
);
818 c
->driver_priv
= NULL
;
819 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], c
->base
);
820 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], c
->size
);
821 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], c
->chip_width
);
822 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[4], c
->bus_width
);
828 retval
= CALL_COMMAND_HANDLER(driver
->flash_bank_command
, c
);
829 if (ERROR_OK
!= retval
)
831 LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32
,
832 driver_name
, c
->base
);
842 COMMAND_HANDLER(handle_flash_banks_command
)
845 return ERROR_INVALID_ARGUMENTS
;
848 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
, n
++)
850 LOG_USER("#%u: %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", "
851 "buswidth %u, chipwidth %u", n
,
852 p
->driver
->name
, p
->base
, p
->size
,
853 p
->bus_width
, p
->chip_width
);
858 static int jim_flash_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
862 Jim_WrongNumArgs(interp
, 1, argv
,
863 "no arguments to 'flash list' command");
867 Jim_Obj
*list
= Jim_NewListObj(interp
, NULL
, 0);
869 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
)
871 Jim_Obj
*elem
= Jim_NewListObj(interp
, NULL
, 0);
873 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "name", -1));
874 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, p
->driver
->name
, -1));
875 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "base", -1));
876 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->base
));
877 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "size", -1));
878 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->size
));
879 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "bus_width", -1));
880 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->bus_width
));
881 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "chip_width", -1));
882 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->chip_width
));
884 Jim_ListAppendElement(interp
, list
, elem
);
887 Jim_SetResult(interp
, list
);
893 COMMAND_HANDLER(handle_flash_init_command
)
896 return ERROR_COMMAND_SYNTAX_ERROR
;
898 static bool flash_initialized
= false;
899 if (flash_initialized
)
901 LOG_INFO("'flash init' has already been called");
904 flash_initialized
= true;
906 LOG_DEBUG("Initializing flash devices...");
907 return flash_init_drivers(CMD_CTX
);
910 static const struct command_registration flash_config_command_handlers
[] = {
913 .handler
= handle_flash_bank_command
,
914 .mode
= COMMAND_CONFIG
,
915 .usage
= "bank_id driver_name base_address size_bytes "
916 "chip_width_bytes bus_width_bytes target "
917 "[driver_options ...]",
918 .help
= "Define a new bank with the given name, "
919 "using the specified NOR flash driver.",
923 .mode
= COMMAND_CONFIG
,
924 .handler
= handle_flash_init_command
,
925 .help
= "Initialize flash devices.",
930 .handler
= handle_flash_banks_command
,
931 .help
= "Display table with information about flash banks.",
936 .jim_handler
= jim_flash_list
,
937 .help
= "Returns a list of details about the flash banks.",
939 COMMAND_REGISTRATION_DONE
941 static const struct command_registration flash_command_handlers
[] = {
945 .help
= "NOR flash command group",
946 .chain
= flash_config_command_handlers
,
948 COMMAND_REGISTRATION_DONE
951 int flash_register_commands(struct command_context
*cmd_ctx
)
953 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)