David Brownell <david-b@pacbell.net>:
authorzwelch <zwelch@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Sun, 24 May 2009 01:57:13 +0000 (01:57 +0000)
committerzwelch <zwelch@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Sun, 24 May 2009 01:57:13 +0000 (01:57 +0000)
Update two oddball NAND commands to work with {offset, length}
instead of block numbers, matching the other commands as well
as usage in U-Boot and the Linux-MTD utilities.

Document them accordingly.  Update the single in-tree use of
those commands (sheevaplug).

ALSO:

 (a) Document the current 2 GByte/chip ceiling for NAND chipsize.
     (32 bit offset/length values can't represent 4 GBytes.)  Maybe
     after the upcoming release, the code can switch to 64-bits.

 (b) The "nand check_bad_blocks" should report "bad" blocks.  They
     are not "invalid" blocks; they're "bad" ones.

 (c) Tweak the "nand info" command to handle the "no arguments"
     case sanely (show everything, instead of showing garbage) and
     not listing the blocksize in hex kbytes (duh).

git-svn-id: svn://svn.berlios.de/openocd/trunk@1904 b42882b7-edfa-0310-969c-e2dbd0fdcd60

doc/openocd.texi
src/flash/nand.c
src/target/board/sheevaplug.cfg

index 8cea8b0c3dbfcfb4e6db606c269b0b8ca324967b..995d0ec2e78cac8cd02a0cfbed2c8cbc0b34184d 100644 (file)
@@ -2616,6 +2616,15 @@ boot loader, operating system, or other data needed to initialize or
 de-brick a board.
 @end enumerate
 
+@b{NOTE:} At the time this text was written, the largest NAND
+flash fully supported by OpenOCD is 2 GiBytes (16 GiBits).
+This is because the variables used to hold offsets and lengths
+are only 32 bits wide.
+(Larger chips may work in some cases, unless an offset or length
+is larger than 0xffffffff, the largest 32-bit unsigned integer.)
+Some larger devices will work, since they are actually multi-chip
+modules with two smaller chips and individual chipselect lines.
+
 @section NAND Configuration Commands
 @cindex NAND configuration
 
@@ -2702,9 +2711,19 @@ spare areas associated with each data page.
 @end itemize
 @end deffn
 
-@deffn Command {nand erase} num ...
+@deffn Command {nand erase} num offset length
 @cindex NAND erasing
-@b{NOTE:} Syntax is in flux.
+Erases blocks on the specified NAND device, starting at the
+specified @var{offset} and continuing for @var{length} bytes.
+Both of those values must be exact multiples of the device's
+block size, and the region they specify must fit entirely in the chip.
+The @var{num} parameter is the value shown by @command{nand list}.
+
+@b{NOTE:} This command will try to erase bad blocks, when told
+to do so, which will probably invalidate the manufacturer's bad
+block marker.
+For the remainder of the current server session, @command{nand info}
+will still report that the block ``is'' bad.
 @end deffn
 
 @deffn Command {nand write} num filename offset [option...]
@@ -2768,8 +2787,18 @@ the underlying driver from applying hardware ECC.
 @section Other NAND commands
 @cindex NAND other commands
 
-@deffn Command {nand check_bad} num ...
-@b{NOTE:} Syntax is in flux.
+@deffn Command {nand check_bad_blocks} [offset length]
+Checks for manufacturer bad block markers on the specified NAND
+device.  If no parameters are provided, checks the whole
+device; otherwise, starts at the specified @var{offset} and
+continues for @var{length} bytes.
+Both of those values must be exact multiples of the device's
+block size, and the region they specify must fit entirely in the chip.
+The @var{num} parameter is the value shown by @command{nand list}.
+
+@b{NOTE:} Before using this command you should force raw access
+with @command{nand raw_access enable} to ensure that the underlying
+driver will not try to apply hardware ECC.
 @end deffn
 
 @deffn Command {nand info} num
index 4046011635ab0cd7d3ad3b163babe71b0e9dcce3..25880a30f52726f80d1c34aeed040eacdd718be7 100644 (file)
@@ -309,12 +309,12 @@ int nand_init(struct command_context_s *cmd_ctx)
                register_command(cmd_ctx, nand_cmd, "probe", handle_nand_probe_command, COMMAND_EXEC,
                                                 "identify NAND flash device <num>");
                register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC,
-                                                "check NAND flash device <num> for bad blocks [<first> <last>]");
+                                                "check NAND flash device <num> for bad blocks [<offset> <length>]");
                register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC,
-                                                "erase blocks on NAND flash device <num> <first> <last>");
+                                                "erase blocks on NAND flash device <num> <offset> <length>");
                register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC,
                                                 "dump from NAND flash device <num> <filename> "
-                                                "<offset> <size> [oob_raw|oob_only]");
+                                                "<offset> <length> [oob_raw|oob_only]");
                register_command(cmd_ctx, nand_cmd, "write", handle_nand_write_command, COMMAND_EXEC,
                                                 "write to NAND flash device <num> <filename> <offset> [oob_raw|oob_only|oob_softecc|oob_softecc_kw]");
                register_command(cmd_ctx, nand_cmd, "raw_access", handle_nand_raw_access_command, COMMAND_EXEC,
@@ -360,7 +360,7 @@ static int nand_build_bbt(struct nand_device_s *device, int first, int last)
                        || (((device->page_size == 512) && (oob[5] != 0xff)) ||
                                ((device->page_size == 2048) && (oob[0] != 0xff))))
                {
-                       LOG_WARNING("invalid block: %i", i);
+                       LOG_WARNING("bad block: %i", i);
                        device->blocks[i].is_bad = 1;
                }
                else
