nand: extend .raw accesses to work on multiple pages

A use for this is to read, modify, erase, and write an entire block as a
single unit, as a replacement for the biterr command.  This way gives
more flexibility in that you can also test multiple bit errors, errors
in the ECC, etc.

Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
Scott Wood 2012-03-02 14:01:57 -06:00 committed by Scott Wood
parent f50bf50d7f
commit 418396e212
2 changed files with 79 additions and 32 deletions

View file

@ -11,7 +11,7 @@
* Added 16-bit nand support
* (C) 2004 Texas Instruments
*
* Copyright 2010 Freescale Semiconductor
* Copyright 2010, 2012 Freescale Semiconductor
* The portions of this file whose copyright is held by Freescale and which
* are not considered a derived work of GPL v2-only code may be distributed
* and/or modified under the terms of the GNU General Public License as
@ -390,6 +390,41 @@ static void nand_print_and_set_info(int idx)
setenv("nand_erasesize", buf);
}
static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
int read)
{
int ret = 0;
size_t rwsize;
while (count--) {
/* Raw access */
mtd_oob_ops_t ops = {
.datbuf = (u8 *)addr,
.oobbuf = ((u8 *)addr) + nand->writesize,
.len = nand->writesize,
.ooblen = nand->oobsize,
.mode = MTD_OOB_RAW
};
rwsize = nand->writesize + nand->oobsize;
if (read)
ret = nand->read_oob(nand, off, &ops);
else
ret = nand->write_oob(nand, off, &ops);
if (ret) {
printf("%s: error at offset %llx, ret %d\n",
__func__, (long long)off, ret);
break;
}
addr += nand->writesize + nand->oobsize;
off += nand->writesize;
}
return ret;
}
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
int i, ret = 0;
@ -568,7 +603,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
size_t rwsize;
ulong pagecount = 1;
int read;
int raw;
if (argc < 4)
goto usage;
@ -577,13 +614,36 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const 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, &dev, &off, &size) != 0)
return 1;
nand = &nand_info[dev];
rwsize = size;
s = strchr(cmd, '.');
if (!strcmp(s, ".raw")) {
raw = 1;
if (arg_off(argv[3], &dev, &off, &size))
return 1;
if (argc > 4 && !str2long(argv[4], &pagecount)) {
printf("'%s' is not a number\n", argv[4]);
return 1;
}
if (pagecount * nand->writesize > size) {
puts("Size exceeds partition or device limit\n");
return -1;
}
rwsize = pagecount * (nand->writesize + nand->oobsize);
} else {
if (arg_off_size(argc - 3, argv + 3, &dev,
&off, &size) != 0)
return 1;
rwsize = size;
}
if (!s || !strcmp(s, ".jffs2") ||
!strcmp(s, ".e") || !strcmp(s, ".i")) {
if (read)
@ -609,7 +669,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
return 1;
}
ret = nand_write_skip_bad(nand, off, &rwsize,
(u_char *)addr, WITH_YAFFS_OOB);
(u_char *)addr,
WITH_INLINE_OOB);
#endif
} else if (!strcmp(s, ".oob")) {
/* out-of-band data */
@ -623,22 +684,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
ret = nand->read_oob(nand, off, &ops);
else
ret = nand->write_oob(nand, off, &ops);
} else if (!strcmp(s, ".raw")) {
/* Raw access */
mtd_oob_ops_t ops = {
.datbuf = (u8 *)addr,
.oobbuf = ((u8 *)addr) + nand->writesize,
.len = nand->writesize,
.ooblen = nand->oobsize,
.mode = MTD_OOB_RAW
};
rwsize = nand->writesize + nand->oobsize;
if (read)
ret = nand->read_oob(nand, off, &ops);
else
ret = nand->write_oob(nand, off, &ops);
} else if (raw) {
ret = raw_access(nand, addr, off, pagecount, read);
} else {
printf("Unknown nand command suffix '%s'.\n", s);
return 1;
@ -732,9 +779,9 @@ U_BOOT_CMD(
"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 read.raw - addr off|partition\n"
"nand write.raw - addr off|partition\n"
" Use read.raw/write.raw to avoid ECC and access the page as-is.\n"
"nand read.raw - addr off|partition [count]\n"
"nand write.raw - addr off|partition [count]\n"
" Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
#ifdef CONFIG_CMD_NAND_TRIMFFS
"nand write.trimffs - addr off|partition size\n"
" write 'size' bytes starting at offset 'off' from memory address\n"

View file

@ -94,14 +94,14 @@ Commands:
of data for one 512-byte page or 2 256-byte pages. There is no check
for bad blocks.
nand read.raw addr ofs|partition
Read page from `ofs' in NAND flash to `addr'. This reads the raw page,
so ECC is avoided and the OOB area is read as well.
nand write.raw addr ofs|partition
Write page from `addr' to `ofs' in NAND flash. This writes the raw page,
so ECC is avoided and the OOB area is written as well, making the whole
page written as-is.
nand read.raw addr ofs|partition [count]
nand write.raw addr ofs|partition [count]
Read or write one or more pages at "ofs" in NAND flash, from or to
"addr" in memory. This is a raw access, so ECC is avoided and the
OOB area is transferred as well. If count is absent, it is assumed
to be one page. As with .yaffs2 accesses, the data is formatted as
a packed sequence of "data, oob, data, oob, ..." -- no alignment of
individual pages is maintained.
Configuration Options: