summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot-nand.lds5
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds4
-rw-r--r--common/cmd_nand.c95
-rw-r--r--doc/README.nand16
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c22
-rw-r--r--drivers/mtd/nand/nand_base.c5
-rw-r--r--drivers/mtd/nand/nand_bbt.c13
-rw-r--r--drivers/mtd/nand/nand_util.c2
8 files changed, 113 insertions, 49 deletions
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds b/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds
index b1a1dac..8ba9399 100644
--- a/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds
+++ b/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds
@@ -51,13 +51,14 @@ SECTIONS
PROVIDE (erotext = .);
.reloc :
{
- KEEP(*(.got))
_GOT2_TABLE_ = .;
KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
_FIXUP_TABLE_ = .;
KEEP(*(.fixup))
}
- __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
__fixup_entries = (. - _FIXUP_TABLE_) >> 2;
.data :
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds
index 852f9aa..668158f 100644
--- a/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds
+++ b/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds
@@ -37,10 +37,12 @@ SECTIONS
.reloc : {
_GOT2_TABLE_ = .;
KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
_FIXUP_TABLE_ = .;
KEEP(*(.fixup))
}
- __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
__fixup_entries = (. - _FIXUP_TABLE_) >> 2;
. = ALIGN(8);
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 0fd3a6c..f060a31 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -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"
diff --git a/doc/README.nand b/doc/README.nand
index 04a87c9..1602b5e 100644
--- a/doc/README.nand
+++ b/doc/README.nand
@@ -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:
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 5cac78b..b3b7c70 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -384,19 +384,30 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* READID must read all possible bytes while CEB is active */
case NAND_CMD_READID:
+ case NAND_CMD_PARAM: {
+ int timing = IFC_FIR_OP_RB;
+ if (command == NAND_CMD_PARAM)
+ timing = IFC_FIR_OP_RBCD;
+
out_be32(&ifc->ifc_nand.nand_fir0,
(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
- (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+ (timing << IFC_NAND_FIR0_OP2_SHIFT));
out_be32(&ifc->ifc_nand.nand_fcr0,
- NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
- /* 4 bytes for manuf, device and exts */
- out_be32(&ifc->ifc_nand.nand_fbcr, 4);
- ctrl->read_bytes = 4;
+ command << IFC_NAND_FCR0_CMD0_SHIFT);
+ out_be32(&ifc->ifc_nand.row3, column);
+
+ /*
+ * although currently it's 8 bytes for READID, we always read
+ * the maximum 256 bytes(for PARAM)
+ */
+ out_be32(&ifc->ifc_nand.nand_fbcr, 256);
+ ctrl->read_bytes = 256;
set_addr(mtd, 0, 0, 0);
fsl_ifc_run_command(mtd);
return;
+ }
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1:
@@ -764,6 +775,7 @@ int board_nand_init(struct nand_chip *nand)
if (priv->bank >= MAX_BANKS) {
printf("%s: address did not match any "
"chip selects\n", __func__);
+ kfree(priv);
return -ENODEV;
}
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index bef79be..bfd668f 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2530,13 +2530,14 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
return 0;
- printk(KERN_INFO "ONFI flash detected\n");
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "ONFI flash detected\n");
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
for (i = 0; i < 3; i++) {
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
le16_to_cpu(p->crc)) {
- printk(KERN_INFO "ONFI param page %d valid\n", i);
+ MTDDEBUG(MTD_DEBUG_LEVEL0,
+ "ONFI param page %d valid\n", i);
break;
}
}
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index dc6c648..74a7061 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -259,10 +259,10 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
mtd->ecc_stats.bbtblocks++;
continue;
}
- /* Leave it for now, if its matured we can move this
- * message to MTD_DEBUG_LEVEL0 */
- printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "nand_read_bbt: " \
+ "Bad block at 0x%012llx\n",
+ (loff_t)((offs << 2) + (act >> 1))
+ << this->bbt_erase_shift);
/* Factory marked bad or worn out ? */
if (tmp == 0)
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -651,8 +651,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
if (td->pages[i] == -1)
printk(KERN_WARNING "Bad block table not found for chip %d\n", i);
else
- printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i],
- td->version[i]);
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "Bad block table found " \
+ "at page %d, version 0x%02X\n", td->pages[i],
+ td->version[i]);
}
return 0;
}
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 60c778e..7ed8b18 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -564,7 +564,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
ops.oobbuf = ops.datbuf + pagesize;
rval = nand->write_oob(nand, offset, &ops);
- if (!rval)
+ if (rval != 0)
break;
offset += pagesize;