@@ -1093,20 +1093,20 @@ static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd
        int first = -1;
        int last = -1;
 
-       if ((argc < 1) || (argc > 3))
-       {
+       switch (argc) {
+       default:
                return ERROR_COMMAND_SYNTAX_ERROR;
-
-       }
-
-       if (argc == 2)
-       {
+       case 1:
+               first = 0;
+               last = INT32_MAX;
+               break;
+       case 2:
                first = last = strtoul(args[1], NULL, 0);
-       }
-       else if (argc == 3)
-       {
+               break;
+       case 3:
                first = strtoul(args[1], NULL, 0);
                last = strtoul(args[2], NULL, 0);
+               break;
        }
 
        p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
@@ -1141,7 +1141,7 @@ static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd
                                else
                                        bad_state = " (block condition unknown)";
 
-                               command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s%s",
+                               command_print(cmd_ctx, "\t#%i: 0x%8.8x (%dkB) %s%s",
                                                        j, p->blocks[j].offset, p->blocks[j].size / 1024,
                                                        erase_state, bad_state);
                        }
@@ -1203,12 +1203,31 @@ static int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cm
        p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
        if (p)
        {
-               int first = strtoul(args[1], NULL, 0);
-               int last = strtoul(args[2], NULL, 0);
+               char *cp;
+               unsigned long offset;
+               unsigned long length;
+
+               offset = strtoul(args[1], &cp, 0);
+               if (*cp || offset == ULONG_MAX || offset % p->erase_size)
+               {
+                       return ERROR_INVALID_ARGUMENTS;
+               }
+               offset /= p->erase_size;
+
+               length = strtoul(args[2], &cp, 0);
+               if (*cp || length == ULONG_MAX || length % p->erase_size)
+               {
+                       return ERROR_INVALID_ARGUMENTS;
+               }
+               length -= 1;
+               length /= p->erase_size;
 
-               if ((retval = nand_erase(p, first, last)) == ERROR_OK)
+               retval = nand_erase(p, offset, offset + length);
+               if (retval == ERROR_OK)
                {
-                       command_print(cmd_ctx, "successfully erased blocks %i to %i on NAND flash device '%s'", first, last, p->device->name);
+                       command_print(cmd_ctx, "successfully erased blocks "
+                                       "%lu to %lu on NAND flash device '%s'",
+                                       offset, offset + length, p->device->name);
                }
                else if (retval == ERROR_NAND_OPERATION_FAILED)
                {
@@ -1240,31 +1259,53 @@ int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char
 
        }
 
-       if (argc == 3)
-       {
-               first = strtoul(args[1], NULL, 0);
-               last = strtoul(args[2], NULL, 0);
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (!p) {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds",
+                               args[0]);
+               return ERROR_INVALID_ARGUMENTS;
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
-       if (p)
+       if (argc == 3)
        {
-               if ((retval = nand_build_bbt(p, first, last)) == ERROR_OK)
-               {
-                       command_print(cmd_ctx, "checked NAND flash device for bad blocks, use \"nand info\" command to list blocks");
-               }
-               else if (retval == ERROR_NAND_OPERATION_FAILED)
+               char *cp;
+               unsigned long offset;
+               unsigned long length;
+
+               offset = strtoul(args[1], &cp, 0);
+               if (*cp || offset == ULONG_MAX || offset % p->erase_size)
                {
-                       command_print(cmd_ctx, "error when checking for bad blocks on NAND flash device");
+                       return ERROR_INVALID_ARGUMENTS;
                }
-               else
+               offset /= p->erase_size;
+
+               length = strtoul(args[2], &cp, 0);
+               if (*cp || length == ULONG_MAX || length % p->erase_size)
                {
-                       command_print(cmd_ctx, "unknown error when checking for bad blocks on NAND flash device");
+                       return ERROR_INVALID_ARGUMENTS;
                }
+               length -= 1;
+               length /= p->erase_size;
+
+               first = offset;
+               last = offset + length;
+       }
+
+       retval = nand_build_bbt(p, first, last);
+       if (retval == ERROR_OK)
+       {
+               command_print(cmd_ctx, "checked NAND flash device for bad blocks, "
+                               "use \"nand info\" command to list blocks");
+       }
+       else if (retval == ERROR_NAND_OPERATION_FAILED)
+       {
+               command_print(cmd_ctx, "error when checking for bad blocks on "
+                               "NAND flash device");
        }
        else
        {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+               command_print(cmd_ctx, "unknown error when checking for bad "
+                               "blocks on NAND flash device");
        }
 
        return ERROR_OK;
index 276d6f2462023acf97acbf5a289c19806105399b..61d324d0b283fdc6d86c2608c04ed3fb65a85be3 100644 (file)
@@ -98,7 +98,7 @@ proc sheevaplug_reflash_uboot { } {
        # reflash the u-Boot binary and reboot into it
        sheevaplug_init
        nand probe 0
-       nand erase 0 0 4
+       nand erase 0 0x0 0xa0000
        nand write 0 uboot.bin 0 oob_softecc_kw
        resume