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>
master
Scott Wood 12 years ago committed by Scott Wood
parent f50bf50d7f
commit 418396e212
  1. 95
      common/cmd_nand.c
  2. 16
      doc/README.nand

@ -11,7 +11,7 @@
* Added 16-bit nand support * Added 16-bit nand support
* (C) 2004 Texas Instruments * (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 * 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 * 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 * 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); 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 do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{ {
int i, ret = 0; 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) { if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
size_t rwsize; size_t rwsize;
ulong pagecount = 1;
int read; int read;
int raw;
if (argc < 4) if (argc < 4)
goto usage; 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 */ read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
printf("\nNAND %s: ", read ? "read" : "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]; nand = &nand_info[dev];
rwsize = size;
s = strchr(cmd, '.'); 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") || if (!s || !strcmp(s, ".jffs2") ||
!strcmp(s, ".e") || !strcmp(s, ".i")) { !strcmp(s, ".e") || !strcmp(s, ".i")) {
if (read) if (read)
@ -609,7 +669,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
return 1; return 1;
} }
ret = nand_write_skip_bad(nand, off, &rwsize, ret = nand_write_skip_bad(nand, off, &rwsize,
(u_char *)addr, WITH_YAFFS_OOB); (u_char *)addr,
WITH_INLINE_OOB);
#endif #endif
} else if (!strcmp(s, ".oob")) { } else if (!strcmp(s, ".oob")) {
/* out-of-band data */ /* 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); ret = nand->read_oob(nand, off, &ops);
else else
ret = nand->write_oob(nand, off, &ops); ret = nand->write_oob(nand, off, &ops);
} else if (!strcmp(s, ".raw")) { } else if (raw) {
/* Raw access */ ret = raw_access(nand, addr, off, pagecount, read);
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 { } else {
printf("Unknown nand command suffix '%s'.\n", s); printf("Unknown nand command suffix '%s'.\n", s);
return 1; return 1;
@ -732,9 +779,9 @@ U_BOOT_CMD(
"nand write - addr off|partition size\n" "nand write - addr off|partition size\n"
" read/write 'size' bytes starting at offset 'off'\n" " read/write 'size' bytes starting at offset 'off'\n"
" to/from memory address 'addr', skipping bad blocks.\n" " to/from memory address 'addr', skipping bad blocks.\n"
"nand read.raw - addr off|partition\n" "nand read.raw - addr off|partition [count]\n"
"nand write.raw - addr off|partition\n" "nand write.raw - addr off|partition [count]\n"
" Use read.raw/write.raw to avoid ECC and access the page as-is.\n" " Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
#ifdef CONFIG_CMD_NAND_TRIMFFS #ifdef CONFIG_CMD_NAND_TRIMFFS
"nand write.trimffs - addr off|partition size\n" "nand write.trimffs - addr off|partition size\n"
" write 'size' bytes starting at offset 'off' from memory address\n" " write 'size' bytes starting at offset 'off' from memory address\n"

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

Loading…
Cancel
Save