[U-Boot] [PATCH] cmd_nand.c: converted to new style subcmd handling
Frans Meulenbroeks
fransmeulenbroeks at gmail.com
Sun Apr 4 21:53:16 CEST 2010
converted to new style subcmd handling.
partly tested on sheevaplug
read and information commands tested on sheevaplug
(sorry did not want to nuke my device so I did not want to
test things like nand scrub)
Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks at gmail.com>
---
note that nand biterr has no implementation
---
common/cmd_nand.c | 595 ++++++++++++++++++++++++++++++++++-------------------
1 files changed, 386 insertions(+), 209 deletions(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 9b0c930..d537b4b 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -204,281 +204,458 @@ static void nand_print_info(int idx)
nand->name, nand->erasesize >> 10);
}
-int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+static int nand_quiet(void)
{
- int i, dev, ret = 0;
- ulong addr, off;
- size_t size;
- char *cmd, *s;
- nand_info_t *nand;
+ const char *quiet_str = getenv("quiet");
#ifdef CONFIG_SYS_NAND_QUIET
int quiet = CONFIG_SYS_NAND_QUIET;
#else
int quiet = 0;
#endif
- const char *quiet_str = getenv("quiet");
-
- /* at least two arguments please */
- if (argc < 2)
- goto usage;
-
if (quiet_str)
quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
+ return quiet;
+}
- cmd = argv[1];
+static nand_info_t *get_nand(void)
+{
+ /* the following commands operate on the current device */
+ if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[nand_curr_device].name) {
+ puts("\nno devices available\n");
+ return NULL;
+ }
+ return &nand_info[nand_curr_device];
+}
- if (strcmp(cmd, "info") == 0) {
+static int do_nand_info(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int i;
- putc('\n');
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
- if (nand_info[i].name)
- nand_print_info(i);
- }
- return 0;
+ putc('\n');
+ for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
+ if (nand_info[i].name)
+ nand_print_info(i);
}
+ return 0;
+}
- if (strcmp(cmd, "device") == 0) {
+static int do_nand_device(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int dev;
- if (argc < 3) {
- putc('\n');
- if ((nand_curr_device < 0) ||
- (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE))
- puts("no devices available\n");
- else
- nand_print_info(nand_curr_device);
- return 0;
- }
- dev = (int)simple_strtoul(argv[2], NULL, 10);
- if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) {
- puts("No such device\n");
- return 1;
- }
- printf("Device %d: %s", dev, nand_info[dev].name);
- puts("... is now current device\n");
- nand_curr_device = dev;
+ if (argc < 2) {
+ putc('\n');
+ if ((nand_curr_device < 0) ||
+ (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE))
+ puts("no devices available\n");
+ else
+ nand_print_info(nand_curr_device);
+ return 0;
+ }
+ dev = (int)simple_strtoul(argv[1], NULL, 10);
+ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) {
+ puts("No such device\n");
+ return 1;
+ }
+ printf("Device %d: %s", dev, nand_info[dev].name);
+ puts("... is now current device\n");
+ nand_curr_device = dev;
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
- /*
- * Select the chip in the board/cpu specific driver
- */
- board_nand_select_device(nand_info[dev].priv, dev);
+ /*
+ * Select the chip in the board/cpu specific driver
+ */
+ board_nand_select_device(nand_info[dev].priv, dev);
#endif
- return 0;
+ return 0;
+}
+
+static int do_nand_read(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int ret = 0;
+ size_t size;
+ ulong off;
+ ulong addr;
+ char *s;
+ nand_info_t *nand;
+
+ nand = get_nand();
+ if (!nand)
+ return 1;
+
+ if (argc < 4)
+ {
+ cmd_usage(cmdtp);
+ return 1;
}
- if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
- strncmp(cmd, "dump", 4) != 0 &&
- strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
- strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
- strcmp(cmd, "biterr") != 0 &&
- strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
- goto usage;
+ addr = (ulong)simple_strtoul(argv[1], NULL, 16);
- /* the following commands operate on the current device */
- if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
- !nand_info[nand_curr_device].name) {
- puts("\nno devices available\n");
+ printf("\nNAND read: ");
+ if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) != 0)
+ return 1;
+
+ s = strchr(argv[0], '.');
+ if (!s || !strcmp(s, ".jffs2") ||
+ !strcmp(s, ".e") || !strcmp(s, ".i")) {
+ ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr);
+ } else if (!strcmp(s, ".oob")) {
+ /* out-of-band data */
+ mtd_oob_ops_t ops = {
+ .oobbuf = (u8 *)addr,
+ .ooblen = size,
+ .mode = MTD_OOB_RAW
+ };
+
+ ret = nand->read_oob(nand, off, &ops);
+ } else {
+ printf("Unknown nand command suffix '%s'.\n", s);
return 1;
}
- nand = &nand_info[nand_curr_device];
- if (strcmp(cmd, "bad") == 0) {
- printf("\nDevice %d bad blocks:\n", nand_curr_device);
- for (off = 0; off < nand->size; off += nand->erasesize)
- if (nand_block_isbad(nand, off))
- printf(" %08lx\n", off);
- return 0;
+ printf(" %zu bytes read: %s\n", size, ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
+
+static int do_nand_write(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int ret = 0;
+ size_t size;
+ ulong off;
+ ulong addr;
+ char *s;
+ nand_info_t *nand;
+
+ nand = get_nand();
+ if (!nand)
+ return 1;
+
+ if (argc < 4)
+ {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ addr = (ulong)simple_strtoul(argv[1], NULL, 16);
+
+ printf("\nNAND write: ");
+ if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) != 0)
+ return 1;
+
+ s = strchr(argv[0], '.');
+ if (!s || !strcmp(s, ".jffs2") ||
+ !strcmp(s, ".e") || !strcmp(s, ".i")) {
+ ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr);
+ } else if (!strcmp(s, ".oob")) {
+ /* out-of-band data */
+ mtd_oob_ops_t ops = {
+ .oobbuf = (u8 *)addr,
+ .ooblen = size,
+ .mode = MTD_OOB_RAW
+ };
+
+ ret = nand->write_oob(nand, off, &ops);
+ } else {
+ printf("Unknown nand command suffix '%s'.\n", s);
+ return 1;
}
+ printf(" %zu bytes written: %s\n", size, ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
+
+static int do_nand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
/*
* Syntax is:
* 0 1 2 3 4
* nand erase [clean] [off size]
*/
- if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
- nand_erase_options_t opts;
- /* "clean" at index 2 means request to write cleanmarker */
- int clean = argc > 2 && !strcmp("clean", argv[2]);
- int o = clean ? 3 : 2;
- int scrub = !strcmp(cmd, "scrub");
-
- printf("\nNAND %s: ", scrub ? "scrub" : "erase");
- /* skip first two or three arguments, look for offset and size */
- if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
- return 1;
- memset(&opts, 0, sizeof(opts));
- opts.offset = off;
- opts.length = size;
- opts.jffs2 = clean;
- opts.quiet = quiet;
-
- if (scrub) {
- puts("Warning: "
- "scrub option will erase all factory set "
- "bad blocks!\n"
- " "
- "There is no reliable way to recover them.\n"
- " "
- "Use this command only for testing purposes "
- "if you\n"
- " "
- "are sure of what you are doing!\n"
- "\nReally scrub this NAND flash? <y/N>\n");
-
- if (getc() == 'y') {
- puts("y");
- if (getc() == '\r')
- opts.scrub = 1;
- else {
- puts("scrub aborted\n");
- return -1;
- }
- } else {
- puts("scrub aborted\n");
- return -1;
- }
- }
- ret = nand_erase_opts(nand, &opts);
- printf("%s\n", ret ? "ERROR" : "OK");
+ int ret = 0;
+ size_t size;
+ ulong off;
+ nand_erase_options_t opts;
+ /* "clean" at index 1 means request to write cleanmarker */
+ int clean = argc > 1 && !strcmp("clean", argv[1]);
+ int o = clean ? 2 : 1;
+ nand_info_t *nand;
+ int quiet = nand_quiet();
- return ret == 0 ? 0 : 1;
- }
+ nand = get_nand();
+ if (!nand)
+ return 1;
- if (strncmp(cmd, "dump", 4) == 0) {
- if (argc < 3)
- goto usage;
+ printf("\nNAND erase: ");
+ /* skip first two or three arguments, look for offset and size */
+ if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
+ return 1;
- s = strchr(cmd, '.');
- off = (int)simple_strtoul(argv[2], NULL, 16);
+ memset(&opts, 0, sizeof(opts));
+ opts.offset = off;
+ opts.length = size;
+ opts.jffs2 = clean;
+ opts.quiet = quiet;
- if (s != NULL && strcmp(s, ".oob") == 0)
- ret = nand_dump(nand, off, 1);
- else
- ret = nand_dump(nand, off, 0);
+ ret = nand_erase_opts(nand, &opts);
+ printf("%s\n", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
- return ret == 0 ? 1 : 0;
+static int do_nand_scrub(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ /*
+ * Syntax is:
+ * 0 1 2 3 4
+ * nand scrub [clean] [off size]
+ */
+ int ret = 0;
+ size_t size;
+ ulong off;
+ nand_erase_options_t opts;
+ /* "clean" at index 1 means request to write cleanmarker */
+ int clean = argc > 1 && !strcmp("clean", argv[1]);
+ int o = clean ? 2 : 1;
+ nand_info_t *nand;
+ int quiet = nand_quiet();
+
+ nand = get_nand();
+ if (!nand)
+ return 1;
+
+ printf("\nNAND scrub: ");
+ /* skip first two or three arguments, look for offset and size */
+ if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
+ return 1;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.offset = off;
+ opts.length = size;
+ opts.jffs2 = clean;
+ opts.quiet = quiet;
+
+ puts("Warning: "
+ "scrub option will erase all factory set "
+ "bad blocks!\n"
+ " "
+ "There is no reliable way to recover them.\n"
+ " "
+ "Use this command only for testing purposes "
+ "if you\n"
+ " "
+ "are sure of what you are doing!\n"
+ "\nReally scrub this NAND flash? <y/N>\n");
+
+ if (getc() == 'y') {
+ puts("y");
+ if (getc() == '\r')
+ opts.scrub = 1;
+ else {
+ puts("scrub aborted\n");
+ return -1;
+ }
+ } else {
+ puts("scrub aborted\n");
+ return -1;
}
+ ret = nand_erase_opts(nand, &opts);
+ printf("%s\n", ret ? "ERROR" : "OK");
- if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
- int read;
+ return ret == 0 ? 0 : 1;
+}
- if (argc < 4)
- goto usage;
+static int do_nand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong off;
+ nand_info_t *nand;
- addr = (ulong)simple_strtoul(argv[2], NULL, 16);
+ nand = get_nand();
+ if (!nand)
+ return 1;
- read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
- printf("\nNAND %s: ", read ? "read" : "write");
- if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
- return 1;
+ printf("\nDevice %d bad blocks:\n", nand_curr_device);
+ for (off = 0; off < nand->size; off += nand->erasesize)
+ if (nand_block_isbad(nand, off))
+ printf(" %08lx\n", off);
+ return 0;
+}
- s = strchr(cmd, '.');
- if (!s || !strcmp(s, ".jffs2") ||
- !strcmp(s, ".e") || !strcmp(s, ".i")) {
- if (read)
- ret = nand_read_skip_bad(nand, off, &size,
- (u_char *)addr);
- else
- ret = nand_write_skip_bad(nand, off, &size,
- (u_char *)addr);
- } else if (!strcmp(s, ".oob")) {
- /* out-of-band data */
- mtd_oob_ops_t ops = {
- .oobbuf = (u8 *)addr,
- .ooblen = size,
- .mode = MTD_OOB_RAW
- };
-
- if (read)
- ret = nand->read_oob(nand, off, &ops);
- else
- ret = nand->write_oob(nand, off, &ops);
- } else {
- printf("Unknown nand command suffix '%s'.\n", s);
- return 1;
- }
+static int do_nand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int ret = 0;
+ ulong off;
+ char *s;
+ nand_info_t *nand;
- printf(" %zu bytes %s: %s\n", size,
- read ? "read" : "written", ret ? "ERROR" : "OK");
+ nand = get_nand();
+ if (!nand)
+ return 1;
- return ret == 0 ? 0 : 1;
+ if (argc < 2)
+ {
+ cmd_usage(cmdtp);
+ return 1;
}
- if (strcmp(cmd, "markbad") == 0) {
- argc -= 2;
- argv += 2;
+ s = strchr(argv[0], '.');
+ off = (int)simple_strtoul(argv[1], NULL, 16);
- if (argc <= 0)
- goto usage;
+ if (s != NULL && strcmp(s, ".oob") == 0)
+ ret = nand_dump(nand, off, 1);
+ else
+ ret = nand_dump(nand, off, 0);
- while (argc > 0) {
- addr = simple_strtoul(*argv, NULL, 16);
+ return ret == 0 ? 1 : 0;
+}
- if (nand->block_markbad(nand, addr)) {
- printf("block 0x%08lx NOT marked "
- "as bad! ERROR %d\n",
- addr, ret);
- ret = 1;
- } else {
- printf("block 0x%08lx successfully "
- "marked as bad\n",
- addr);
- }
- --argc;
- ++argv;
- }
- return ret;
- }
+static int do_nand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int ret = 0;
+ ulong addr;
+ nand_info_t *nand;
+
+ nand = get_nand();
+ if (!nand)
+ return 1;
- if (strcmp(cmd, "biterr") == 0) {
- /* todo */
+ argc--;
+ argv++;
+
+ if (argc <= 0)
+ {
+ cmd_usage(cmdtp);
return 1;
}
-#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
- if (strcmp(cmd, "lock") == 0) {
- int tight = 0;
- int status = 0;
- if (argc == 3) {
- if (!strcmp("tight", argv[2]))
- tight = 1;
- if (!strcmp("status", argv[2]))
- status = 1;
- }
- if (status) {
- do_nand_status(nand);
+ while (argc > 0) {
+ addr = simple_strtoul(*argv, NULL, 16);
+
+ if (nand->block_markbad(nand, addr)) {
+ printf("block 0x%08lx NOT marked "
+ "as bad! ERROR %d\n",
+ addr, ret);
+ ret = 1;
} else {
- if (!nand_lock(nand, tight)) {
- puts("NAND flash successfully locked\n");
- } else {
- puts("Error locking NAND flash\n");
- return 1;
- }
+ printf("block 0x%08lx successfully "
+ "marked as bad\n",
+ addr);
}
- return 0;
+ argc--;
+ argv++;
}
+ return ret;
+}
- if (strcmp(cmd, "unlock") == 0) {
- if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
- return 1;
+static int do_nand_biterr(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ nand_info_t *nand;
- if (!nand_unlock(nand, off, size)) {
- puts("NAND flash successfully unlocked\n");
+ nand = get_nand();
+ if (!nand)
+ return 1;
+
+ /* todo */
+ return 1;
+}
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+static int do_nand_lock(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong addr;
+ size_t size;
+ nand_info_t *nand;
+ int tight = 0;
+ int status = 0;
+
+ nand = get_nand();
+ if (!nand)
+ return 1;
+
+ if (argc == 2) {
+ if (!strcmp("tight", argv[1]))
+ tight = 1;
+ if (!strcmp("status", argv[1]))
+ status = 1;
+ }
+ if (status) {
+ do_nand_status(nand);
+ } else {
+ if (!nand_lock(nand, tight)) {
+ puts("NAND flash successfully locked\n");
} else {
- puts("Error unlocking NAND flash, "
- "write and erase will probably fail\n");
+ puts("Error locking NAND flash\n");
return 1;
}
- return 0;
}
+ return 0;
+}
+
+static int do_nand_unlock(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong addr;
+ size_t size;
+ nand_info_t *nand;
+
+ argc--;
+ argv++;
+
+ nand = get_nand();
+ if (!nand)
+ return 1;
+
+ if (arg_off_size(argc, argv, nand, &off, &size) < 0)
+ return 1;
+
+ if (!nand_unlock(nand, off, size)) {
+ puts("NAND flash successfully unlocked\n");
+ } else {
+ puts("Error unlocking NAND flash, "
+ "write and erase will probably fail\n");
+ return 1;
+ }
+ return 0;
+}
#endif
-usage:
- cmd_usage(cmdtp);
- return 1;
+static cmd_tbl_t cmd_nand_sub[] = {
+ U_BOOT_CMD_MKENT(info, 1, 1, do_nand_info, "", ""),
+ U_BOOT_CMD_MKENT(device, 2, 1, do_nand_device, "", ""),
+ U_BOOT_CMD_MKENT(read, 4, 1, do_nand_read, "", ""),
+ U_BOOT_CMD_MKENT(write, 4, 1, do_nand_write, "", ""),
+ U_BOOT_CMD_MKENT(erase, 4, 1, do_nand_erase, "", ""),
+ U_BOOT_CMD_MKENT(bad, 1, 1, do_nand_bad, "", ""),
+ U_BOOT_CMD_MKENT(dump, 2, 1, do_nand_dump, "", ""),
+ U_BOOT_CMD_MKENT(scrub, 1, 1, do_nand_scrub, "", ""),
+ U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 1, do_nand_markbad, "", ""),
+ U_BOOT_CMD_MKENT(biterr, 2, 1, do_nand_biterr, "", ""),
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ U_BOOT_CMD_MKENT(lock, 1, 1, do_nand_lock, "", ""),
+ U_BOOT_CMD_MKENT(unlock, 1, 1, do_nand_unlock, "", ""),
+#endif
+};
+
+static int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ cmd_tbl_t *c;
+
+ /* Strip off leading 'nand' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_nand_sub[0], ARRAY_SIZE(cmd_nand_sub));
+
+ if (c) {
+ return c->cmd(cmdtp, flag, argc, argv);
+ } else {
+ cmd_usage(cmdtp);
+ return 1;
+ }
}
U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
--
1.6.4.2
More information about the U-Boot
mailing list