
Permit the use of a + prefix to sizes in nand commands to extend operations to multiples of the appropriate page or erase block size.
Signed-off-by: Josh Karabin gkarabin@vocollect.com --- common/cmd_nand.c | 122 +++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 99 insertions(+), 23 deletions(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 1992531..516363e 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -102,14 +102,23 @@ static inline int str2long(char *p, ulong *num) }
static int -arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size) +arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, + size_t *size, size_t *headsize, size_t *tailsize) { int idx = nand_curr_device; + char *ps = argv[1]; + size_t max_tailsize; #if defined(CONFIG_CMD_MTDPARTS) struct mtd_device *dev; struct part_info *part; u8 pnum; +#endif + max_tailsize = *tailsize; + + if (argc >= 1 && *ps == '+') + ps++;
+#if defined(CONFIG_CMD_MTDPARTS) if (argc >= 1 && !(str2long(argv[0], off))) { if ((mtdparts_init() == 0) && (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) { @@ -119,8 +128,8 @@ arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size } *off = part->offset; if (argc >= 2) { - if (!(str2long(argv[1], (ulong *)size))) { - printf("'%s' is not a number\n", argv[1]); + if (!(str2long(ps, (ulong *)size))) { + printf("'%s' is not a number\n", ps); return -1; } if (*size > part->size) @@ -145,8 +154,8 @@ arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size }
if (argc >= 2) { - if (!(str2long(argv[1], (ulong *)size))) { - printf("'%s' is not a number\n", argv[1]); + if (!(str2long(ps, (ulong *)size))) { + printf("'%s' is not a number\n", ps); return -1; } } else { @@ -156,6 +165,16 @@ arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size #if defined(CONFIG_CMD_MTDPARTS) out: #endif + if (ps != argv[1]) { + *tailsize = *size & (max_tailsize - 1); + *headsize = *size - *tailsize; + if (*tailsize) + *size = *headsize + max_tailsize; + } else { + *tailsize = 0; + *headsize = *size; + } + printf("device %d ", idx); if (*size == nand->size) puts("whole chip\n"); @@ -229,6 +248,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) int quiet = 0; #endif const char *quiet_str = getenv("quiet"); + size_t tailsize = 0; + size_t headsize = 0;
/* at least two arguments please */ if (argc < 2) @@ -317,12 +338,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
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) + tailsize = nand->erasesize; + if (arg_off_size(argc - o, argv + o, nand, &off, &size, + &headsize, &tailsize) != 0) return 1;
memset(&opts, 0, sizeof(opts)); opts.offset = off; - opts.length = size; + opts.length = headsize; opts.jffs2 = clean; opts.quiet = quiet;
@@ -346,7 +369,18 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return -1; } } - ret = nand_erase_opts(nand, &opts); + + if (headsize) + ret = nand_erase_opts(nand, &opts); + else + ret = 0; + + if (!ret && tailsize) { + opts.offset = off + headsize; + opts.length = nand->erasesize; + ret = nand_erase_opts(nand, &opts); + } + printf("%s\n", ret ? "ERROR" : "OK");
return ret == 0 ? 0 : 1; @@ -378,23 +412,52 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
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) + tailsize = nand->writesize; + if (arg_off_size(argc - 3, argv + 3, nand, &off, &size, + &headsize, &tailsize) != 0) return 1;
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); + ret = nand_read_skip_bad(nand, off, &headsize, + (u_char *)addr); + else { + if (headsize) + ret = nand_write_skip_bad(nand, off, + &headsize, + (u_char *)addr); + else + ret = 0; + + if (!ret && tailsize) { + size_t pagesize = nand->writesize; + u_char *tailpage; + + tailpage = malloc(pagesize); + if (tailpage) { + memcpy(tailpage, + (u_char *)addr + + headsize, tailsize); + memset(tailpage + tailsize, + 0xff, + pagesize - tailsize); + ret = nand_write_skip_bad( + nand, + off + headsize, + &pagesize, + tailpage); + } + else + ret = 1; + } + } } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, - .ooblen = size, + .ooblen = size + tailsize, .mode = MTD_OOB_RAW };
@@ -457,10 +520,20 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) }
if (strcmp(cmd, "unlock") == 0) { - if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0) + tailsize = nand->erasesize; + if (arg_off_size(argc - 2, argv + 2, nand, &off, &size, + &headsize, &tailsize) < 0) return 1;
- if (!nand_unlock(nand, off, size)) { + if (headsize) + ret = nand_unlock(nand, off, headsize); + else + ret = 0; + + if (!ret && tailsize) + ret = nand_unlock(nand, off+headsize, nand->erasesize); + + if (!ret) { puts("NAND flash successfully unlocked\n"); } else { puts("Error unlocking NAND flash, " @@ -480,12 +553,14 @@ U_BOOT_CMD(nand, 5, 1, do_nand, "NAND sub-system", "info - show available NAND devices\n" "nand device [dev] - show or set current device\n" - "nand read - addr off|partition size\n" - "nand write - addr off|partition size\n" + "nand read - addr off|partition [+]size\n" + "nand write - addr off|partition [+]size\n" " read/write 'size' bytes starting at offset 'off'\n" - " to/from memory address 'addr', skipping bad blocks.\n" - "nand erase [clean] [off size] - erase 'size' bytes from\n" - " offset 'off' (entire device if not specified)\n" + " to/from memory address 'addr', skipping bad blocks,\n" + " extending to a page size if '+' is specified.\n" + "nand erase [clean] [off [+]size] - erase 'size' bytes from\n" + " extending to an erase block if '+' is specified,\n" + " from offset 'off' (entire device if not specified)\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" @@ -494,7 +569,8 @@ U_BOOT_CMD(nand, 5, 1, do_nand, #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK "nand lock [tight] [status]\n" " bring nand to lock state or display locked pages\n" - "nand unlock [offset] [size] - unlock section\n" + "nand unlock [offset] [[+]size] - unlock section\n" + " extending to an erase block if + is specified.\n" #endif );