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"