From eb385b2e7086cd0bb97d99f8253ae16579394663 Mon Sep 17 00:00:00 2001 From: zwelch Date: Sun, 24 May 2009 01:57:13 +0000 Subject: [PATCH] David Brownell : 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 | 37 +++++++++-- src/flash/nand.c | 109 ++++++++++++++++++++++---------- src/target/board/sheevaplug.cfg | 2 +- 3 files changed, 109 insertions(+), 39 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 8cea8b0c3..995d0ec2e 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -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 diff --git a/src/flash/nand.c b/src/flash/nand.c index 404601163..25880a30f 100644 --- a/src/flash/nand.c +++ b/src/flash/nand.c @@ -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 "); register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC, - "check NAND flash device for bad blocks [ ]"); + "check NAND flash device for bad blocks [ ]"); register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC, - "erase blocks on NAND flash device "); + "erase blocks on NAND flash device "); register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC, "dump from NAND flash device " - " [oob_raw|oob_only]"); + " [oob_raw|oob_only]"); register_command(cmd_ctx, nand_cmd, "write", handle_nand_write_command, COMMAND_EXEC, "write to NAND flash device [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; - if ((retval = nand_erase(p, first, last)) == ERROR_OK) + offset = strtoul(args[1], &cp, 0); + if (*cp || offset == ULONG_MAX || offset % p->erase_size) { - command_print(cmd_ctx, "successfully erased blocks %i to %i on NAND flash device '%s'", first, last, p->device->name); + 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; + + retval = nand_erase(p, offset, offset + length); + if (retval == ERROR_OK) + { + 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) + 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, "checked NAND flash device for bad blocks, use \"nand info\" command to list blocks"); + return ERROR_INVALID_ARGUMENTS; } - else if (retval == ERROR_NAND_OPERATION_FAILED) + offset /= p->erase_size; + + length = strtoul(args[2], &cp, 0); + if (*cp || length == ULONG_MAX || length % p->erase_size) { - command_print(cmd_ctx, "error when checking for bad blocks on NAND flash device"); - } - else - { - 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; diff --git a/src/target/board/sheevaplug.cfg b/src/target/board/sheevaplug.cfg index 276d6f246..61d324d0b 100644 --- a/src/target/board/sheevaplug.cfg +++ b/src/target/board/sheevaplug.cfg @@ -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