Merge branch 'master' of git://git.denx.de/u-boot-nand-flash

* 'master' of git://git.denx.de/u-boot-nand-flash:
  NAND: Remove ONFI detection message to from bootup log
  driver/mtd:IFC: Fix possible memory leak
  driver/mtd: IFC NAND: Add support of ONFI NAND flash
  mtd, nand: move some printfs to debug output.
  nand_util: correct YAFFS image write function
  powerpc/85xx: fix NAND boot linker scripts for -fpic
  nand: extend .raw accesses to work on multiple pages
This commit is contained in:
Wolfgang Denk 2012-05-20 22:47:40 +02:00
commit 8fa3d2b816
8 changed files with 113 additions and 49 deletions

View File

@ -51,13 +51,14 @@ SECTIONS
PROVIDE (erotext = .); PROVIDE (erotext = .);
.reloc : .reloc :
{ {
KEEP(*(.got))
_GOT2_TABLE_ = .; _GOT2_TABLE_ = .;
KEEP(*(.got2)) KEEP(*(.got2))
KEEP(*(.got))
PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
_FIXUP_TABLE_ = .; _FIXUP_TABLE_ = .;
KEEP(*(.fixup)) KEEP(*(.fixup))
} }
__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
__fixup_entries = (. - _FIXUP_TABLE_) >> 2; __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
.data : .data :

View File

@ -37,10 +37,12 @@ SECTIONS
.reloc : { .reloc : {
_GOT2_TABLE_ = .; _GOT2_TABLE_ = .;
KEEP(*(.got2)) KEEP(*(.got2))
KEEP(*(.got))
PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
_FIXUP_TABLE_ = .; _FIXUP_TABLE_ = .;
KEEP(*(.fixup)) KEEP(*(.fixup))
} }
__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
__fixup_entries = (. - _FIXUP_TABLE_) >> 2; __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
. = ALIGN(8); . = ALIGN(8);

View File

@ -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"

View File

@ -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:

View File

@ -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 */ /* READID must read all possible bytes while CEB is active */
case NAND_CMD_READID: 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, out_be32(&ifc->ifc_nand.nand_fir0,
(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_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, out_be32(&ifc->ifc_nand.nand_fcr0,
NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); command << IFC_NAND_FCR0_CMD0_SHIFT);
/* 4 bytes for manuf, device and exts */ out_be32(&ifc->ifc_nand.row3, column);
out_be32(&ifc->ifc_nand.nand_fbcr, 4);
ctrl->read_bytes = 4; /*
* 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); set_addr(mtd, 0, 0, 0);
fsl_ifc_run_command(mtd); fsl_ifc_run_command(mtd);
return; return;
}
/* ERASE1 stores the block and page address */ /* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1: case NAND_CMD_ERASE1:
@ -764,6 +775,7 @@ int board_nand_init(struct nand_chip *nand)
if (priv->bank >= MAX_BANKS) { if (priv->bank >= MAX_BANKS) {
printf("%s: address did not match any " printf("%s: address did not match any "
"chip selects\n", __func__); "chip selects\n", __func__);
kfree(priv);
return -ENODEV; return -ENODEV;
} }

View File

@ -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') chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
return 0; 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); chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
le16_to_cpu(p->crc)) { 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; break;
} }
} }

View File

@ -259,10 +259,10 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
mtd->ecc_stats.bbtblocks++; mtd->ecc_stats.bbtblocks++;
continue; continue;
} }
/* Leave it for now, if its matured we can move this MTDDEBUG(MTD_DEBUG_LEVEL0, "nand_read_bbt: " \
* message to MTD_DEBUG_LEVEL0 */ "Bad block at 0x%012llx\n",
printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1))
(loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); << this->bbt_erase_shift);
/* Factory marked bad or worn out ? */ /* Factory marked bad or worn out ? */
if (tmp == 0) if (tmp == 0)
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); 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) if (td->pages[i] == -1)
printk(KERN_WARNING "Bad block table not found for chip %d\n", i); printk(KERN_WARNING "Bad block table not found for chip %d\n", i);
else else
printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], MTDDEBUG(MTD_DEBUG_LEVEL0, "Bad block table found " \
td->version[i]); "at page %d, version 0x%02X\n", td->pages[i],
td->version[i]);
} }
return 0; return 0;
} }

View File

@ -564,7 +564,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
ops.oobbuf = ops.datbuf + pagesize; ops.oobbuf = ops.datbuf + pagesize;
rval = nand->write_oob(nand, offset, &ops); rval = nand->write_oob(nand, offset, &ops);
if (!rval) if (rval != 0)
break; break;
offset += pagesize; offset += pagesize;