David Brownell <david-b@pacbell.net>:

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
This commit is contained in:
zwelch 2009-05-24 01:57:13 +00:00
parent c0fc8f93f1
commit eb385b2e70
3 changed files with 109 additions and 39 deletions

View 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

View 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;
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;

View 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