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 <[email protected]>
---
 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
 );
 
-- 
1.6.0.4

_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to