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>
29 COMMAND_HELPER(flash_command_get_bank
, unsigned name_index
,
30 struct flash_bank
**bank
)
32 const char *name
= CMD_ARGV
[name_index
];
33 *bank
= get_flash_bank_by_name(name
);
38 COMMAND_PARSE_NUMBER(uint
, name
, bank_num
);
40 *bank
= get_flash_bank_by_num(bank_num
);
43 command_print(CMD_CTX
, "flash bank '%s' not found", name
);
44 return ERROR_INVALID_ARGUMENTS
;
50 COMMAND_HANDLER(handle_flash_info_command
)
58 return ERROR_COMMAND_SYNTAX_ERROR
;
61 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
63 for (p
= flash_bank_list(); p
; p
= p
->next
, i
++)
70 /* attempt auto probe */
71 if ((retval
= p
->driver
->auto_probe(p
)) != ERROR_OK
)
74 command_print(CMD_CTX
,
75 "#%" PRIi32
" : %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", buswidth %i, chipwidth %i",
82 for (j
= 0; j
< p
->num_sectors
; j
++)
86 if (p
->sectors
[j
].is_protected
== 0)
87 protect_state
= "not protected";
88 else if (p
->sectors
[j
].is_protected
== 1)
89 protect_state
= "protected";
91 protect_state
= "protection state unknown";
93 command_print(CMD_CTX
,
94 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
98 p
->sectors
[j
].size
>> 10,
102 *buf
= '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
103 retval
= p
->driver
->info(p
, buf
, sizeof(buf
));
104 command_print(CMD_CTX
, "%s", buf
);
105 if (retval
!= ERROR_OK
)
106 LOG_ERROR("error retrieving flash info (%d)", retval
);
112 COMMAND_HANDLER(handle_flash_probe_command
)
118 return ERROR_COMMAND_SYNTAX_ERROR
;
122 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], bank_nr
);
123 struct flash_bank
*p
= get_flash_bank_by_num_noprobe(bank_nr
);
126 if ((retval
= p
->driver
->probe(p
)) == ERROR_OK
)
128 command_print(CMD_CTX
, "flash '%s' found at 0x%8.8" PRIx32
, p
->driver
->name
, p
->base
);
130 else if (retval
== ERROR_FLASH_BANK_INVALID
)
132 command_print(CMD_CTX
, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32
,
133 CMD_ARGV
[0], p
->base
);
137 command_print(CMD_CTX
, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32
,
138 CMD_ARGV
[0], p
->base
);
143 command_print(CMD_CTX
, "flash bank '#%s' is out of bounds", CMD_ARGV
[0]);
149 COMMAND_HANDLER(handle_flash_erase_check_command
)
153 return ERROR_COMMAND_SYNTAX_ERROR
;
156 struct flash_bank
*p
;
157 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
158 if (ERROR_OK
!= retval
)
162 if ((retval
= p
->driver
->erase_check(p
)) == ERROR_OK
)
164 command_print(CMD_CTX
, "successfully checked erase state");
168 command_print(CMD_CTX
, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32
,
169 CMD_ARGV
[0], p
->base
);
172 for (j
= 0; j
< p
->num_sectors
; j
++)
176 if (p
->sectors
[j
].is_erased
== 0)
177 erase_state
= "not erased";
178 else if (p
->sectors
[j
].is_erased
== 1)
179 erase_state
= "erased";
181 erase_state
= "erase state unknown";
183 command_print(CMD_CTX
,
184 "\t#%3i: 0x%8.8" PRIx32
" (0x%" PRIx32
" %" PRIi32
"kB) %s",
186 p
->sectors
[j
].offset
,
188 p
->sectors
[j
].size
>> 10,
195 COMMAND_HANDLER(handle_flash_erase_address_command
)
197 struct flash_bank
*p
;
202 struct target
*target
= get_current_target(CMD_CTX
);
205 return ERROR_COMMAND_SYNTAX_ERROR
;
207 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], address
);
208 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], length
);
211 command_print(CMD_CTX
, "Length must be >0");
212 return ERROR_COMMAND_SYNTAX_ERROR
;
215 p
= get_flash_bank_by_addr(target
, address
);
221 /* We can't know if we did a resume + halt, in which case we no longer know the erased state */
224 struct duration bench
;
225 duration_start(&bench
);
227 retval
= flash_erase_address_range(target
, address
, length
);
229 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
231 command_print(CMD_CTX
, "erased address 0x%8.8x (length %i)"
232 " in %fs (%0.3f kb/s)", address
, length
,
233 duration_elapsed(&bench
), duration_kbps(&bench
, length
));
239 COMMAND_HANDLER(handle_flash_protect_check_command
)
242 return ERROR_COMMAND_SYNTAX_ERROR
;
244 struct flash_bank
*p
;
245 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
246 if (ERROR_OK
!= retval
)
249 if ((retval
= p
->driver
->protect_check(p
)) == ERROR_OK
)
251 command_print(CMD_CTX
, "successfully checked protect state");
253 else if (retval
== ERROR_FLASH_OPERATION_FAILED
)
255 command_print(CMD_CTX
, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8" PRIx32
, CMD_ARGV
[0], p
->base
);
259 command_print(CMD_CTX
, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8" PRIx32
, CMD_ARGV
[0], p
->base
);
265 static int flash_check_sector_parameters(struct command_context
*cmd_ctx
,
266 uint32_t first
, uint32_t last
, uint32_t num_sectors
)
268 if (!(first
<= last
)) {
269 command_print(cmd_ctx
, "ERROR: "
270 "first sector must be <= last sector");
274 if (!(last
<= (num_sectors
- 1))) {
275 command_print(cmd_ctx
, "ERROR: last sector must be <= %d",
276 (int) num_sectors
- 1);
283 COMMAND_HANDLER(handle_flash_erase_command
)
286 return ERROR_COMMAND_SYNTAX_ERROR
;
292 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
293 struct flash_bank
*p
= get_flash_bank_by_num(bank_nr
);
297 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
298 if (strcmp(CMD_ARGV
[2], "last") == 0)
299 last
= p
->num_sectors
- 1;
301 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
304 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
305 first
, last
, p
->num_sectors
)) != ERROR_OK
)
308 struct duration bench
;
309 duration_start(&bench
);
311 retval
= flash_driver_erase(p
, first
, last
);
313 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
315 command_print(CMD_CTX
, "erased sectors %" PRIu32
" "
316 "through %" PRIu32
" on flash bank %" PRIu32
" "
317 "in %fs", first
, last
, bank_nr
, duration_elapsed(&bench
));
323 COMMAND_HANDLER(handle_flash_protect_command
)
326 return ERROR_COMMAND_SYNTAX_ERROR
;
332 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], bank_nr
);
333 struct flash_bank
*p
= get_flash_bank_by_num(bank_nr
);
337 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], first
);
338 if (strcmp(CMD_ARGV
[2], "last") == 0)
339 last
= p
->num_sectors
- 1;
341 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], last
);
344 COMMAND_PARSE_ON_OFF(CMD_ARGV
[3], set
);
347 if ((retval
= flash_check_sector_parameters(CMD_CTX
,
348 first
, last
, p
->num_sectors
)) != ERROR_OK
)
351 retval
= flash_driver_protect(p
, set
, first
, last
);
352 if (retval
== ERROR_OK
) {
353 command_print(CMD_CTX
, "%s protection for sectors %i "
354 "through %i on flash bank %i",
355 (set
) ? "set" : "cleared", (int) first
,
356 (int) last
, (int) bank_nr
);
362 COMMAND_HANDLER(handle_flash_write_image_command
)
364 struct target
*target
= get_current_target(CMD_CTX
);
373 return ERROR_COMMAND_SYNTAX_ERROR
;
376 /* flash auto-erase is disabled by default*/
378 bool auto_unlock
= false;
382 if (strcmp(CMD_ARGV
[0], "erase") == 0)
387 command_print(CMD_CTX
, "auto erase enabled");
388 } else if (strcmp(CMD_ARGV
[0], "unlock") == 0)
393 command_print(CMD_CTX
, "auto unlock enabled");
402 return ERROR_COMMAND_SYNTAX_ERROR
;
407 LOG_ERROR("no target selected");
411 struct duration bench
;
412 duration_start(&bench
);
416 image
.base_address_set
= 1;
417 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], image
.base_address
);
421 image
.base_address_set
= 0;
422 image
.base_address
= 0x0;
425 image
.start_address_set
= 0;
427 retval
= image_open(&image
, CMD_ARGV
[0], (CMD_ARGC
== 3) ? CMD_ARGV
[2] : NULL
);
428 if (retval
!= ERROR_OK
)
433 retval
= flash_write_unlock(target
, &image
, &written
, auto_erase
, auto_unlock
);
434 if (retval
!= ERROR_OK
)
440 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
442 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes from file %s "
443 "in %fs (%0.3f kb/s)", written
, CMD_ARGV
[0],
444 duration_elapsed(&bench
), duration_kbps(&bench
, written
));
452 COMMAND_HANDLER(handle_flash_fill_command
)
459 uint32_t cur_size
= 0;
460 uint32_t chunk_count
;
461 struct target
*target
= get_current_target(CMD_CTX
);
464 int retval
= ERROR_OK
;
466 static size_t const chunksize
= 1024;
467 uint8_t *chunk
= malloc(chunksize
);
471 uint8_t *readback
= malloc(chunksize
);
472 if (readback
== NULL
)
481 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
486 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
487 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], pattern
);
488 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], count
);
505 retval
= ERROR_COMMAND_SYNTAX_ERROR
;
509 chunk_count
= MIN(count
, (chunksize
/ wordsize
));
513 for (i
= 0; i
< chunk_count
; i
++)
515 target_buffer_set_u32(target
, chunk
+ i
* wordsize
, pattern
);
519 for (i
= 0; i
< chunk_count
; i
++)
521 target_buffer_set_u16(target
, chunk
+ i
* wordsize
, pattern
);
525 memset(chunk
, pattern
, chunk_count
);
528 LOG_ERROR("BUG: can't happen");
532 struct duration bench
;
533 duration_start(&bench
);
535 for (wrote
= 0; wrote
< (count
*wordsize
); wrote
+= cur_size
)
537 struct flash_bank
*bank
;
539 bank
= get_flash_bank_by_addr(target
, address
);
546 cur_size
= MIN((count
* wordsize
- wrote
), chunksize
);
547 err
= flash_driver_write(bank
, chunk
, address
- bank
->base
+ wrote
, cur_size
);
554 err
= target_read_buffer(target
, address
+ wrote
, cur_size
, readback
);
562 for (i
= 0; i
< cur_size
; i
++)
564 if (readback
[i
]!=chunk
[i
])
566 LOG_ERROR("Verfication error address 0x%08" PRIx32
", read back 0x%02x, expected 0x%02x",
567 address
+ wrote
+ i
, readback
[i
], chunk
[i
]);
574 if (duration_measure(&bench
) == ERROR_OK
)
576 command_print(CMD_CTX
, "wrote %" PRIu32
" bytes to 0x%8.8" PRIx32
577 " in %fs (%0.3f kb/s)", wrote
, address
,
578 duration_elapsed(&bench
), duration_kbps(&bench
, wrote
));
588 COMMAND_HANDLER(handle_flash_write_bank_command
)
592 struct fileio fileio
;
595 return ERROR_COMMAND_SYNTAX_ERROR
;
597 struct duration bench
;
598 duration_start(&bench
);
600 struct flash_bank
*p
;
601 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &p
);
602 if (ERROR_OK
!= retval
)
605 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], offset
);
607 if (fileio_open(&fileio
, CMD_ARGV
[1], FILEIO_READ
, FILEIO_BINARY
) != ERROR_OK
)
612 buffer
= malloc(fileio
.size
);
614 if (fileio_read(&fileio
, fileio
.size
, buffer
, &buf_cnt
) != ERROR_OK
)
617 fileio_close(&fileio
);
621 retval
= flash_driver_write(p
, buffer
, offset
, buf_cnt
);
626 if ((ERROR_OK
== retval
) && (duration_measure(&bench
) == ERROR_OK
))
628 command_print(CMD_CTX
, "wrote %ld bytes from file %s to flash bank %u"
629 " at offset 0x%8.8" PRIx32
" in %fs (%0.3f kb/s)",
630 (long)fileio
.size
, CMD_ARGV
[1], p
->bank_number
, offset
,
631 duration_elapsed(&bench
), duration_kbps(&bench
, fileio
.size
));
634 fileio_close(&fileio
);
639 void flash_set_dirty(void)
641 struct flash_bank
*c
;
644 /* set all flash to require erasing */
645 for (c
= flash_bank_list(); c
; c
= c
->next
)
647 for (i
= 0; i
< c
->num_sectors
; i
++)
649 c
->sectors
[i
].is_erased
= 0;
654 static const struct command_registration flash_exec_command_handlers
[] = {
657 .handler
= handle_flash_probe_command
,
658 .mode
= COMMAND_EXEC
,
660 .help
= "Identify a flash bank.",
664 .handler
= handle_flash_info_command
,
665 .mode
= COMMAND_EXEC
,
667 .help
= "Print information about a flash bank.",
670 .name
= "erase_check",
671 .handler
= handle_flash_erase_check_command
,
672 .mode
= COMMAND_EXEC
,
674 .help
= "Check erase state of all blocks in a "
678 .name
= "protect_check",
679 .handler
= handle_flash_protect_check_command
,
680 .mode
= COMMAND_EXEC
,
682 .help
= "Check protection state of all blocks in a "
686 .name
= "erase_sector",
687 .handler
= handle_flash_erase_command
,
688 .mode
= COMMAND_EXEC
,
689 .usage
= "bank_id first_sector_num last_sector_num",
690 .help
= "Erase a range of sectors in a flash bank.",
693 .name
= "erase_address",
694 .handler
= handle_flash_erase_address_command
,
695 .mode
= COMMAND_EXEC
,
696 .usage
= "address length",
697 .help
= "Erase flash blocks starting at address "
698 "and continuing for length bytes.",
702 .handler
= handle_flash_fill_command
,
703 .mode
= COMMAND_EXEC
,
704 .usage
= "address value n",
705 .help
= "Fill n words with 32-bit value, starting at "
706 "word address. (No autoerase.)",
710 .handler
= handle_flash_fill_command
,
711 .mode
= COMMAND_EXEC
,
712 .usage
= "address value n",
713 .help
= "Fill n halfwords with 16-bit value, starting at "
714 "word address. (No autoerase.)",
718 .handler
= handle_flash_fill_command
,
719 .mode
= COMMAND_EXEC
,
720 .usage
= "address value n",
721 .help
= "Fill n bytes with 8-bit value, starting at "
722 "word address. (No autoerase.)",
725 .name
= "write_bank",
726 .handler
= handle_flash_write_bank_command
,
727 .mode
= COMMAND_EXEC
,
728 .usage
= "bank_id filename offset",
729 .help
= "Write binary data from file to flash bank, "
730 "starting at specified byte offset from the "
731 "beginning of the bank.",
734 .name
= "write_image",
735 .handler
= handle_flash_write_image_command
,
736 .mode
= COMMAND_EXEC
,
737 .usage
= "[erase] [unlock] filename [offset [file_type]]",
738 .help
= "Write an image to flash. Optionally first unprotect "
739 "and/or erase the region to be used. Allow optional "
740 "offset from beginning of bank (defaults to zero)",
744 .handler
= handle_flash_protect_command
,
745 .mode
= COMMAND_EXEC
,
746 .usage
= "bank_id first_sector [last_sector|'last'] "
748 .help
= "Turn protection on or off for a range of sectors "
749 "in a given flash bank.",
751 COMMAND_REGISTRATION_DONE
754 int flash_init_drivers(struct command_context
*cmd_ctx
)
756 if (!flash_bank_list())
759 struct command
*parent
= command_find_in_context(cmd_ctx
, "flash");
760 return register_commands(cmd_ctx
, parent
, flash_exec_command_handlers
);
764 COMMAND_HANDLER(handle_flash_bank_command
)
768 LOG_ERROR("usage: flash bank <name> <driver> "
769 "<base> <size> <chip_width> <bus_width>");
770 return ERROR_COMMAND_SYNTAX_ERROR
;
772 // save bank name and advance arguments for compatibility
773 const char *bank_name
= *CMD_ARGV
++;
776 struct target
*target
;
777 if ((target
= get_target(CMD_ARGV
[5])) == NULL
)
779 LOG_ERROR("target '%s' not defined", CMD_ARGV
[5]);
783 const char *driver_name
= CMD_ARGV
[0];
784 struct flash_driver
*driver
= flash_driver_find_by_name(driver_name
);
787 /* no matching flash driver found */
788 LOG_ERROR("flash driver '%s' not found", driver_name
);
792 /* register flash specific commands */
793 if (NULL
!= driver
->commands
)
795 int retval
= register_commands(CMD_CTX
, NULL
,
797 if (ERROR_OK
!= retval
)
799 LOG_ERROR("couldn't register '%s' commands",
805 struct flash_bank
*c
= malloc(sizeof(*c
));
806 c
->name
= strdup(bank_name
);
809 c
->driver_priv
= NULL
;
810 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], c
->base
);
811 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], c
->size
);
812 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], c
->chip_width
);
813 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[4], c
->bus_width
);
819 retval
= CALL_COMMAND_HANDLER(driver
->flash_bank_command
, c
);
820 if (ERROR_OK
!= retval
)
822 LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32
,
823 driver_name
, c
->base
);
833 COMMAND_HANDLER(handle_flash_banks_command
)
836 return ERROR_INVALID_ARGUMENTS
;
839 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
, n
++)
841 LOG_USER("#%u: %s at 0x%8.8" PRIx32
", size 0x%8.8" PRIx32
", "
842 "buswidth %u, chipwidth %u", n
,
843 p
->driver
->name
, p
->base
, p
->size
,
844 p
->bus_width
, p
->chip_width
);
849 static int jim_flash_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
853 Jim_WrongNumArgs(interp
, 1, argv
,
854 "no arguments to 'flash list' command");
858 Jim_Obj
*list
= Jim_NewListObj(interp
, NULL
, 0);
860 for (struct flash_bank
*p
= flash_bank_list(); p
; p
= p
->next
)
862 Jim_Obj
*elem
= Jim_NewListObj(interp
, NULL
, 0);
864 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "name", -1));
865 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, p
->driver
->name
, -1));
866 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "base", -1));
867 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->base
));
868 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "size", -1));
869 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->size
));
870 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "bus_width", -1));
871 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->bus_width
));
872 Jim_ListAppendElement(interp
, elem
, Jim_NewStringObj(interp
, "chip_width", -1));
873 Jim_ListAppendElement(interp
, elem
, Jim_NewIntObj(interp
, p
->chip_width
));
875 Jim_ListAppendElement(interp
, list
, elem
);
878 Jim_SetResult(interp
, list
);
884 COMMAND_HANDLER(handle_flash_init_command
)
887 return ERROR_COMMAND_SYNTAX_ERROR
;
889 static bool flash_initialized
= false;
890 if (flash_initialized
)
892 LOG_INFO("'flash init' has already been called");
895 flash_initialized
= true;
897 LOG_DEBUG("Initializing flash devices...");
898 return flash_init_drivers(CMD_CTX
);
901 static const struct command_registration flash_config_command_handlers
[] = {
904 .handler
= &handle_flash_bank_command
,
905 .mode
= COMMAND_CONFIG
,
906 .usage
= "bank_id driver_name base_address size_bytes "
907 "chip_width_bytes bus_width_bytes target "
908 "[driver_options ...]",
909 .help
= "Define a new bank with the given name, "
910 "using the specified NOR flash driver.",
914 .mode
= COMMAND_CONFIG
,
915 .handler
= &handle_flash_init_command
,
916 .help
= "Initialize flash devices.",
921 .handler
= &handle_flash_banks_command
,
922 .help
= "Display table with information about flash banks.",
927 .jim_handler
= &jim_flash_list
,
928 .help
= "Returns a list of details about the flash banks.",
930 COMMAND_REGISTRATION_DONE
932 static const struct command_registration flash_command_handlers
[] = {
936 .help
= "NOR flash command group",
937 .chain
= flash_config_command_handlers
,
939 COMMAND_REGISTRATION_DONE
942 int flash_register_commands(struct command_context
*cmd_ctx
)
944 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)