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).
---
doc/openocd.texi | 37 +++++++++++-
src/flash/nand.c | 109 ++++++++++++++++++++++++++------------
src/target/board/sheevaplug.cfg | 2
3 files changed, 109 insertions(+), 39 deletions(-)
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).
---
doc/openocd.texi | 37 +++++++++++-
src/flash/nand.c | 109 ++++++++++++++++++++++++++------------
src/target/board/sheevaplug.cfg | 2
3 files changed, 109 insertions(+), 39 deletions(-)
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -2596,6 +2596,15 @@ boot loader, operating system, or other
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
@@ -2682,9 +2691,19 @@ spare areas associated with each data pa
@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...]
@@ -2748,8 +2767,18 @@ the underlying driver from applying hard
@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
--- a/src/flash/nand.c
+++ b/src/flash/nand.c
@@ -309,12 +309,12 @@ int nand_init(struct command_context_s *
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_de
|| (((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(stru
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(stru
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(str
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
}
- 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;
--- 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
_______________________________________________
Openocd-development mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development