mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
mtd: resync with Linux-3.7.1
This patch is essentially an update of u-boot MTD subsystem to the state of Linux-3.7.1 with exclusion of some bits: - the update is concentrated on NAND, no onenand or CFI/NOR/SPI flashes interfaces are updated EXCEPT for API changes. - new large NAND chips support is there, though some updates have got in Linux-3.8.-rc1, (which will follow on top of this patch). To produce this update I used tag v3.7.1 of linux-stable repository. The update was made using application of relevant patches, with changes relevant to U-Boot-only stuff sticked together to keep bisectability. Then all changes were grouped together to this patch. Signed-off-by: Sergey Lapin <slapin@ossfans.org> [scottwood@freescale.com: some eccstrength and build fixes] Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
parent
a1b81ab26f
commit
dfe64e2c89
48 changed files with 2204 additions and 1702 deletions
|
@ -120,7 +120,7 @@ int board_eth_init(bd_t *bis)
|
||||||
#ifdef CONFIG_NAND_DAVINCI
|
#ifdef CONFIG_NAND_DAVINCI
|
||||||
static int
|
static int
|
||||||
davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint8_t *buf, int page)
|
uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
int i, eccsize = chip->ecc.size;
|
int i, eccsize = chip->ecc.size;
|
||||||
|
@ -167,8 +167,9 @@ davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void davinci_std_write_page_syndrome(struct mtd_info *mtd,
|
static int davinci_std_write_page_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, const uint8_t *buf)
|
struct nand_chip *chip, const uint8_t *buf,
|
||||||
|
int oob_required)
|
||||||
{
|
{
|
||||||
unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE];
|
unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE];
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -218,6 +219,7 @@ static void davinci_std_write_page_syndrome(struct mtd_info *mtd,
|
||||||
i = mtd->oobsize - (oob - chip->oob_poi);
|
i = mtd->oobsize - (oob - chip->oob_poi);
|
||||||
if (i)
|
if (i)
|
||||||
chip->write_buf(mtd, oob, i);
|
chip->write_buf(mtd, oob, i);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int davinci_std_write_oob_syndrome(struct mtd_info *mtd,
|
static int davinci_std_write_oob_syndrome(struct mtd_info *mtd,
|
||||||
|
@ -239,7 +241,7 @@ static int davinci_std_write_oob_syndrome(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int davinci_std_read_oob_syndrome(struct mtd_info *mtd,
|
static int davinci_std_read_oob_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, int page, int sndcmd)
|
struct nand_chip *chip, int page)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
uint8_t *buf = chip->oob_poi;
|
uint8_t *buf = chip->oob_poi;
|
||||||
|
@ -249,7 +251,7 @@ static int davinci_std_read_oob_syndrome(struct mtd_info *mtd,
|
||||||
|
|
||||||
chip->read_buf(mtd, bufpoi, mtd->oobsize);
|
chip->read_buf(mtd, bufpoi, mtd->oobsize);
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip)
|
static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip)
|
||||||
|
|
|
@ -62,8 +62,8 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
|
||||||
ops.oobbuf = oobbuf;
|
ops.oobbuf = oobbuf;
|
||||||
ops.len = nand->writesize;
|
ops.len = nand->writesize;
|
||||||
ops.ooblen = nand->oobsize;
|
ops.ooblen = nand->oobsize;
|
||||||
ops.mode = MTD_OOB_RAW;
|
ops.mode = MTD_OPS_RAW;
|
||||||
i = nand->read_oob(nand, addr, &ops);
|
i = mtd_read_oob(nand, addr, &ops);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
printf("Error (%d) reading page %08lx\n", i, off);
|
printf("Error (%d) reading page %08lx\n", i, off);
|
||||||
free(datbuf);
|
free(datbuf);
|
||||||
|
@ -404,13 +404,13 @@ static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
|
||||||
.oobbuf = ((u8 *)addr) + nand->writesize,
|
.oobbuf = ((u8 *)addr) + nand->writesize,
|
||||||
.len = nand->writesize,
|
.len = nand->writesize,
|
||||||
.ooblen = nand->oobsize,
|
.ooblen = nand->oobsize,
|
||||||
.mode = MTD_OOB_RAW
|
.mode = MTD_OPS_RAW
|
||||||
};
|
};
|
||||||
|
|
||||||
if (read)
|
if (read)
|
||||||
ret = nand->read_oob(nand, off, &ops);
|
ret = mtd_read_oob(nand, off, &ops);
|
||||||
else
|
else
|
||||||
ret = nand->write_oob(nand, off, &ops);
|
ret = mtd_write_oob(nand, off, &ops);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("%s: error at offset %llx, ret %d\n",
|
printf("%s: error at offset %llx, ret %d\n",
|
||||||
|
@ -715,13 +715,13 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
mtd_oob_ops_t ops = {
|
mtd_oob_ops_t ops = {
|
||||||
.oobbuf = (u8 *)addr,
|
.oobbuf = (u8 *)addr,
|
||||||
.ooblen = rwsize,
|
.ooblen = rwsize,
|
||||||
.mode = MTD_OOB_RAW
|
.mode = MTD_OPS_RAW
|
||||||
};
|
};
|
||||||
|
|
||||||
if (read)
|
if (read)
|
||||||
ret = nand->read_oob(nand, off, &ops);
|
ret = mtd_read_oob(nand, off, &ops);
|
||||||
else
|
else
|
||||||
ret = nand->write_oob(nand, off, &ops);
|
ret = mtd_write_oob(nand, off, &ops);
|
||||||
} else if (raw) {
|
} else if (raw) {
|
||||||
ret = raw_access(nand, addr, off, pagecount, read);
|
ret = raw_access(nand, addr, off, pagecount, read);
|
||||||
} else {
|
} else {
|
||||||
|
@ -764,7 +764,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
addr = simple_strtoul(*argv, NULL, 16);
|
addr = simple_strtoul(*argv, NULL, 16);
|
||||||
|
|
||||||
if (nand->block_markbad(nand, addr)) {
|
if (mtd_block_markbad(nand, addr)) {
|
||||||
printf("block 0x%08lx NOT marked "
|
printf("block 0x%08lx NOT marked "
|
||||||
"as bad! ERROR %d\n",
|
"as bad! ERROR %d\n",
|
||||||
addr, ret);
|
addr, ret);
|
||||||
|
|
|
@ -83,7 +83,7 @@ static int onenand_block_read(loff_t from, size_t len,
|
||||||
ops.len = blocksize;
|
ops.len = blocksize;
|
||||||
|
|
||||||
while (blocks) {
|
while (blocks) {
|
||||||
ret = mtd->block_isbad(mtd, ofs);
|
ret = mtd_block_isbad(mtd, ofs);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk("Bad blocks %d at 0x%x\n",
|
printk("Bad blocks %d at 0x%x\n",
|
||||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||||
|
@ -97,7 +97,7 @@ static int onenand_block_read(loff_t from, size_t len,
|
||||||
ops.datbuf = buf;
|
ops.datbuf = buf;
|
||||||
|
|
||||||
ops.retlen = 0;
|
ops.retlen = 0;
|
||||||
ret = mtd->read_oob(mtd, ofs, &ops);
|
ret = mtd_read_oob(mtd, ofs, &ops);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
|
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
|
||||||
ofs += blocksize;
|
ofs += blocksize;
|
||||||
|
@ -118,7 +118,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
|
||||||
struct mtd_oob_ops ops = {
|
struct mtd_oob_ops ops = {
|
||||||
.len = mtd->writesize,
|
.len = mtd->writesize,
|
||||||
.ooblen = mtd->oobsize,
|
.ooblen = mtd->oobsize,
|
||||||
.mode = MTD_OOB_AUTO,
|
.mode = MTD_OPS_AUTO_OOB,
|
||||||
};
|
};
|
||||||
int page, ret = 0;
|
int page, ret = 0;
|
||||||
for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) {
|
for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) {
|
||||||
|
@ -126,7 +126,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
|
||||||
buf += mtd->writesize;
|
buf += mtd->writesize;
|
||||||
ops.oobbuf = (u_char *)buf;
|
ops.oobbuf = (u_char *)buf;
|
||||||
buf += mtd->oobsize;
|
buf += mtd->oobsize;
|
||||||
ret = mtd->write_oob(mtd, to, &ops);
|
ret = mtd_write_oob(mtd, to, &ops);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
to += mtd->writesize;
|
to += mtd->writesize;
|
||||||
|
@ -156,7 +156,7 @@ static int onenand_block_write(loff_t to, size_t len,
|
||||||
ofs = to;
|
ofs = to;
|
||||||
|
|
||||||
while (blocks) {
|
while (blocks) {
|
||||||
ret = mtd->block_isbad(mtd, ofs);
|
ret = mtd_block_isbad(mtd, ofs);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk("Bad blocks %d at 0x%x\n",
|
printk("Bad blocks %d at 0x%x\n",
|
||||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||||
|
@ -165,7 +165,7 @@ static int onenand_block_write(loff_t to, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!withoob)
|
if (!withoob)
|
||||||
ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
|
ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf);
|
||||||
else
|
else
|
||||||
ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
|
ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -195,7 +195,7 @@ static int onenand_block_erase(u32 start, u32 size, int force)
|
||||||
int blocksize = 1 << this->erase_shift;
|
int blocksize = 1 << this->erase_shift;
|
||||||
|
|
||||||
for (ofs = start; ofs < (start + size); ofs += blocksize) {
|
for (ofs = start; ofs < (start + size); ofs += blocksize) {
|
||||||
ret = mtd->block_isbad(mtd, ofs);
|
ret = mtd_block_isbad(mtd, ofs);
|
||||||
if (ret && !force) {
|
if (ret && !force) {
|
||||||
printf("Skip erase bad block %d at 0x%x\n",
|
printf("Skip erase bad block %d at 0x%x\n",
|
||||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||||
|
@ -206,7 +206,7 @@ static int onenand_block_erase(u32 start, u32 size, int force)
|
||||||
instr.len = blocksize;
|
instr.len = blocksize;
|
||||||
instr.priv = force;
|
instr.priv = force;
|
||||||
instr.mtd = mtd;
|
instr.mtd = mtd;
|
||||||
ret = mtd->erase(mtd, &instr);
|
ret = mtd_erase(mtd, &instr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("erase failed block %d at 0x%x\n",
|
printf("erase failed block %d at 0x%x\n",
|
||||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||||
|
@ -261,7 +261,7 @@ static int onenand_block_test(u32 start, u32 size)
|
||||||
while (blocks < end_block) {
|
while (blocks < end_block) {
|
||||||
printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
|
printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||||
|
|
||||||
ret = mtd->block_isbad(mtd, ofs);
|
ret = mtd_block_isbad(mtd, ofs);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Skip erase bad block %d at 0x%x\n",
|
printf("Skip erase bad block %d at 0x%x\n",
|
||||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||||
|
@ -270,19 +270,19 @@ static int onenand_block_test(u32 start, u32 size)
|
||||||
|
|
||||||
instr.addr = ofs;
|
instr.addr = ofs;
|
||||||
instr.len = blocksize;
|
instr.len = blocksize;
|
||||||
ret = mtd->erase(mtd, &instr);
|
ret = mtd_erase(mtd, &instr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk("Erase failed 0x%x, %d\n", (u32)ofs, ret);
|
printk("Erase failed 0x%x, %d\n", (u32)ofs, ret);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mtd->write(mtd, ofs, blocksize, &retlen, buf);
|
ret = mtd_write(mtd, ofs, blocksize, &retlen, buf);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk("Write failed 0x%x, %d\n", (u32)ofs, ret);
|
printk("Write failed 0x%x, %d\n", (u32)ofs, ret);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mtd->read(mtd, ofs, blocksize, &retlen, verify_buf);
|
ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
|
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
|
||||||
goto next;
|
goto next;
|
||||||
|
@ -324,7 +324,7 @@ static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob)
|
||||||
ops.len = mtd->writesize;
|
ops.len = mtd->writesize;
|
||||||
ops.ooblen = mtd->oobsize;
|
ops.ooblen = mtd->oobsize;
|
||||||
ops.retlen = 0;
|
ops.retlen = 0;
|
||||||
i = mtd->read_oob(mtd, addr, &ops);
|
i = mtd_read_oob(mtd, addr, &ops);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
printf("Error (%d) reading page %08lx\n", i, off);
|
printf("Error (%d) reading page %08lx\n", i, off);
|
||||||
free(datbuf);
|
free(datbuf);
|
||||||
|
@ -373,7 +373,7 @@ static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar
|
||||||
/* Currently only one OneNAND device is supported */
|
/* Currently only one OneNAND device is supported */
|
||||||
printf("\nDevice %d bad blocks:\n", 0);
|
printf("\nDevice %d bad blocks:\n", 0);
|
||||||
for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) {
|
for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) {
|
||||||
if (mtd->block_isbad(mtd, ofs))
|
if (mtd_block_isbad(mtd, ofs))
|
||||||
printf(" %08x\n", (u32)ofs);
|
printf(" %08x\n", (u32)ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * cons
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
addr = simple_strtoul(*argv, NULL, 16);
|
addr = simple_strtoul(*argv, NULL, 16);
|
||||||
|
|
||||||
if (mtd->block_markbad(mtd, addr)) {
|
if (mtd_block_markbad(mtd, addr)) {
|
||||||
printf("block 0x%08lx NOT marked "
|
printf("block 0x%08lx NOT marked "
|
||||||
"as bad! ERROR %d\n",
|
"as bad! ERROR %d\n",
|
||||||
addr, ret);
|
addr, ret);
|
||||||
|
|
|
@ -68,7 +68,7 @@ void env_relocate_spec(void)
|
||||||
/* Check OneNAND exist */
|
/* Check OneNAND exist */
|
||||||
if (mtd->writesize)
|
if (mtd->writesize)
|
||||||
/* Ignore read fail */
|
/* Ignore read fail */
|
||||||
mtd->read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
|
mtd_read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
|
||||||
&retlen, (u_char *)buf);
|
&retlen, (u_char *)buf);
|
||||||
else
|
else
|
||||||
mtd->writesize = MAX_ONENAND_PAGESIZE;
|
mtd->writesize = MAX_ONENAND_PAGESIZE;
|
||||||
|
@ -113,12 +113,12 @@ int saveenv(void)
|
||||||
#endif
|
#endif
|
||||||
instr.addr = env_addr;
|
instr.addr = env_addr;
|
||||||
instr.mtd = mtd;
|
instr.mtd = mtd;
|
||||||
if (mtd->erase(mtd, &instr)) {
|
if (mtd_erase(mtd, &instr)) {
|
||||||
printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
|
printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mtd->write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
|
if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
|
||||||
(u_char *)&env_new)) {
|
(u_char *)&env_new)) {
|
||||||
printf("OneNAND: write failed at 0x%llx\n", instr.addr);
|
printf("OneNAND: write failed at 0x%llx\n", instr.addr);
|
||||||
return 2;
|
return 2;
|
||||||
|
|
|
@ -25,7 +25,9 @@ include $(TOPDIR)/config.mk
|
||||||
|
|
||||||
LIB := $(obj)libmtd.o
|
LIB := $(obj)libmtd.o
|
||||||
|
|
||||||
COBJS-$(CONFIG_MTD_DEVICE) += mtdcore.o
|
ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)))
|
||||||
|
COBJS-y += mtdcore.o
|
||||||
|
endif
|
||||||
COBJS-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
|
COBJS-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
|
||||||
COBJS-$(CONFIG_MTD_CONCAT) += mtdconcat.o
|
COBJS-$(CONFIG_MTD_CONCAT) += mtdconcat.o
|
||||||
COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o
|
COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o
|
||||||
|
|
|
@ -244,12 +244,12 @@ int cfi_mtd_init(void)
|
||||||
mtd->size = fi->size;
|
mtd->size = fi->size;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
|
|
||||||
mtd->erase = cfi_mtd_erase;
|
mtd->_erase = cfi_mtd_erase;
|
||||||
mtd->read = cfi_mtd_read;
|
mtd->_read = cfi_mtd_read;
|
||||||
mtd->write = cfi_mtd_write;
|
mtd->_write = cfi_mtd_write;
|
||||||
mtd->sync = cfi_mtd_sync;
|
mtd->_sync = cfi_mtd_sync;
|
||||||
mtd->lock = cfi_mtd_lock;
|
mtd->_lock = cfi_mtd_lock;
|
||||||
mtd->unlock = cfi_mtd_unlock;
|
mtd->_unlock = cfi_mtd_unlock;
|
||||||
mtd->priv = fi;
|
mtd->priv = fi;
|
||||||
|
|
||||||
if (add_mtd_device(mtd))
|
if (add_mtd_device(mtd))
|
||||||
|
|
|
@ -70,14 +70,14 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
/* Entire transaction goes into this subdev */
|
/* Entire transaction goes into this subdev */
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
err = subdev->read(subdev, from, size, &retsize, buf);
|
err = mtd_read(subdev, from, size, &retsize, buf);
|
||||||
|
|
||||||
/* Save information about bitflips! */
|
/* Save information about bitflips! */
|
||||||
if (unlikely(err)) {
|
if (unlikely(err)) {
|
||||||
if (err == -EBADMSG) {
|
if (mtd_is_eccerr(err)) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
ret = err;
|
ret = err;
|
||||||
} else if (err == -EUCLEAN) {
|
} else if (mtd_is_bitflip(err)) {
|
||||||
mtd->ecc_stats.corrected++;
|
mtd->ecc_stats.corrected++;
|
||||||
/* Do not overwrite -EBADMSG !! */
|
/* Do not overwrite -EBADMSG !! */
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -105,9 +105,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
*retlen = 0;
|
*retlen = 0;
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
|
@ -124,11 +121,7 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
else
|
else
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
if (!(subdev->flags & MTD_WRITEABLE))
|
err = mtd_write(subdev, to, size, &retsize, buf);
|
||||||
err = -EROFS;
|
|
||||||
else
|
|
||||||
err = subdev->write(subdev, to, size, &retsize, buf);
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -165,16 +158,16 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||||
if (from + devops.len > subdev->size)
|
if (from + devops.len > subdev->size)
|
||||||
devops.len = subdev->size - from;
|
devops.len = subdev->size - from;
|
||||||
|
|
||||||
err = subdev->read_oob(subdev, from, &devops);
|
err = mtd_read_oob(subdev, from, &devops);
|
||||||
ops->retlen += devops.retlen;
|
ops->retlen += devops.retlen;
|
||||||
ops->oobretlen += devops.oobretlen;
|
ops->oobretlen += devops.oobretlen;
|
||||||
|
|
||||||
/* Save information about bitflips! */
|
/* Save information about bitflips! */
|
||||||
if (unlikely(err)) {
|
if (unlikely(err)) {
|
||||||
if (err == -EBADMSG) {
|
if (mtd_is_eccerr(err)) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
ret = err;
|
ret = err;
|
||||||
} else if (err == -EUCLEAN) {
|
} else if (mtd_is_bitflip(err)) {
|
||||||
mtd->ecc_stats.corrected++;
|
mtd->ecc_stats.corrected++;
|
||||||
/* Do not overwrite -EBADMSG !! */
|
/* Do not overwrite -EBADMSG !! */
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -225,7 +218,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
|
||||||
if (to + devops.len > subdev->size)
|
if (to + devops.len > subdev->size)
|
||||||
devops.len = subdev->size - to;
|
devops.len = subdev->size - to;
|
||||||
|
|
||||||
err = subdev->write_oob(subdev, to, &devops);
|
err = mtd_write_oob(subdev, to, &devops);
|
||||||
ops->retlen += devops.retlen;
|
ops->retlen += devops.retlen;
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -271,7 +264,7 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
|
||||||
* FIXME: Allow INTERRUPTIBLE. Which means
|
* FIXME: Allow INTERRUPTIBLE. Which means
|
||||||
* not having the wait_queue head on the stack.
|
* not having the wait_queue head on the stack.
|
||||||
*/
|
*/
|
||||||
err = mtd->erase(mtd, erase);
|
err = mtd_erase(mtd, erase);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||||
add_wait_queue(&waitq, &wait);
|
add_wait_queue(&waitq, &wait);
|
||||||
|
@ -294,15 +287,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
uint64_t length, offset = 0;
|
uint64_t length, offset = 0;
|
||||||
struct erase_info *erase;
|
struct erase_info *erase;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
if (instr->addr > concat->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (instr->len + instr->addr > concat->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for proper erase block alignment of the to-be-erased area.
|
* Check for proper erase block alignment of the to-be-erased area.
|
||||||
* It is easier to do this based on the super device's erase
|
* It is easier to do this based on the super device's erase
|
||||||
|
@ -350,8 +334,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
|
||||||
|
|
||||||
/* make a local copy of instr to avoid modifying the caller's struct */
|
/* make a local copy of instr to avoid modifying the caller's struct */
|
||||||
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
|
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
|
||||||
|
|
||||||
|
@ -390,10 +372,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
else
|
else
|
||||||
erase->len = length;
|
erase->len = length;
|
||||||
|
|
||||||
if (!(subdev->flags & MTD_WRITEABLE)) {
|
|
||||||
err = -EROFS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
length -= erase->len;
|
length -= erase->len;
|
||||||
if ((err = concat_dev_erase(subdev, erase))) {
|
if ((err = concat_dev_erase(subdev, erase))) {
|
||||||
/* sanity check: should never happen since
|
/* sanity check: should never happen since
|
||||||
|
@ -429,9 +407,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, err = -EINVAL;
|
int i, err = -EINVAL;
|
||||||
|
|
||||||
if ((len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
@ -446,7 +421,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
else
|
else
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
err = subdev->lock(subdev, ofs, size);
|
err = mtd_lock(subdev, ofs, size);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
@ -467,9 +442,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
if ((len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
@ -484,7 +456,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
else
|
else
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
err = subdev->unlock(subdev, ofs, size);
|
err = mtd_unlock(subdev, ofs, size);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
@ -507,7 +479,7 @@ static void concat_sync(struct mtd_info *mtd)
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
subdev->sync(subdev);
|
mtd_sync(subdev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,12 +488,9 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, res = 0;
|
int i, res = 0;
|
||||||
|
|
||||||
if (!concat->subdev[0]->block_isbad)
|
if (!mtd_can_have_bb(concat->subdev[0]))
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
if (ofs > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
|
|
||||||
|
@ -530,7 +499,7 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = subdev->block_isbad(subdev, ofs);
|
res = mtd_block_isbad(subdev, ofs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,12 +511,9 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, err = -EINVAL;
|
int i, err = -EINVAL;
|
||||||
|
|
||||||
if (!concat->subdev[0]->block_markbad)
|
if (!mtd_can_have_bb(concat->subdev[0]))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (ofs > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
|
|
||||||
|
@ -556,7 +522,7 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = subdev->block_markbad(subdev, ofs);
|
err = mtd_block_markbad(subdev, ofs);
|
||||||
if (!err)
|
if (!err)
|
||||||
mtd->ecc_stats.badblocks++;
|
mtd->ecc_stats.badblocks++;
|
||||||
break;
|
break;
|
||||||
|
@ -609,14 +575,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||||
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
|
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
|
||||||
concat->mtd.oobsize = subdev[0]->oobsize;
|
concat->mtd.oobsize = subdev[0]->oobsize;
|
||||||
concat->mtd.oobavail = subdev[0]->oobavail;
|
concat->mtd.oobavail = subdev[0]->oobavail;
|
||||||
if (subdev[0]->read_oob)
|
if (subdev[0]->_read_oob)
|
||||||
concat->mtd.read_oob = concat_read_oob;
|
concat->mtd._read_oob = concat_read_oob;
|
||||||
if (subdev[0]->write_oob)
|
if (subdev[0]->_write_oob)
|
||||||
concat->mtd.write_oob = concat_write_oob;
|
concat->mtd._write_oob = concat_write_oob;
|
||||||
if (subdev[0]->block_isbad)
|
if (subdev[0]->_block_isbad)
|
||||||
concat->mtd.block_isbad = concat_block_isbad;
|
concat->mtd._block_isbad = concat_block_isbad;
|
||||||
if (subdev[0]->block_markbad)
|
if (subdev[0]->_block_markbad)
|
||||||
concat->mtd.block_markbad = concat_block_markbad;
|
concat->mtd._block_markbad = concat_block_markbad;
|
||||||
|
|
||||||
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
||||||
|
|
||||||
|
@ -653,8 +619,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||||
if (concat->mtd.writesize != subdev[i]->writesize ||
|
if (concat->mtd.writesize != subdev[i]->writesize ||
|
||||||
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
|
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
|
||||||
concat->mtd.oobsize != subdev[i]->oobsize ||
|
concat->mtd.oobsize != subdev[i]->oobsize ||
|
||||||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
|
!concat->mtd._read_oob != !subdev[i]->_read_oob ||
|
||||||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
|
!concat->mtd._write_oob != !subdev[i]->_write_oob) {
|
||||||
kfree(concat);
|
kfree(concat);
|
||||||
printk("Incompatible OOB or ECC data on \"%s\"\n",
|
printk("Incompatible OOB or ECC data on \"%s\"\n",
|
||||||
subdev[i]->name);
|
subdev[i]->name);
|
||||||
|
@ -669,12 +635,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||||
concat->num_subdev = num_devs;
|
concat->num_subdev = num_devs;
|
||||||
concat->mtd.name = name;
|
concat->mtd.name = name;
|
||||||
|
|
||||||
concat->mtd.erase = concat_erase;
|
concat->mtd._erase = concat_erase;
|
||||||
concat->mtd.read = concat_read;
|
concat->mtd._read = concat_read;
|
||||||
concat->mtd.write = concat_write;
|
concat->mtd._write = concat_write;
|
||||||
concat->mtd.sync = concat_sync;
|
concat->mtd._sync = concat_sync;
|
||||||
concat->mtd.lock = concat_lock;
|
concat->mtd._lock = concat_lock;
|
||||||
concat->mtd.unlock = concat_unlock;
|
concat->mtd._unlock = concat_unlock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Combine the erase block size info of the subdevices:
|
* Combine the erase block size info of the subdevices:
|
||||||
|
|
|
@ -25,6 +25,11 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||||
mtd->index = i;
|
mtd->index = i;
|
||||||
mtd->usecount = 0;
|
mtd->usecount = 0;
|
||||||
|
|
||||||
|
/* default value if not set by driver */
|
||||||
|
if (mtd->bitflip_threshold == 0)
|
||||||
|
mtd->bitflip_threshold = mtd->ecc_strength;
|
||||||
|
|
||||||
|
|
||||||
/* No need to get a refcount on the module containing
|
/* No need to get a refcount on the module containing
|
||||||
the notifier, since we hold the mtd_table_mutex */
|
the notifier, since we hold the mtd_table_mutex */
|
||||||
|
|
||||||
|
@ -186,3 +191,189 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
|
#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Erase is an asynchronous operation. Device drivers are supposed
|
||||||
|
* to call instr->callback() whenever the operation completes, even
|
||||||
|
* if it completes with a failure.
|
||||||
|
* Callers are supposed to pass a callback function and wait for it
|
||||||
|
* to be called before writing to the block.
|
||||||
|
*/
|
||||||
|
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
|
{
|
||||||
|
if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
||||||
|
if (!instr->len) {
|
||||||
|
instr->state = MTD_ERASE_DONE;
|
||||||
|
mtd_erase_callback(instr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return mtd->_erase(mtd, instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||||
|
u_char *buf)
|
||||||
|
{
|
||||||
|
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_read(mtd, from, len, retlen, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
const u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_write(mtd, to, len, retlen, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In blackbox flight recorder like scenarios we want to make successful writes
|
||||||
|
* in interrupt context. panic_write() is only intended to be called when its
|
||||||
|
* known the kernel is about to panic and we need the write to succeed. Since
|
||||||
|
* the kernel is not going to be running for much longer, this function can
|
||||||
|
* break locks and delay to ensure the write succeeds (but not sleep).
|
||||||
|
*/
|
||||||
|
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
const u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_panic_write)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_panic_write(mtd, to, len, retlen, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||||
|
{
|
||||||
|
ops->retlen = ops->oobretlen = 0;
|
||||||
|
if (!mtd->_read_oob)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
return mtd->_read_oob(mtd, from, ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Method to access the protection register area, present in some flash
|
||||||
|
* devices. The user data is one time programmable but the factory data is read
|
||||||
|
* only.
|
||||||
|
*/
|
||||||
|
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_get_fact_prot_info)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_get_fact_prot_info(mtd, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_read_fact_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_get_user_prot_info)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_get_user_prot_info(mtd, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_read_user_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_write_user_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_lock_user_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_lock_user_prot_reg(mtd, from, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chip-supported device locking */
|
||||||
|
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_lock)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_lock(mtd, ofs, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_unlock)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_unlock(mtd, ofs, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
|
{
|
||||||
|
if (!mtd->_block_isbad)
|
||||||
|
return 0;
|
||||||
|
if (ofs < 0 || ofs > mtd->size)
|
||||||
|
return -EINVAL;
|
||||||
|
return mtd->_block_isbad(mtd, ofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
|
{
|
||||||
|
if (!mtd->_block_markbad)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (ofs < 0 || ofs > mtd->size)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
return mtd->_block_markbad(mtd, ofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,17 +52,11 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
stats = part->master->ecc_stats;
|
stats = part->master->ecc_stats;
|
||||||
|
res = mtd_read(part->master, from + part->offset, len, retlen, buf);
|
||||||
if (from >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (from + len > mtd->size)
|
|
||||||
len = mtd->size - from;
|
|
||||||
res = part->master->read(part->master, from + part->offset,
|
|
||||||
len, retlen, buf);
|
|
||||||
if (unlikely(res)) {
|
if (unlikely(res)) {
|
||||||
if (res == -EUCLEAN)
|
if (mtd_is_bitflip(res))
|
||||||
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
||||||
if (res == -EBADMSG)
|
if (mtd_is_eccerr(res))
|
||||||
mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
|
mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -78,12 +72,12 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (ops->datbuf && from + ops->len > mtd->size)
|
if (ops->datbuf && from + ops->len > mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
res = part->master->read_oob(part->master, from + part->offset, ops);
|
res = mtd_read_oob(part->master, from + part->offset, ops);
|
||||||
|
|
||||||
if (unlikely(res)) {
|
if (unlikely(res)) {
|
||||||
if (res == -EUCLEAN)
|
if (mtd_is_bitflip(res))
|
||||||
mtd->ecc_stats.corrected++;
|
mtd->ecc_stats.corrected++;
|
||||||
if (res == -EBADMSG)
|
if (mtd_is_eccerr(res))
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -93,58 +87,35 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len, size_t *retlen, u_char *buf)
|
size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->read_user_prot_reg(part->master, from,
|
return mtd_read_user_prot_reg(part->master, from, len, retlen, buf);
|
||||||
len, retlen, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_get_user_prot_info(struct mtd_info *mtd,
|
static int part_get_user_prot_info(struct mtd_info *mtd,
|
||||||
struct otp_info *buf, size_t len)
|
struct otp_info *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->get_user_prot_info(part->master, buf, len);
|
return mtd_get_user_prot_info(part->master, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len, size_t *retlen, u_char *buf)
|
size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->read_fact_prot_reg(part->master, from,
|
return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf);
|
||||||
len, retlen, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->get_fact_prot_info(part->master, buf, len);
|
return mtd_get_fact_prot_info(part->master, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
|
static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const u_char *buf)
|
size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
return mtd_write(part->master, to + part->offset, len, retlen, buf);
|
||||||
return -EROFS;
|
|
||||||
if (to >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (to + len > mtd->size)
|
|
||||||
len = mtd->size - to;
|
|
||||||
return part->master->write(part->master, to + part->offset,
|
|
||||||
len, retlen, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
||||||
size_t *retlen, const u_char *buf)
|
|
||||||
{
|
|
||||||
struct mtd_part *part = PART(mtd);
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
if (to >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (to + len > mtd->size)
|
|
||||||
len = mtd->size - to;
|
|
||||||
return part->master->panic_write(part->master, to + part->offset,
|
|
||||||
len, retlen, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
|
@ -152,41 +123,34 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
if (to >= mtd->size)
|
if (to >= mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (ops->datbuf && to + ops->len > mtd->size)
|
if (ops->datbuf && to + ops->len > mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return part->master->write_oob(part->master, to + part->offset, ops);
|
return mtd_write_oob(part->master, to + part->offset, ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len, size_t *retlen, u_char *buf)
|
size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->write_user_prot_reg(part->master, from,
|
return mtd_write_user_prot_reg(part->master, from, len, retlen, buf);
|
||||||
len, retlen, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->lock_user_prot_reg(part->master, from, len);
|
return mtd_lock_user_prot_reg(part->master, from, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
int ret;
|
int ret;
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
if (instr->addr >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
instr->addr += part->offset;
|
instr->addr += part->offset;
|
||||||
ret = part->master->erase(part->master, instr);
|
ret = mtd_erase(part->master, instr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||||
instr->fail_addr -= part->offset;
|
instr->fail_addr -= part->offset;
|
||||||
|
@ -197,7 +161,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
|
|
||||||
void mtd_erase_callback(struct erase_info *instr)
|
void mtd_erase_callback(struct erase_info *instr)
|
||||||
{
|
{
|
||||||
if (instr->mtd->erase == part_erase) {
|
if (instr->mtd->_erase == part_erase) {
|
||||||
struct mtd_part *part = PART(instr->mtd);
|
struct mtd_part *part = PART(instr->mtd);
|
||||||
|
|
||||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||||
|
@ -211,32 +175,26 @@ void mtd_erase_callback(struct erase_info *instr)
|
||||||
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
return mtd_lock(part->master, ofs + part->offset, len);
|
||||||
return -EINVAL;
|
|
||||||
return part->master->lock(part->master, ofs + part->offset, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
return mtd_unlock(part->master, ofs + part->offset, len);
|
||||||
return -EINVAL;
|
|
||||||
return part->master->unlock(part->master, ofs + part->offset, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void part_sync(struct mtd_info *mtd)
|
static void part_sync(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
part->master->sync(part->master);
|
mtd_sync(part->master);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (ofs >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
ofs += part->offset;
|
ofs += part->offset;
|
||||||
return part->master->block_isbad(part->master, ofs);
|
return mtd_block_isbad(part->master, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
|
@ -244,12 +202,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
if (ofs >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
ofs += part->offset;
|
ofs += part->offset;
|
||||||
res = part->master->block_markbad(part->master, ofs);
|
res = mtd_block_markbad(part->master, ofs);
|
||||||
if (!res)
|
if (!res)
|
||||||
mtd->ecc_stats.badblocks++;
|
mtd->ecc_stats.badblocks++;
|
||||||
return res;
|
return res;
|
||||||
|
@ -303,39 +257,36 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
|
||||||
slave->mtd.name = part->name;
|
slave->mtd.name = part->name;
|
||||||
slave->mtd.owner = master->owner;
|
slave->mtd.owner = master->owner;
|
||||||
|
|
||||||
slave->mtd.read = part_read;
|
slave->mtd._read = part_read;
|
||||||
slave->mtd.write = part_write;
|
slave->mtd._write = part_write;
|
||||||
|
|
||||||
if (master->panic_write)
|
if (master->_read_oob)
|
||||||
slave->mtd.panic_write = part_panic_write;
|
slave->mtd._read_oob = part_read_oob;
|
||||||
|
if (master->_write_oob)
|
||||||
if (master->read_oob)
|
slave->mtd._write_oob = part_write_oob;
|
||||||
slave->mtd.read_oob = part_read_oob;
|
if (master->_read_user_prot_reg)
|
||||||
if (master->write_oob)
|
slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
|
||||||
slave->mtd.write_oob = part_write_oob;
|
if (master->_read_fact_prot_reg)
|
||||||
if (master->read_user_prot_reg)
|
slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
|
||||||
slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
|
if (master->_write_user_prot_reg)
|
||||||
if (master->read_fact_prot_reg)
|
slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
|
||||||
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
|
if (master->_lock_user_prot_reg)
|
||||||
if (master->write_user_prot_reg)
|
slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
|
||||||
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
|
if (master->_get_user_prot_info)
|
||||||
if (master->lock_user_prot_reg)
|
slave->mtd._get_user_prot_info = part_get_user_prot_info;
|
||||||
slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
|
if (master->_get_fact_prot_info)
|
||||||
if (master->get_user_prot_info)
|
slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
|
||||||
slave->mtd.get_user_prot_info = part_get_user_prot_info;
|
if (master->_sync)
|
||||||
if (master->get_fact_prot_info)
|
slave->mtd._sync = part_sync;
|
||||||
slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
|
if (master->_lock)
|
||||||
if (master->sync)
|
slave->mtd._lock = part_lock;
|
||||||
slave->mtd.sync = part_sync;
|
if (master->_unlock)
|
||||||
if (master->lock)
|
slave->mtd._unlock = part_unlock;
|
||||||
slave->mtd.lock = part_lock;
|
if (master->_block_isbad)
|
||||||
if (master->unlock)
|
slave->mtd._block_isbad = part_block_isbad;
|
||||||
slave->mtd.unlock = part_unlock;
|
if (master->_block_markbad)
|
||||||
if (master->block_isbad)
|
slave->mtd._block_markbad = part_block_markbad;
|
||||||
slave->mtd.block_isbad = part_block_isbad;
|
slave->mtd._erase = part_erase;
|
||||||
if (master->block_markbad)
|
|
||||||
slave->mtd.block_markbad = part_block_markbad;
|
|
||||||
slave->mtd.erase = part_erase;
|
|
||||||
slave->master = master;
|
slave->master = master;
|
||||||
slave->offset = part->offset;
|
slave->offset = part->offset;
|
||||||
slave->index = partno;
|
slave->index = partno;
|
||||||
|
@ -416,12 +367,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
|
||||||
}
|
}
|
||||||
|
|
||||||
slave->mtd.ecclayout = master->ecclayout;
|
slave->mtd.ecclayout = master->ecclayout;
|
||||||
if (master->block_isbad) {
|
if (master->_block_isbad) {
|
||||||
uint64_t offs = 0;
|
uint64_t offs = 0;
|
||||||
|
|
||||||
while (offs < slave->mtd.size) {
|
while (offs < slave->mtd.size) {
|
||||||
if (master->block_isbad(master,
|
if (mtd_block_isbad(master, offs + slave->offset))
|
||||||
offs + slave->offset))
|
|
||||||
slave->mtd.ecc_stats.badblocks++;
|
slave->mtd.ecc_stats.badblocks++;
|
||||||
offs += slave->mtd.erasesize;
|
offs += slave->mtd.erasesize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,7 +489,7 @@ normal_check:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, uint8_t *buf, int page)
|
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
struct atmel_nand_host *host = chip->priv;
|
struct atmel_nand_host *host = chip->priv;
|
||||||
int eccsize = chip->ecc.size;
|
int eccsize = chip->ecc.size;
|
||||||
|
@ -529,8 +529,9 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, const uint8_t *buf)
|
struct nand_chip *chip, const uint8_t *buf,
|
||||||
|
int oob_required)
|
||||||
{
|
{
|
||||||
struct atmel_nand_host *host = chip->priv;
|
struct atmel_nand_host *host = chip->priv;
|
||||||
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
||||||
|
@ -557,7 +558,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||||
|
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
|
printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < host->pmecc_sector_number; i++) {
|
for (i = 0; i < host->pmecc_sector_number; i++) {
|
||||||
|
@ -570,6 +571,8 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
out:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
||||||
|
@ -706,6 +709,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
|
||||||
|
|
||||||
nand->ecc.read_page = atmel_nand_pmecc_read_page;
|
nand->ecc.read_page = atmel_nand_pmecc_read_page;
|
||||||
nand->ecc.write_page = atmel_nand_pmecc_write_page;
|
nand->ecc.write_page = atmel_nand_pmecc_write_page;
|
||||||
|
nand->ecc.strength = cap;
|
||||||
|
|
||||||
atmel_pmecc_core_init(mtd);
|
atmel_pmecc_core_init(mtd);
|
||||||
|
|
||||||
|
@ -775,9 +779,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
|
||||||
* mtd: mtd info structure
|
* mtd: mtd info structure
|
||||||
* chip: nand chip info structure
|
* chip: nand chip info structure
|
||||||
* buf: buffer to store read data
|
* buf: buffer to store read data
|
||||||
|
* oob_required: caller expects OOB data read to chip->oob_poi
|
||||||
*/
|
*/
|
||||||
static int atmel_nand_read_page(struct mtd_info *mtd,
|
static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip, uint8_t *buf, int page)
|
uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
int eccsize = chip->ecc.size;
|
int eccsize = chip->ecc.size;
|
||||||
int eccbytes = chip->ecc.bytes;
|
int eccbytes = chip->ecc.bytes;
|
||||||
|
|
|
@ -374,9 +374,11 @@ int board_nand_init(struct nand_chip *chip)
|
||||||
if (!NAND_IS_512()) {
|
if (!NAND_IS_512()) {
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
chip->ecc.size = 256;
|
chip->ecc.size = 256;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
} else {
|
} else {
|
||||||
chip->ecc.bytes = 6;
|
chip->ecc.bytes = 6;
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
|
chip->ecc.strength = 2;
|
||||||
}
|
}
|
||||||
chip->ecc.mode = NAND_ECC_HW;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
chip->ecc.calculate = bfin_nfc_calculate_ecc;
|
chip->ecc.calculate = bfin_nfc_calculate_ecc;
|
||||||
|
|
|
@ -607,12 +607,13 @@ void davinci_nand_init(struct nand_chip *nand)
|
||||||
{
|
{
|
||||||
nand->chip_delay = 0;
|
nand->chip_delay = 0;
|
||||||
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
|
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
|
||||||
nand->options |= NAND_USE_FLASH_BBT;
|
nand->bbt_options |= NAND_BBT_USE_FLASH;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SYS_NAND_HW_ECC
|
#ifdef CONFIG_SYS_NAND_HW_ECC
|
||||||
nand->ecc.mode = NAND_ECC_HW;
|
nand->ecc.mode = NAND_ECC_HW;
|
||||||
nand->ecc.size = 512;
|
nand->ecc.size = 512;
|
||||||
nand->ecc.bytes = 3;
|
nand->ecc.bytes = 3;
|
||||||
|
nand->ecc.strength = 1;
|
||||||
nand->ecc.calculate = nand_davinci_calculate_ecc;
|
nand->ecc.calculate = nand_davinci_calculate_ecc;
|
||||||
nand->ecc.correct = nand_davinci_correct_data;
|
nand->ecc.correct = nand_davinci_correct_data;
|
||||||
nand->ecc.hwctl = nand_davinci_enable_hwecc;
|
nand->ecc.hwctl = nand_davinci_enable_hwecc;
|
||||||
|
@ -623,6 +624,7 @@ void davinci_nand_init(struct nand_chip *nand)
|
||||||
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||||
nand->ecc.size = 512;
|
nand->ecc.size = 512;
|
||||||
nand->ecc.bytes = 10;
|
nand->ecc.bytes = 10;
|
||||||
|
nand->ecc.strength = 4;
|
||||||
nand->ecc.calculate = nand_davinci_4bit_calculate_ecc;
|
nand->ecc.calculate = nand_davinci_4bit_calculate_ecc;
|
||||||
nand->ecc.correct = nand_davinci_4bit_correct_data;
|
nand->ecc.correct = nand_davinci_4bit_correct_data;
|
||||||
nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc;
|
nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc;
|
||||||
|
|
|
@ -134,7 +134,7 @@ static struct rs_control *rs_decoder;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The HW decoder in the DoC ASIC's provides us a error syndrome,
|
* The HW decoder in the DoC ASIC's provides us a error syndrome,
|
||||||
* which we must convert to a standard syndrom usable by the generic
|
* which we must convert to a standard syndrome usable by the generic
|
||||||
* Reed-Solomon library code.
|
* Reed-Solomon library code.
|
||||||
*
|
*
|
||||||
* Fabrice Bellard figured this out in the old docecc code. I added
|
* Fabrice Bellard figured this out in the old docecc code. I added
|
||||||
|
@ -154,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
|
||||||
ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
|
ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
|
||||||
parity = ecc[1];
|
parity = ecc[1];
|
||||||
|
|
||||||
/* Initialize the syndrom buffer */
|
/* Initialize the syndrome buffer */
|
||||||
for (i = 0; i < NROOTS; i++)
|
for (i = 0; i < NROOTS; i++)
|
||||||
s[i] = ds[0];
|
s[i] = ds[0];
|
||||||
/*
|
/*
|
||||||
|
@ -1033,7 +1033,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
|
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
|
||||||
else
|
else
|
||||||
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
|
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
|
||||||
if (no_ecc_failures && (ret == -EBADMSG)) {
|
if (no_ecc_failures && mtd_is_eccerr(ret)) {
|
||||||
printk(KERN_ERR "suppressing ECC failure\n");
|
printk(KERN_ERR "suppressing ECC failure\n");
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1073,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
|
|
||||||
for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
|
for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
|
||||||
ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
|
ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
|
||||||
if (retlen != mtd->writesize)
|
if (retlen != mtd->writesize)
|
||||||
continue;
|
continue;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1098,7 +1098,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
|
||||||
/* Only one mediaheader was found. We want buf to contain a
|
/* Only one mediaheader was found. We want buf to contain a
|
||||||
mediaheader on return, so we'll have to re-read the one we found. */
|
mediaheader on return, so we'll have to re-read the one we found. */
|
||||||
offs = doc->mh0_page << this->page_shift;
|
offs = doc->mh0_page << this->page_shift;
|
||||||
ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
|
ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
|
||||||
if (retlen != mtd->writesize) {
|
if (retlen != mtd->writesize) {
|
||||||
/* Insanity. Give up. */
|
/* Insanity. Give up. */
|
||||||
printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
|
printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
|
||||||
|
@ -1658,7 +1658,8 @@ static int __init doc_probe(unsigned long physadr)
|
||||||
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
|
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
nand->ecc.size = 512;
|
nand->ecc.size = 512;
|
||||||
nand->ecc.bytes = 6;
|
nand->ecc.bytes = 6;
|
||||||
nand->options = NAND_USE_FLASH_BBT;
|
nand->ecc.strength = 2;
|
||||||
|
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||||
|
|
||||||
doc->physadr = physadr;
|
doc->physadr = physadr;
|
||||||
doc->virtadr = virtadr;
|
doc->virtadr = virtadr;
|
||||||
|
|
|
@ -640,9 +640,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||||
return fsl_elbc_read_byte(mtd);
|
return fsl_elbc_read_byte(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsl_elbc_read_page(struct mtd_info *mtd,
|
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip,
|
uint8_t *buf, int oob_required, int page)
|
||||||
uint8_t *buf, int page)
|
|
||||||
{
|
{
|
||||||
fsl_elbc_read_buf(mtd, buf, mtd->writesize);
|
fsl_elbc_read_buf(mtd, buf, mtd->writesize);
|
||||||
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
@ -656,12 +655,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd,
|
||||||
/* ECC will be calculated automatically, and errors will be detected in
|
/* ECC will be calculated automatically, and errors will be detected in
|
||||||
* waitfunc.
|
* waitfunc.
|
||||||
*/
|
*/
|
||||||
static void fsl_elbc_write_page(struct mtd_info *mtd,
|
static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip,
|
const uint8_t *buf, int oob_required)
|
||||||
const uint8_t *buf)
|
|
||||||
{
|
{
|
||||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fsl_elbc_ctrl *elbc_ctrl;
|
static struct fsl_elbc_ctrl *elbc_ctrl;
|
||||||
|
@ -747,8 +747,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||||
nand->bbt_md = &bbt_mirror_descr;
|
nand->bbt_md = &bbt_mirror_descr;
|
||||||
|
|
||||||
/* set up nand options */
|
/* set up nand options */
|
||||||
nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
|
nand->options = NAND_NO_SUBPAGE_WRITE;
|
||||||
NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
|
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||||
|
|
||||||
nand->controller = &elbc_ctrl->controller;
|
nand->controller = &elbc_ctrl->controller;
|
||||||
nand->priv = priv;
|
nand->priv = priv;
|
||||||
|
@ -769,6 +769,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||||
nand->ecc.size = 512;
|
nand->ecc.size = 512;
|
||||||
nand->ecc.bytes = 3;
|
nand->ecc.bytes = 3;
|
||||||
nand->ecc.steps = 1;
|
nand->ecc.steps = 1;
|
||||||
|
nand->ecc.strength = 1;
|
||||||
} else {
|
} else {
|
||||||
/* otherwise fall back to default software ECC */
|
/* otherwise fall back to default software ECC */
|
||||||
nand->ecc.mode = NAND_ECC_SOFT;
|
nand->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
|
@ -686,9 +686,8 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||||
return nand_fsr;
|
return nand_fsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsl_ifc_read_page(struct mtd_info *mtd,
|
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip,
|
uint8_t *buf, int oob_required, int page)
|
||||||
uint8_t *buf, int page)
|
|
||||||
{
|
{
|
||||||
struct fsl_ifc_mtd *priv = chip->priv;
|
struct fsl_ifc_mtd *priv = chip->priv;
|
||||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||||
|
@ -705,12 +704,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd,
|
||||||
/* ECC will be calculated automatically, and errors will be detected in
|
/* ECC will be calculated automatically, and errors will be detected in
|
||||||
* waitfunc.
|
* waitfunc.
|
||||||
*/
|
*/
|
||||||
static void fsl_ifc_write_page(struct mtd_info *mtd,
|
static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip,
|
const uint8_t *buf, int oob_required)
|
||||||
const uint8_t *buf)
|
|
||||||
{
|
{
|
||||||
fsl_ifc_write_buf(mtd, buf, mtd->writesize);
|
fsl_ifc_write_buf(mtd, buf, mtd->writesize);
|
||||||
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fsl_ifc_ctrl_init(void)
|
static void fsl_ifc_ctrl_init(void)
|
||||||
|
@ -858,8 +858,8 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||||
nand->bbt_md = &bbt_mirror_descr;
|
nand->bbt_md = &bbt_mirror_descr;
|
||||||
|
|
||||||
/* set up nand options */
|
/* set up nand options */
|
||||||
nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
|
nand->options = NAND_NO_SUBPAGE_WRITE;
|
||||||
NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
|
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||||
|
|
||||||
if (cspr & CSPR_PORT_SIZE_16) {
|
if (cspr & CSPR_PORT_SIZE_16) {
|
||||||
nand->read_byte = fsl_ifc_read_byte16;
|
nand->read_byte = fsl_ifc_read_byte16;
|
||||||
|
@ -890,11 +890,13 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||||
bbt_mirror_descr.offs = 0;
|
bbt_mirror_descr.offs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nand->ecc.strength = 4;
|
||||||
priv->bufnum_mask = 15;
|
priv->bufnum_mask = 15;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CSOR_NAND_PGS_2K:
|
case CSOR_NAND_PGS_2K:
|
||||||
layout = &oob_2048_ecc4;
|
layout = &oob_2048_ecc4;
|
||||||
|
nand->ecc.strength = 4;
|
||||||
priv->bufnum_mask = 3;
|
priv->bufnum_mask = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -902,8 +904,10 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||||
if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
|
if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
|
||||||
CSOR_NAND_ECC_MODE_4) {
|
CSOR_NAND_ECC_MODE_4) {
|
||||||
layout = &oob_4096_ecc4;
|
layout = &oob_4096_ecc4;
|
||||||
|
nand->ecc.strength = 4;
|
||||||
} else {
|
} else {
|
||||||
layout = &oob_4096_ecc8;
|
layout = &oob_4096_ecc8;
|
||||||
|
nand->ecc.strength = 8;
|
||||||
nand->ecc.bytes = 16;
|
nand->ecc.bytes = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||||
* @mtd: mtd info structure
|
* @mtd: mtd info structure
|
||||||
* @chip: nand chip info structure
|
* @chip: nand chip info structure
|
||||||
* @buf: buffer to store read data
|
* @buf: buffer to store read data
|
||||||
|
* @oob_required: caller expects OOB data read to chip->oob_poi
|
||||||
* @page: page number to read
|
* @page: page number to read
|
||||||
*
|
*
|
||||||
* This routine is needed for fsmc verison 8 as reading from NAND chip has to be
|
* This routine is needed for fsmc verison 8 as reading from NAND chip has to be
|
||||||
|
@ -350,7 +351,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||||
* max of 8 bits)
|
* max of 8 bits)
|
||||||
*/
|
*/
|
||||||
static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint8_t *buf, int page)
|
uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
struct fsmc_eccplace *fsmc_eccpl;
|
struct fsmc_eccplace *fsmc_eccpl;
|
||||||
int i, j, s, stat, eccsize = chip->ecc.size;
|
int i, j, s, stat, eccsize = chip->ecc.size;
|
||||||
|
@ -452,6 +453,7 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||||
switch (fsmc_version) {
|
switch (fsmc_version) {
|
||||||
case FSMC_VER8:
|
case FSMC_VER8:
|
||||||
nand->ecc.bytes = 13;
|
nand->ecc.bytes = 13;
|
||||||
|
nand->ecc.strength = 8;
|
||||||
nand->ecc.correct = fsmc_bch8_correct_data;
|
nand->ecc.correct = fsmc_bch8_correct_data;
|
||||||
nand->ecc.read_page = fsmc_read_page_hwecc;
|
nand->ecc.read_page = fsmc_read_page_hwecc;
|
||||||
if (mtd->writesize == 512)
|
if (mtd->writesize == 512)
|
||||||
|
@ -466,6 +468,7 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nand->ecc.bytes = 3;
|
nand->ecc.bytes = 3;
|
||||||
|
nand->ecc.strength = 1;
|
||||||
nand->ecc.layout = &fsmc_ecc1_layout;
|
nand->ecc.layout = &fsmc_ecc1_layout;
|
||||||
nand->ecc.correct = nand_correct_data;
|
nand->ecc.correct = nand_correct_data;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -253,6 +253,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||||
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||||
|
nand->ecc.strength = 4;
|
||||||
nand->ecc.layout = &qi_lb60_ecclayout_2gb;
|
nand->ecc.layout = &qi_lb60_ecclayout_2gb;
|
||||||
nand->chip_delay = 50;
|
nand->chip_delay = 50;
|
||||||
nand->options = NAND_USE_FLASH_BBT;
|
nand->options = NAND_USE_FLASH_BBT;
|
||||||
|
|
|
@ -621,7 +621,7 @@ int board_nand_init(struct nand_chip *chip)
|
||||||
chip->write_buf = mpc5121_nfc_write_buf;
|
chip->write_buf = mpc5121_nfc_write_buf;
|
||||||
chip->verify_buf = mpc5121_nfc_verify_buf;
|
chip->verify_buf = mpc5121_nfc_verify_buf;
|
||||||
chip->select_chip = mpc5121_nfc_select_chip;
|
chip->select_chip = mpc5121_nfc_select_chip;
|
||||||
chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
|
chip->bbt_options = NAND_BBT_USE_FLASH;
|
||||||
chip->ecc.mode = NAND_ECC_SOFT;
|
chip->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Reset NAND Flash controller */
|
/* Reset NAND Flash controller */
|
||||||
|
|
|
@ -396,7 +396,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||||
#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
|
#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
|
||||||
static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
|
static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip,
|
struct nand_chip *chip,
|
||||||
int page, int sndcmd)
|
int page)
|
||||||
{
|
{
|
||||||
struct mxc_nand_host *host = chip->priv;
|
struct mxc_nand_host *host = chip->priv;
|
||||||
uint8_t *buf = chip->oob_poi;
|
uint8_t *buf = chip->oob_poi;
|
||||||
|
@ -450,6 +450,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
|
||||||
static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip,
|
struct nand_chip *chip,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
|
int oob_required,
|
||||||
int page)
|
int page)
|
||||||
{
|
{
|
||||||
struct mxc_nand_host *host = chip->priv;
|
struct mxc_nand_host *host = chip->priv;
|
||||||
|
@ -494,6 +495,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
||||||
static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,
|
static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip,
|
struct nand_chip *chip,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
|
int oob_required,
|
||||||
int page)
|
int page)
|
||||||
{
|
{
|
||||||
struct mxc_nand_host *host = chip->priv;
|
struct mxc_nand_host *host = chip->priv;
|
||||||
|
@ -583,9 +585,10 @@ static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd,
|
||||||
return status & NAND_STATUS_FAIL ? -EIO : 0;
|
return status & NAND_STATUS_FAIL ? -EIO : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip,
|
struct nand_chip *chip,
|
||||||
const uint8_t *buf)
|
const uint8_t *buf,
|
||||||
|
int oob_required)
|
||||||
{
|
{
|
||||||
struct mxc_nand_host *host = chip->priv;
|
struct mxc_nand_host *host = chip->priv;
|
||||||
int eccsize = chip->ecc.size;
|
int eccsize = chip->ecc.size;
|
||||||
|
@ -619,11 +622,13 @@ static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||||
size = mtd->oobsize - (oob - chip->oob_poi);
|
size = mtd->oobsize - (oob - chip->oob_poi);
|
||||||
if (size)
|
if (size)
|
||||||
chip->write_buf(mtd, oob, size);
|
chip->write_buf(mtd, oob, size);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
static int mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip,
|
struct nand_chip *chip,
|
||||||
const uint8_t *buf)
|
const uint8_t *buf,
|
||||||
|
int oob_required)
|
||||||
{
|
{
|
||||||
struct mxc_nand_host *host = chip->priv;
|
struct mxc_nand_host *host = chip->priv;
|
||||||
int i, n, eccsize = chip->ecc.size;
|
int i, n, eccsize = chip->ecc.size;
|
||||||
|
@ -662,6 +667,7 @@ static void mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||||
i = mtd->oobsize - (oob - chip->oob_poi);
|
i = mtd->oobsize - (oob - chip->oob_poi);
|
||||||
if (i)
|
if (i)
|
||||||
chip->write_buf(mtd, oob, i);
|
chip->write_buf(mtd, oob, i);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
|
@ -1188,7 +1194,7 @@ int board_nand_init(struct nand_chip *this)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
|
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
|
||||||
this->options |= NAND_USE_FLASH_BBT;
|
this->bbt_options |= NAND_BBT_USE_FLASH;
|
||||||
this->bbt_td = &bbt_main_descr;
|
this->bbt_td = &bbt_main_descr;
|
||||||
this->bbt_md = &bbt_mirror_descr;
|
this->bbt_md = &bbt_mirror_descr;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1236,6 +1242,13 @@ int board_nand_init(struct nand_chip *this)
|
||||||
this->ecc.mode = NAND_ECC_HW;
|
this->ecc.mode = NAND_ECC_HW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->ecc.mode == NAND_ECC_HW) {
|
||||||
|
if (is_mxc_nfc_1())
|
||||||
|
this->ecc.strength = 1;
|
||||||
|
else
|
||||||
|
this->ecc.strength = 4;
|
||||||
|
}
|
||||||
|
|
||||||
host->pagesize_2k = 0;
|
host->pagesize_2k = 0;
|
||||||
|
|
||||||
this->ecc.size = 512;
|
this->ecc.size = 512;
|
||||||
|
|
|
@ -546,7 +546,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
|
||||||
* Read a page from NAND.
|
* Read a page from NAND.
|
||||||
*/
|
*/
|
||||||
static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
|
static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
|
||||||
uint8_t *buf, int page)
|
uint8_t *buf, int oob_required,
|
||||||
|
int page)
|
||||||
{
|
{
|
||||||
struct mxs_nand_info *nand_info = nand->priv;
|
struct mxs_nand_info *nand_info = nand->priv;
|
||||||
struct mxs_dma_desc *d;
|
struct mxs_dma_desc *d;
|
||||||
|
@ -691,8 +692,9 @@ rtn:
|
||||||
/*
|
/*
|
||||||
* Write a page to NAND.
|
* Write a page to NAND.
|
||||||
*/
|
*/
|
||||||
static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
||||||
struct nand_chip *nand, const uint8_t *buf)
|
struct nand_chip *nand, const uint8_t *buf,
|
||||||
|
int oob_required)
|
||||||
{
|
{
|
||||||
struct mxs_nand_info *nand_info = nand->priv;
|
struct mxs_nand_info *nand_info = nand->priv;
|
||||||
struct mxs_dma_desc *d;
|
struct mxs_dma_desc *d;
|
||||||
|
@ -748,6 +750,7 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
||||||
|
|
||||||
rtn:
|
rtn:
|
||||||
mxs_nand_return_dma_descs(nand_info);
|
mxs_nand_return_dma_descs(nand_info);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -763,7 +766,7 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
struct mxs_nand_info *nand_info = chip->priv;
|
struct mxs_nand_info *nand_info = chip->priv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_RAW)
|
if (ops->mode == MTD_OPS_RAW)
|
||||||
nand_info->raw_oob_mode = 1;
|
nand_info->raw_oob_mode = 1;
|
||||||
else
|
else
|
||||||
nand_info->raw_oob_mode = 0;
|
nand_info->raw_oob_mode = 0;
|
||||||
|
@ -788,7 +791,7 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
struct mxs_nand_info *nand_info = chip->priv;
|
struct mxs_nand_info *nand_info = chip->priv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_RAW)
|
if (ops->mode == MTD_OPS_RAW)
|
||||||
nand_info->raw_oob_mode = 1;
|
nand_info->raw_oob_mode = 1;
|
||||||
else
|
else
|
||||||
nand_info->raw_oob_mode = 0;
|
nand_info->raw_oob_mode = 0;
|
||||||
|
@ -866,7 +869,7 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
* what to do.
|
* what to do.
|
||||||
*/
|
*/
|
||||||
static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||||
int page, int cmd)
|
int page)
|
||||||
{
|
{
|
||||||
struct mxs_nand_info *nand_info = nand->priv;
|
struct mxs_nand_info *nand_info = nand->priv;
|
||||||
|
|
||||||
|
@ -997,19 +1000,19 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
|
||||||
writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);
|
writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);
|
||||||
|
|
||||||
/* Hook some operations at the MTD level. */
|
/* Hook some operations at the MTD level. */
|
||||||
if (mtd->read_oob != mxs_nand_hook_read_oob) {
|
if (mtd->_read_oob != mxs_nand_hook_read_oob) {
|
||||||
nand_info->hooked_read_oob = mtd->read_oob;
|
nand_info->hooked_read_oob = mtd->_read_oob;
|
||||||
mtd->read_oob = mxs_nand_hook_read_oob;
|
mtd->_read_oob = mxs_nand_hook_read_oob;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mtd->write_oob != mxs_nand_hook_write_oob) {
|
if (mtd->_write_oob != mxs_nand_hook_write_oob) {
|
||||||
nand_info->hooked_write_oob = mtd->write_oob;
|
nand_info->hooked_write_oob = mtd->_write_oob;
|
||||||
mtd->write_oob = mxs_nand_hook_write_oob;
|
mtd->_write_oob = mxs_nand_hook_write_oob;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mtd->block_markbad != mxs_nand_hook_block_markbad) {
|
if (mtd->_block_markbad != mxs_nand_hook_block_markbad) {
|
||||||
nand_info->hooked_block_markbad = mtd->block_markbad;
|
nand_info->hooked_block_markbad = mtd->_block_markbad;
|
||||||
mtd->block_markbad = mxs_nand_hook_block_markbad;
|
mtd->_block_markbad = mxs_nand_hook_block_markbad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We use the reference implementation for bad block management. */
|
/* We use the reference implementation for bad block management. */
|
||||||
|
@ -1163,6 +1166,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||||
nand->ecc.mode = NAND_ECC_HW;
|
nand->ecc.mode = NAND_ECC_HW;
|
||||||
nand->ecc.bytes = 9;
|
nand->ecc.bytes = 9;
|
||||||
nand->ecc.size = 512;
|
nand->ecc.size = 512;
|
||||||
|
nand->ecc.strength = 8;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -71,7 +71,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
|
||||||
* These are the new chips with large page size. The pagesize and the
|
* These are the new chips with large page size. The pagesize and the
|
||||||
* erasesize is determined from the extended id bytes
|
* erasesize is determined from the extended id bytes
|
||||||
*/
|
*/
|
||||||
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
|
#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
|
||||||
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
|
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
|
||||||
|
|
||||||
/* 512 Megabit */
|
/* 512 Megabit */
|
||||||
|
@ -79,6 +79,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS},
|
{"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS},
|
||||||
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
|
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
|
||||||
{"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS},
|
{"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS},
|
||||||
|
{"NAND 64MiB 3,3V 8-bit", 0xF0, 0, 64, 0, LP_OPTIONS},
|
||||||
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
|
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
|
||||||
{"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16},
|
{"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16},
|
||||||
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
|
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
|
||||||
|
@ -157,9 +158,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
|
||||||
* writes possible, but not implemented now
|
* writes possible, but not implemented now
|
||||||
*/
|
*/
|
||||||
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
|
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
|
||||||
NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
|
NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
|
||||||
BBT_AUTO_REFRESH
|
|
||||||
},
|
|
||||||
|
|
||||||
{NULL,}
|
{NULL,}
|
||||||
};
|
};
|
||||||
|
@ -176,6 +175,9 @@ const struct nand_manufacturers nand_manuf_ids[] = {
|
||||||
{NAND_MFR_STMICRO, "ST Micro"},
|
{NAND_MFR_STMICRO, "ST Micro"},
|
||||||
{NAND_MFR_HYNIX, "Hynix"},
|
{NAND_MFR_HYNIX, "Hynix"},
|
||||||
{NAND_MFR_MICRON, "Micron"},
|
{NAND_MFR_MICRON, "Micron"},
|
||||||
{NAND_MFR_AMD, "AMD"},
|
{NAND_MFR_AMD, "AMD/Spansion"},
|
||||||
|
{NAND_MFR_MACRONIX, "Macronix"},
|
||||||
|
{NAND_MFR_EON, "Eon"},
|
||||||
{0x0, "Unknown"}
|
{0x0, "Unknown"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||||
WATCHDOG_RESET();
|
WATCHDOG_RESET();
|
||||||
|
|
||||||
if (!opts->scrub && bbtest) {
|
if (!opts->scrub && bbtest) {
|
||||||
int ret = meminfo->block_isbad(meminfo, erase.addr);
|
int ret = mtd_block_isbad(meminfo, erase.addr);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
if (!opts->quiet)
|
if (!opts->quiet)
|
||||||
printf("\rSkipping bad block at "
|
printf("\rSkipping bad block at "
|
||||||
|
@ -144,7 +144,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||||
|
|
||||||
erased_length++;
|
erased_length++;
|
||||||
|
|
||||||
result = meminfo->erase(meminfo, &erase);
|
result = mtd_erase(meminfo, &erase);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
printf("\n%s: MTD Erase failure: %d\n",
|
printf("\n%s: MTD Erase failure: %d\n",
|
||||||
mtd_device, result);
|
mtd_device, result);
|
||||||
|
@ -153,15 +153,16 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||||
|
|
||||||
/* format for JFFS2 ? */
|
/* format for JFFS2 ? */
|
||||||
if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
|
if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
|
||||||
chip->ops.ooblen = 8;
|
struct mtd_oob_ops ops;
|
||||||
chip->ops.datbuf = NULL;
|
ops.ooblen = 8;
|
||||||
chip->ops.oobbuf = (uint8_t *)&cleanmarker;
|
ops.datbuf = NULL;
|
||||||
chip->ops.ooboffs = 0;
|
ops.oobbuf = (uint8_t *)&cleanmarker;
|
||||||
chip->ops.mode = MTD_OOB_AUTO;
|
ops.ooboffs = 0;
|
||||||
|
ops.mode = MTD_OPS_AUTO_OOB;
|
||||||
|
|
||||||
result = meminfo->write_oob(meminfo,
|
result = mtd_write_oob(meminfo,
|
||||||
erase.addr,
|
erase.addr,
|
||||||
&chip->ops);
|
&ops);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
printf("\n%s: MTD writeoob failure: %d\n",
|
printf("\n%s: MTD writeoob failure: %d\n",
|
||||||
mtd_device, result);
|
mtd_device, result);
|
||||||
|
@ -605,7 +606,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
|
|
||||||
ops.len = pagesize;
|
ops.len = pagesize;
|
||||||
ops.ooblen = nand->oobsize;
|
ops.ooblen = nand->oobsize;
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OPS_AUTO_OOB;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
|
|
||||||
pages = write_size / pagesize_oob;
|
pages = write_size / pagesize_oob;
|
||||||
|
@ -615,7 +616,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
ops.datbuf = p_buffer;
|
ops.datbuf = p_buffer;
|
||||||
ops.oobbuf = ops.datbuf + pagesize;
|
ops.oobbuf = ops.datbuf + pagesize;
|
||||||
|
|
||||||
rval = nand->write_oob(nand, offset, &ops);
|
rval = mtd_write_oob(nand, offset, &ops);
|
||||||
if (rval != 0)
|
if (rval != 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||||
nand->ecc.mode = NAND_ECC_HW;
|
nand->ecc.mode = NAND_ECC_HW;
|
||||||
nand->ecc.size = 256;
|
nand->ecc.size = 256;
|
||||||
nand->ecc.bytes = 3;
|
nand->ecc.bytes = 3;
|
||||||
|
nand->ecc.strength = 1;
|
||||||
nand->select_chip = ndfc_select_chip;
|
nand->select_chip = ndfc_select_chip;
|
||||||
|
|
||||||
#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
|
#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
|
||||||
|
|
|
@ -212,6 +212,7 @@ int board_nand_init(struct nand_chip *chip)
|
||||||
chip->ecc.mode = NAND_ECC_HW;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
chip->ecc.layout = &nomadik_ecc_layout;
|
chip->ecc.layout = &nomadik_ecc_layout;
|
||||||
chip->ecc.calculate = nomadik_ecc_calculate;
|
chip->ecc.calculate = nomadik_ecc_calculate;
|
||||||
chip->ecc.hwctl = nomadik_ecc_hwctl;
|
chip->ecc.hwctl = nomadik_ecc_hwctl;
|
||||||
|
|
|
@ -590,11 +590,12 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
|
||||||
* @mtd: mtd info structure
|
* @mtd: mtd info structure
|
||||||
* @chip: nand chip info structure
|
* @chip: nand chip info structure
|
||||||
* @buf: buffer to store read data
|
* @buf: buffer to store read data
|
||||||
|
* @oob_required: caller expects OOB data read to chip->oob_poi
|
||||||
* @page: page number to read
|
* @page: page number to read
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint8_t *buf, int page)
|
uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
int i, eccsize = chip->ecc.size;
|
int i, eccsize = chip->ecc.size;
|
||||||
int eccbytes = chip->ecc.bytes;
|
int eccbytes = chip->ecc.bytes;
|
||||||
|
@ -804,6 +805,7 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
|
||||||
nand->ecc.hwctl = NULL;
|
nand->ecc.hwctl = NULL;
|
||||||
nand->ecc.correct = NULL;
|
nand->ecc.correct = NULL;
|
||||||
nand->ecc.calculate = NULL;
|
nand->ecc.calculate = NULL;
|
||||||
|
nand->ecc.strength = eccstrength;
|
||||||
|
|
||||||
/* Setup the ecc configurations again */
|
/* Setup the ecc configurations again */
|
||||||
if (hardware) {
|
if (hardware) {
|
||||||
|
@ -901,7 +903,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||||
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
|
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
|
||||||
|
|
||||||
nand->cmd_ctrl = omap_nand_hwcontrol;
|
nand->cmd_ctrl = omap_nand_hwcontrol;
|
||||||
nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
|
nand->options = NAND_NO_PADDING | NAND_CACHEPRG;
|
||||||
/* If we are 16 bit dev, our gpmc config tells us that */
|
/* If we are 16 bit dev, our gpmc config tells us that */
|
||||||
if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
|
if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
|
||||||
nand->options |= NAND_BUSWIDTH_16;
|
nand->options |= NAND_BUSWIDTH_16;
|
||||||
|
|
|
@ -173,6 +173,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||||
nand->ecc.mode = NAND_ECC_HW;
|
nand->ecc.mode = NAND_ECC_HW;
|
||||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||||
|
nand->ecc.strength = 1;
|
||||||
#else
|
#else
|
||||||
nand->ecc.mode = NAND_ECC_SOFT;
|
nand->ecc.mode = NAND_ECC_SOFT;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -707,7 +707,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* -EIO when command timeout
|
* -EIO when command timeout
|
||||||
*/
|
*/
|
||||||
static int nand_read_page_hwecc(struct mtd_info *mtd,
|
static int nand_read_page_hwecc(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, uint8_t *buf, int page)
|
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
return nand_rw_page(mtd, chip, buf, page, 1, 0);
|
return nand_rw_page(mtd, chip, buf, page, 1, 0);
|
||||||
}
|
}
|
||||||
|
@ -719,8 +719,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd,
|
||||||
* @param chip nand chip info structure
|
* @param chip nand chip info structure
|
||||||
* @param buf data buffer
|
* @param buf data buffer
|
||||||
*/
|
*/
|
||||||
static void nand_write_page_hwecc(struct mtd_info *mtd,
|
static int nand_write_page_hwecc(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, const uint8_t *buf)
|
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||||
{
|
{
|
||||||
int page;
|
int page;
|
||||||
struct nand_drv *info;
|
struct nand_drv *info;
|
||||||
|
@ -731,6 +731,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,
|
||||||
(readl(&info->reg->addr_reg2) << 16);
|
(readl(&info->reg->addr_reg2) << 16);
|
||||||
|
|
||||||
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1);
|
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -746,7 +747,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,
|
||||||
* -EIO when command timeout
|
* -EIO when command timeout
|
||||||
*/
|
*/
|
||||||
static int nand_read_page_raw(struct mtd_info *mtd,
|
static int nand_read_page_raw(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, uint8_t *buf, int page)
|
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||||
{
|
{
|
||||||
return nand_rw_page(mtd, chip, buf, page, 0, 0);
|
return nand_rw_page(mtd, chip, buf, page, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -758,8 +759,8 @@ static int nand_read_page_raw(struct mtd_info *mtd,
|
||||||
* @param chip nand chip info structure
|
* @param chip nand chip info structure
|
||||||
* @param buf data buffer
|
* @param buf data buffer
|
||||||
*/
|
*/
|
||||||
static void nand_write_page_raw(struct mtd_info *mtd,
|
static int nand_write_page_raw(struct mtd_info *mtd,
|
||||||
struct nand_chip *chip, const uint8_t *buf)
|
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||||
{
|
{
|
||||||
int page;
|
int page;
|
||||||
struct nand_drv *info;
|
struct nand_drv *info;
|
||||||
|
@ -769,6 +770,7 @@ static void nand_write_page_raw(struct mtd_info *mtd,
|
||||||
(readl(&info->reg->addr_reg2) << 16);
|
(readl(&info->reg->addr_reg2) << 16);
|
||||||
|
|
||||||
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1);
|
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -873,19 +875,13 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* @param mtd mtd info structure
|
* @param mtd mtd info structure
|
||||||
* @param chip nand chip info structure
|
* @param chip nand chip info structure
|
||||||
* @param page page number to read
|
* @param page page number to read
|
||||||
* @param sndcmd flag whether to issue read command or not
|
|
||||||
* @return 1 - issue read command next time
|
|
||||||
* 0 - not to issue
|
|
||||||
*/
|
*/
|
||||||
static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int page, int sndcmd)
|
int page)
|
||||||
{
|
{
|
||||||
if (sndcmd) {
|
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
||||||
sndcmd = 0;
|
|
||||||
}
|
|
||||||
nand_rw_oob(mtd, chip, page, 0, 0);
|
nand_rw_oob(mtd, chip, page, 0, 0);
|
||||||
return sndcmd;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1018,6 +1014,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
||||||
nand->ecc.write_page_raw = nand_write_page_raw;
|
nand->ecc.write_page_raw = nand_write_page_raw;
|
||||||
nand->ecc.read_oob = nand_read_oob;
|
nand->ecc.read_oob = nand_read_oob;
|
||||||
nand->ecc.write_oob = nand_write_oob;
|
nand->ecc.write_oob = nand_write_oob;
|
||||||
|
nand->ecc.strength = 1;
|
||||||
nand->select_chip = nand_select_chip;
|
nand->select_chip = nand_select_chip;
|
||||||
nand->dev_ready = nand_dev_ready;
|
nand->dev_ready = nand_dev_ready;
|
||||||
nand->priv = &nand_ctrl;
|
nand->priv = &nand_ctrl;
|
||||||
|
|
|
@ -224,7 +224,7 @@ enum {
|
||||||
#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8)
|
#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8)
|
||||||
#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF
|
#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF
|
||||||
|
|
||||||
#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR)
|
#define LP_OPTIONS 0
|
||||||
|
|
||||||
struct nand_ctlr {
|
struct nand_ctlr {
|
||||||
u32 command; /* offset 00h */
|
u32 command; /* offset 00h */
|
||||||
|
|
|
@ -743,7 +743,7 @@ static void onenand_release_device(struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
|
* onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
* @param buf destination address
|
* @param buf destination address
|
||||||
* @param column oob offset to read from
|
* @param column oob offset to read from
|
||||||
|
@ -807,7 +807,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
/* check if we failed due to uncorrectable error */
|
/* check if we failed due to uncorrectable error */
|
||||||
if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
|
if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
/* check if address lies in MLC region */
|
/* check if address lies in MLC region */
|
||||||
|
@ -847,7 +847,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
|
|
||||||
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
|
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_AUTO)
|
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||||
oobsize = this->ecclayout->oobavail;
|
oobsize = this->ecclayout->oobavail;
|
||||||
else
|
else
|
||||||
oobsize = mtd->oobsize;
|
oobsize = mtd->oobsize;
|
||||||
|
@ -914,7 +914,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
thisooblen = oobsize - oobcolumn;
|
thisooblen = oobsize - oobcolumn;
|
||||||
thisooblen = min_t(int, thisooblen, ooblen - oobread);
|
thisooblen = min_t(int, thisooblen, ooblen - oobread);
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_AUTO)
|
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||||
onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
|
onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
|
||||||
else
|
else
|
||||||
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
|
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
|
||||||
|
@ -929,7 +929,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
if (unlikely(ret))
|
if (unlikely(ret))
|
||||||
ret = onenand_recover_lsb(mtd, from, ret);
|
ret = onenand_recover_lsb(mtd, from, ret);
|
||||||
onenand_update_bufferram(mtd, from, !ret);
|
onenand_update_bufferram(mtd, from, !ret);
|
||||||
if (ret == -EBADMSG)
|
if (mtd_is_eccerr(ret))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,7 +950,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
/* Now wait for load */
|
/* Now wait for load */
|
||||||
ret = this->wait(mtd, FL_READING);
|
ret = this->wait(mtd, FL_READING);
|
||||||
onenand_update_bufferram(mtd, from, !ret);
|
onenand_update_bufferram(mtd, from, !ret);
|
||||||
if (ret == -EBADMSG)
|
if (mtd_is_eccerr(ret))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -987,7 +987,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
struct mtd_ecc_stats stats;
|
struct mtd_ecc_stats stats;
|
||||||
int read = 0, thislen, column, oobsize;
|
int read = 0, thislen, column, oobsize;
|
||||||
size_t len = ops->ooblen;
|
size_t len = ops->ooblen;
|
||||||
mtd_oob_mode_t mode = ops->mode;
|
unsigned int mode = ops->mode;
|
||||||
u_char *buf = ops->oobbuf;
|
u_char *buf = ops->oobbuf;
|
||||||
int ret = 0, readcmd;
|
int ret = 0, readcmd;
|
||||||
|
|
||||||
|
@ -998,7 +998,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
/* Initialize return length value */
|
/* Initialize return length value */
|
||||||
ops->oobretlen = 0;
|
ops->oobretlen = 0;
|
||||||
|
|
||||||
if (mode == MTD_OOB_AUTO)
|
if (mode == MTD_OPS_AUTO_OOB)
|
||||||
oobsize = this->ecclayout->oobavail;
|
oobsize = this->ecclayout->oobavail;
|
||||||
else
|
else
|
||||||
oobsize = mtd->oobsize;
|
oobsize = mtd->oobsize;
|
||||||
|
@ -1041,7 +1041,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == MTD_OOB_AUTO)
|
if (mode == MTD_OPS_AUTO_OOB)
|
||||||
onenand_transfer_auto_oob(mtd, buf, column, thislen);
|
onenand_transfer_auto_oob(mtd, buf, column, thislen);
|
||||||
else
|
else
|
||||||
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
|
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
|
||||||
|
@ -1115,10 +1115,10 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (ops->mode) {
|
switch (ops->mode) {
|
||||||
case MTD_OOB_PLACE:
|
case MTD_OPS_PLACE_OOB:
|
||||||
case MTD_OOB_AUTO:
|
case MTD_OPS_AUTO_OOB:
|
||||||
break;
|
break;
|
||||||
case MTD_OOB_RAW:
|
case MTD_OPS_RAW:
|
||||||
/* Not implemented yet */
|
/* Not implemented yet */
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1337,7 +1337,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
|
||||||
#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
|
#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_fill_auto_oob - [Internal] oob auto-placement transfer
|
* onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
* @param oob_buf oob buffer
|
* @param oob_buf oob buffer
|
||||||
* @param buf source address
|
* @param buf source address
|
||||||
|
@ -1404,19 +1404,13 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
||||||
ops->retlen = 0;
|
ops->retlen = 0;
|
||||||
ops->oobretlen = 0;
|
ops->oobretlen = 0;
|
||||||
|
|
||||||
/* Do not allow writes past end of device */
|
|
||||||
if (unlikely((to + len) > mtd->size)) {
|
|
||||||
printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reject writes, which are not page aligned */
|
/* Reject writes, which are not page aligned */
|
||||||
if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
|
if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
|
||||||
printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
|
printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_AUTO)
|
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||||
oobsize = this->ecclayout->oobavail;
|
oobsize = this->ecclayout->oobavail;
|
||||||
else
|
else
|
||||||
oobsize = mtd->oobsize;
|
oobsize = mtd->oobsize;
|
||||||
|
@ -1450,7 +1444,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
||||||
/* We send data to spare ram with oobsize
|
/* We send data to spare ram with oobsize
|
||||||
* * to prevent byte access */
|
* * to prevent byte access */
|
||||||
memset(oobbuf, 0xff, mtd->oobsize);
|
memset(oobbuf, 0xff, mtd->oobsize);
|
||||||
if (ops->mode == MTD_OOB_AUTO)
|
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||||
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
|
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
|
||||||
else
|
else
|
||||||
memcpy(oobbuf + oobcolumn, oob, thisooblen);
|
memcpy(oobbuf + oobcolumn, oob, thisooblen);
|
||||||
|
@ -1502,7 +1496,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
|
* onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
* @param to offset to write to
|
* @param to offset to write to
|
||||||
* @param len number of bytes to write
|
* @param len number of bytes to write
|
||||||
|
@ -1521,7 +1515,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
|
||||||
u_char *oobbuf;
|
u_char *oobbuf;
|
||||||
size_t len = ops->ooblen;
|
size_t len = ops->ooblen;
|
||||||
const u_char *buf = ops->oobbuf;
|
const u_char *buf = ops->oobbuf;
|
||||||
mtd_oob_mode_t mode = ops->mode;
|
unsigned int mode = ops->mode;
|
||||||
|
|
||||||
to += ops->ooboffs;
|
to += ops->ooboffs;
|
||||||
|
|
||||||
|
@ -1530,7 +1524,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
|
||||||
/* Initialize retlen, in case of early exit */
|
/* Initialize retlen, in case of early exit */
|
||||||
ops->oobretlen = 0;
|
ops->oobretlen = 0;
|
||||||
|
|
||||||
if (mode == MTD_OOB_AUTO)
|
if (mode == MTD_OPS_AUTO_OOB)
|
||||||
oobsize = this->ecclayout->oobavail;
|
oobsize = this->ecclayout->oobavail;
|
||||||
else
|
else
|
||||||
oobsize = mtd->oobsize;
|
oobsize = mtd->oobsize;
|
||||||
|
@ -1571,7 +1565,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
|
||||||
/* We send data to spare ram with oobsize
|
/* We send data to spare ram with oobsize
|
||||||
* to prevent byte access */
|
* to prevent byte access */
|
||||||
memset(oobbuf, 0xff, mtd->oobsize);
|
memset(oobbuf, 0xff, mtd->oobsize);
|
||||||
if (mode == MTD_OOB_AUTO)
|
if (mode == MTD_OPS_AUTO_OOB)
|
||||||
onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
|
onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
|
||||||
else
|
else
|
||||||
memcpy(oobbuf + column, buf, thislen);
|
memcpy(oobbuf + column, buf, thislen);
|
||||||
|
@ -1661,10 +1655,10 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (ops->mode) {
|
switch (ops->mode) {
|
||||||
case MTD_OOB_PLACE:
|
case MTD_OPS_PLACE_OOB:
|
||||||
case MTD_OOB_AUTO:
|
case MTD_OPS_AUTO_OOB:
|
||||||
break;
|
break;
|
||||||
case MTD_OOB_RAW:
|
case MTD_OPS_RAW:
|
||||||
/* Not implemented yet */
|
/* Not implemented yet */
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1720,13 +1714,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
|
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
|
||||||
(unsigned int) addr, len);
|
(unsigned int) addr, len);
|
||||||
|
|
||||||
/* Do not allow erase past end of device */
|
|
||||||
if (unlikely((len + addr) > mtd->size)) {
|
|
||||||
MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
|
|
||||||
"Erase past end of device\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FLEXONENAND(this)) {
|
if (FLEXONENAND(this)) {
|
||||||
/* Find the eraseregion of this address */
|
/* Find the eraseregion of this address */
|
||||||
i = flexonenand_region(mtd, addr);
|
i = flexonenand_region(mtd, addr);
|
||||||
|
@ -1762,8 +1749,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
instr->fail_addr = 0xffffffff;
|
|
||||||
|
|
||||||
/* Grab the lock and see if the device is available */
|
/* Grab the lock and see if the device is available */
|
||||||
onenand_get_device(mtd, FL_ERASING);
|
onenand_get_device(mtd, FL_ERASING);
|
||||||
|
|
||||||
|
@ -1889,7 +1874,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
struct bbm_info *bbm = this->bbm;
|
struct bbm_info *bbm = this->bbm;
|
||||||
u_char buf[2] = {0, 0};
|
u_char buf[2] = {0, 0};
|
||||||
struct mtd_oob_ops ops = {
|
struct mtd_oob_ops ops = {
|
||||||
.mode = MTD_OOB_PLACE,
|
.mode = MTD_OPS_PLACE_OOB,
|
||||||
.ooblen = 2,
|
.ooblen = 2,
|
||||||
.oobbuf = buf,
|
.oobbuf = buf,
|
||||||
.ooboffs = 0,
|
.ooboffs = 0,
|
||||||
|
@ -1915,7 +1900,6 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
*/
|
*/
|
||||||
int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
struct onenand_chip *this = mtd->priv;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = onenand_block_isbad(mtd, ofs);
|
ret = onenand_block_isbad(mtd, ofs);
|
||||||
|
@ -1926,7 +1910,7 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = this->block_markbad(mtd, ofs);
|
ret = mtd_block_markbad(mtd, ofs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2386,7 +2370,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
|
||||||
int i, ret;
|
int i, ret;
|
||||||
int block;
|
int block;
|
||||||
struct mtd_oob_ops ops = {
|
struct mtd_oob_ops ops = {
|
||||||
.mode = MTD_OOB_PLACE,
|
.mode = MTD_OPS_PLACE_OOB,
|
||||||
.ooboffs = 0,
|
.ooboffs = 0,
|
||||||
.ooblen = mtd->oobsize,
|
.ooblen = mtd->oobsize,
|
||||||
.datbuf = NULL,
|
.datbuf = NULL,
|
||||||
|
@ -2645,14 +2629,14 @@ int onenand_probe(struct mtd_info *mtd)
|
||||||
mtd->size = this->chipsize;
|
mtd->size = this->chipsize;
|
||||||
|
|
||||||
mtd->flags = MTD_CAP_NANDFLASH;
|
mtd->flags = MTD_CAP_NANDFLASH;
|
||||||
mtd->erase = onenand_erase;
|
mtd->_erase = onenand_erase;
|
||||||
mtd->read = onenand_read;
|
mtd->_read = onenand_read;
|
||||||
mtd->write = onenand_write;
|
mtd->_write = onenand_write;
|
||||||
mtd->read_oob = onenand_read_oob;
|
mtd->_read_oob = onenand_read_oob;
|
||||||
mtd->write_oob = onenand_write_oob;
|
mtd->_write_oob = onenand_write_oob;
|
||||||
mtd->sync = onenand_sync;
|
mtd->_sync = onenand_sync;
|
||||||
mtd->block_isbad = onenand_block_isbad;
|
mtd->_block_isbad = onenand_block_isbad;
|
||||||
mtd->block_markbad = onenand_block_markbad;
|
mtd->_block_markbad = onenand_block_markbad;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
|
||||||
startblock = 0;
|
startblock = 0;
|
||||||
from = 0;
|
from = 0;
|
||||||
|
|
||||||
ops.mode = MTD_OOB_PLACE;
|
ops.mode = MTD_OPS_PLACE_OOB;
|
||||||
ops.ooblen = readlen;
|
ops.ooblen = readlen;
|
||||||
ops.oobbuf = buf;
|
ops.oobbuf = buf;
|
||||||
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
|
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
|
||||||
|
@ -200,10 +200,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
len = this->chipsize >> (this->erase_shift + 2);
|
len = this->chipsize >> (this->erase_shift + 2);
|
||||||
/* Allocate memory (2bit per block) */
|
/* Allocate memory (2bit per block) */
|
||||||
bbm->bbt = malloc(len);
|
bbm->bbt = malloc(len);
|
||||||
if (!bbm->bbt) {
|
if (!bbm->bbt)
|
||||||
printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
/* Clear the memory bad block table */
|
/* Clear the memory bad block table */
|
||||||
memset(bbm->bbt, 0x00, len);
|
memset(bbm->bbt, 0x00, len);
|
||||||
|
|
||||||
|
|
|
@ -539,7 +539,7 @@ static int io_init(struct ubi_device *ubi)
|
||||||
ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);
|
ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);
|
||||||
ubi->flash_size = ubi->mtd->size;
|
ubi->flash_size = ubi->mtd->size;
|
||||||
|
|
||||||
if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
|
if (mtd_can_have_bb(ubi->mtd))
|
||||||
ubi->bad_allowed = 1;
|
ubi->bad_allowed = 1;
|
||||||
|
|
||||||
ubi->min_io_size = ubi->mtd->writesize;
|
ubi->min_io_size = ubi->mtd->writesize;
|
||||||
|
|
|
@ -460,7 +460,7 @@ retry:
|
||||||
if (err == UBI_IO_BITFLIPS) {
|
if (err == UBI_IO_BITFLIPS) {
|
||||||
scrub = 1;
|
scrub = 1;
|
||||||
err = 0;
|
err = 0;
|
||||||
} else if (err == -EBADMSG) {
|
} else if (mtd_is_eccerr(err)) {
|
||||||
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
|
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
scrub = 1;
|
scrub = 1;
|
||||||
|
|
|
@ -154,7 +154,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
|
||||||
|
|
||||||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||||
retry:
|
retry:
|
||||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
|
err = mtd_read(ubi->mtd, addr, len, &read, buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == -EUCLEAN) {
|
if (err == -EUCLEAN) {
|
||||||
/*
|
/*
|
||||||
|
@ -268,7 +268,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||||
err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
|
err = mtd_write(ubi->mtd, addr, len, &written, buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
|
ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
|
||||||
" %zd bytes", err, len, pnum, offset, written);
|
" %zd bytes", err, len, pnum, offset, written);
|
||||||
|
@ -318,7 +318,7 @@ retry:
|
||||||
ei.callback = erase_callback;
|
ei.callback = erase_callback;
|
||||||
ei.priv = (unsigned long)&wq;
|
ei.priv = (unsigned long)&wq;
|
||||||
|
|
||||||
err = ubi->mtd->erase(ubi->mtd, &ei);
|
err = mtd_erase(ubi->mtd, &ei);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (retries++ < UBI_IO_RETRIES) {
|
if (retries++ < UBI_IO_RETRIES) {
|
||||||
dbg_io("error %d while erasing PEB %d, retry",
|
dbg_io("error %d while erasing PEB %d, retry",
|
||||||
|
@ -516,7 +516,7 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)
|
||||||
if (ubi->bad_allowed) {
|
if (ubi->bad_allowed) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
|
ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ubi_err("error %d while checking if PEB %d is bad",
|
ubi_err("error %d while checking if PEB %d is bad",
|
||||||
ret, pnum);
|
ret, pnum);
|
||||||
|
@ -551,7 +551,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
|
||||||
if (!ubi->bad_allowed)
|
if (!ubi->bad_allowed)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
|
err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
|
||||||
if (err)
|
if (err)
|
||||||
ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
|
ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1242,7 +1242,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
|
||||||
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||||
|
|
||||||
mutex_lock(&ubi->dbg_buf_mutex);
|
mutex_lock(&ubi->dbg_buf_mutex);
|
||||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
|
err = mtd_read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
|
||||||
if (err && err != -EUCLEAN) {
|
if (err && err != -EUCLEAN) {
|
||||||
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
|
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
|
||||||
"read %zd bytes", err, len, pnum, offset, read);
|
"read %zd bytes", err, len, pnum, offset, read);
|
||||||
|
|
|
@ -349,7 +349,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
|
err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
|
||||||
if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
|
if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
|
||||||
ubi_warn("mark volume %d as corrupted", vol_id);
|
ubi_warn("mark volume %d as corrupted", vol_id);
|
||||||
vol->corrupted = 1;
|
vol->corrupted = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
|
||||||
|
|
||||||
err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
|
err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == -EBADMSG)
|
if (mtd_is_eccerr(err))
|
||||||
err = 1;
|
err = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,7 +388,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
|
||||||
|
|
||||||
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
|
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
|
||||||
ubi->vtbl_size);
|
ubi->vtbl_size);
|
||||||
if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
|
if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
|
||||||
/*
|
/*
|
||||||
* Scrub the PEB later. Note, -EBADMSG indicates an
|
* Scrub the PEB later. Note, -EBADMSG indicates an
|
||||||
* uncorrectable ECC error, but we have our own CRC and
|
* uncorrectable ECC error, but we have our own CRC and
|
||||||
|
|
|
@ -70,22 +70,22 @@ int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
|
||||||
u8 spareAsBytes[8]; /* OOB */
|
u8 spareAsBytes[8]; /* OOB */
|
||||||
|
|
||||||
if (data && !spare)
|
if (data && !spare)
|
||||||
retval = mtd->write(mtd, addr, dev->data_bytes_per_chunk,
|
retval = mtd_write(mtd, addr, dev->data_bytes_per_chunk,
|
||||||
&dummy, data);
|
&dummy, data);
|
||||||
else if (spare) {
|
else if (spare) {
|
||||||
if (dev->param.use_nand_ecc) {
|
if (dev->param.use_nand_ecc) {
|
||||||
translate_spare2oob(spare, spareAsBytes);
|
translate_spare2oob(spare, spareAsBytes);
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OPS_AUTO_OOB;
|
||||||
ops.ooblen = 8; /* temp hack */
|
ops.ooblen = 8; /* temp hack */
|
||||||
} else {
|
} else {
|
||||||
ops.mode = MTD_OOB_RAW;
|
ops.mode = MTD_OPS_RAW;
|
||||||
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||||
}
|
}
|
||||||
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
|
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
|
||||||
ops.datbuf = (u8 *)data;
|
ops.datbuf = (u8 *)data;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
ops.oobbuf = spareAsBytes;
|
ops.oobbuf = spareAsBytes;
|
||||||
retval = mtd->write_oob(mtd, addr, &ops);
|
retval = mtd_write_oob(mtd, addr, &ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
|
@ -106,21 +106,21 @@ int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
|
||||||
u8 spareAsBytes[8]; /* OOB */
|
u8 spareAsBytes[8]; /* OOB */
|
||||||
|
|
||||||
if (data && !spare)
|
if (data && !spare)
|
||||||
retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk,
|
retval = mtd_read(mtd, addr, dev->data_bytes_per_chunk,
|
||||||
&dummy, data);
|
&dummy, data);
|
||||||
else if (spare) {
|
else if (spare) {
|
||||||
if (dev->param.use_nand_ecc) {
|
if (dev->param.use_nand_ecc) {
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OPS_AUTO_OOB;
|
||||||
ops.ooblen = 8; /* temp hack */
|
ops.ooblen = 8; /* temp hack */
|
||||||
} else {
|
} else {
|
||||||
ops.mode = MTD_OOB_RAW;
|
ops.mode = MTD_OPS_RAW;
|
||||||
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||||
}
|
}
|
||||||
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
|
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
|
||||||
ops.datbuf = data;
|
ops.datbuf = data;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
ops.oobbuf = spareAsBytes;
|
ops.oobbuf = spareAsBytes;
|
||||||
retval = mtd->read_oob(mtd, addr, &ops);
|
retval = mtd_read_oob(mtd, addr, &ops);
|
||||||
if (dev->param.use_nand_ecc)
|
if (dev->param.use_nand_ecc)
|
||||||
translate_oob2spare(spare, spareAsBytes);
|
translate_oob2spare(spare, spareAsBytes);
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
|
||||||
/* Todo finish off the ei if required */
|
/* Todo finish off the ei if required */
|
||||||
|
|
||||||
|
|
||||||
retval = mtd->erase(mtd, &ei);
|
retval = mtd_erase(mtd, &ei);
|
||||||
|
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
|
|
|
@ -77,13 +77,13 @@ int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||||
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
|
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OPS_AUTO_OOB;
|
||||||
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
|
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
|
||||||
ops.len = dev->param.total_bytes_per_chunk;
|
ops.len = dev->param.total_bytes_per_chunk;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
ops.datbuf = (u8 *) data;
|
ops.datbuf = (u8 *) data;
|
||||||
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
|
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
|
||||||
retval = mtd->write_oob(mtd, addr, &ops);
|
retval = mtd_write_oob(mtd, addr, &ops);
|
||||||
|
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
|
@ -121,16 +121,16 @@ int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->param.inband_tags || (data && !tags))
|
if (dev->param.inband_tags || (data && !tags))
|
||||||
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
|
retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
|
||||||
&dummy, data);
|
&dummy, data);
|
||||||
else if (tags) {
|
else if (tags) {
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OPS_AUTO_OOB;
|
||||||
ops.ooblen = packed_tags_size;
|
ops.ooblen = packed_tags_size;
|
||||||
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
|
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
ops.datbuf = data;
|
ops.datbuf = data;
|
||||||
ops.oobbuf = local_spare;
|
ops.oobbuf = local_spare;
|
||||||
retval = mtd->read_oob(mtd, addr, &ops);
|
retval = mtd_read_oob(mtd, addr, &ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->param.inband_tags) {
|
if (dev->param.inband_tags) {
|
||||||
|
@ -179,7 +179,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
|
||||||
"nandmtd2_MarkNANDBlockBad %d", blockNo);
|
"nandmtd2_MarkNANDBlockBad %d", blockNo);
|
||||||
|
|
||||||
retval =
|
retval =
|
||||||
mtd->block_markbad(mtd,
|
mtd_block_markbad(mtd,
|
||||||
blockNo * dev->param.chunks_per_block *
|
blockNo * dev->param.chunks_per_block *
|
||||||
dev->data_bytes_per_chunk);
|
dev->data_bytes_per_chunk);
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
|
||||||
|
|
||||||
yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
|
yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
|
||||||
retval =
|
retval =
|
||||||
mtd->block_isbad(mtd,
|
mtd_block_isbad(mtd,
|
||||||
blockNo * dev->param.chunks_per_block *
|
blockNo * dev->param.chunks_per_block *
|
||||||
dev->data_bytes_per_chunk);
|
dev->data_bytes_per_chunk);
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,6 @@
|
||||||
#define CONFIG_SYS_HUSH_PARSER
|
#define CONFIG_SYS_HUSH_PARSER
|
||||||
|
|
||||||
/* Video */
|
/* Video */
|
||||||
#define CONFIG_FSL_DIU_FB
|
|
||||||
|
|
||||||
#ifdef CONFIG_FSL_DIU_FB
|
#ifdef CONFIG_FSL_DIU_FB
|
||||||
#define CONFIG_SYS_DIU_ADDR (CONFIG_SYS_CCSRBAR + 0x10000)
|
#define CONFIG_SYS_DIU_ADDR (CONFIG_SYS_CCSRBAR + 0x10000)
|
||||||
|
@ -336,7 +335,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_FSL_DIU_FB
|
#ifndef CONFIG_FSL_DIU_FB
|
||||||
#define CONFIG_ATI
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ATI
|
#ifdef CONFIG_ATI
|
||||||
|
|
|
@ -81,32 +81,53 @@ struct nand_bbt_descr {
|
||||||
#define NAND_BBT_LASTBLOCK 0x00000010
|
#define NAND_BBT_LASTBLOCK 0x00000010
|
||||||
/* The bbt is at the given page, else we must scan for the bbt */
|
/* The bbt is at the given page, else we must scan for the bbt */
|
||||||
#define NAND_BBT_ABSPAGE 0x00000020
|
#define NAND_BBT_ABSPAGE 0x00000020
|
||||||
/* The bbt is at the given page, else we must scan for the bbt */
|
|
||||||
#define NAND_BBT_SEARCH 0x00000040
|
|
||||||
/* bbt is stored per chip on multichip devices */
|
/* bbt is stored per chip on multichip devices */
|
||||||
#define NAND_BBT_PERCHIP 0x00000080
|
#define NAND_BBT_PERCHIP 0x00000080
|
||||||
/* bbt has a version counter at offset veroffs */
|
/* bbt has a version counter at offset veroffs */
|
||||||
#define NAND_BBT_VERSION 0x00000100
|
#define NAND_BBT_VERSION 0x00000100
|
||||||
/* Create a bbt if none exists */
|
/* Create a bbt if none exists */
|
||||||
#define NAND_BBT_CREATE 0x00000200
|
#define NAND_BBT_CREATE 0x00000200
|
||||||
|
/*
|
||||||
|
* Create an empty BBT with no vendor information. Vendor's information may be
|
||||||
|
* unavailable, for example, if the NAND controller has a different data and OOB
|
||||||
|
* layout or if this information is already purged. Must be used in conjunction
|
||||||
|
* with NAND_BBT_CREATE.
|
||||||
|
*/
|
||||||
|
#define NAND_BBT_CREATE_EMPTY 0x00000400
|
||||||
/* Search good / bad pattern through all pages of a block */
|
/* Search good / bad pattern through all pages of a block */
|
||||||
#define NAND_BBT_SCANALLPAGES 0x00000400
|
#define NAND_BBT_SCANALLPAGES 0x00000800
|
||||||
/* Scan block empty during good / bad block scan */
|
/* Scan block empty during good / bad block scan */
|
||||||
#define NAND_BBT_SCANEMPTY 0x00000800
|
#define NAND_BBT_SCANEMPTY 0x00001000
|
||||||
/* Write bbt if neccecary */
|
/* Write bbt if neccecary */
|
||||||
#define NAND_BBT_WRITE 0x00001000
|
#define NAND_BBT_WRITE 0x00002000
|
||||||
/* Read and write back block contents when writing bbt */
|
/* Read and write back block contents when writing bbt */
|
||||||
#define NAND_BBT_SAVECONTENT 0x00002000
|
#define NAND_BBT_SAVECONTENT 0x00004000
|
||||||
/* Search good / bad pattern on the first and the second page */
|
/* Search good / bad pattern on the first and the second page */
|
||||||
#define NAND_BBT_SCAN2NDPAGE 0x00004000
|
#define NAND_BBT_SCAN2NDPAGE 0x00008000
|
||||||
/* Search good / bad pattern on the last page of the eraseblock */
|
/* Search good / bad pattern on the last page of the eraseblock */
|
||||||
#define NAND_BBT_SCANLASTPAGE 0x00008000
|
#define NAND_BBT_SCANLASTPAGE 0x00010000
|
||||||
/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */
|
/*
|
||||||
#define NAND_BBT_SCANBYTE1AND6 0x00100000
|
* Use a flash based bad block table. By default, OOB identifier is saved in
|
||||||
/* The nand_bbt_descr was created dynamicaly and must be freed */
|
* OOB area. This option is passed to the default bad block table function.
|
||||||
#define NAND_BBT_DYNAMICSTRUCT 0x00200000
|
*/
|
||||||
/* The bad block table does not OOB for marker */
|
#define NAND_BBT_USE_FLASH 0x00020000
|
||||||
#define NAND_BBT_NO_OOB 0x00400000
|
/*
|
||||||
|
* Do not store flash based bad block table marker in the OOB area; store it
|
||||||
|
* in-band.
|
||||||
|
*/
|
||||||
|
#define NAND_BBT_NO_OOB 0x00040000
|
||||||
|
/*
|
||||||
|
* Do not write new bad block markers to OOB; useful, e.g., when ECC covers
|
||||||
|
* entire spare area. Must be used with NAND_BBT_USE_FLASH.
|
||||||
|
*/
|
||||||
|
#define NAND_BBT_NO_OOB_BBM 0x00080000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
|
||||||
|
* was allocated dynamicaly and must be freed in nand_release(). Has no meaning
|
||||||
|
* in nand_chip.bbt_options.
|
||||||
|
*/
|
||||||
|
#define NAND_BBT_DYNAMICSTRUCT 0x80000000
|
||||||
|
|
||||||
/* The maximum number of blocks to scan for a bbt */
|
/* The maximum number of blocks to scan for a bbt */
|
||||||
#define NAND_BBT_SCAN_MAXBLOCKS 4
|
#define NAND_BBT_SCAN_MAXBLOCKS 4
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <div64.h>
|
#include <div64.h>
|
||||||
#include <linux/mtd/mtd-abi.h>
|
#include <mtd/mtd-abi.h>
|
||||||
|
#include <asm/errno.h>
|
||||||
|
|
||||||
#define MTD_CHAR_MAJOR 90
|
#define MTD_CHAR_MAJOR 90
|
||||||
#define MTD_BLOCK_MAJOR 31
|
#define MTD_BLOCK_MAJOR 31
|
||||||
|
@ -65,22 +66,6 @@ struct mtd_erase_region_info {
|
||||||
unsigned long *lockmap; /* If keeping bitmap of locks */
|
unsigned long *lockmap; /* If keeping bitmap of locks */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* oob operation modes
|
|
||||||
*
|
|
||||||
* MTD_OOB_PLACE: oob data are placed at the given offset
|
|
||||||
* MTD_OOB_AUTO: oob data are automatically placed at the free areas
|
|
||||||
* which are defined by the ecclayout
|
|
||||||
* MTD_OOB_RAW: mode to read raw data+oob in one chunk. The oob data
|
|
||||||
* is inserted into the data. Thats a raw image of the
|
|
||||||
* flash contents.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
MTD_OOB_PLACE,
|
|
||||||
MTD_OOB_AUTO,
|
|
||||||
MTD_OOB_RAW,
|
|
||||||
} mtd_oob_mode_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct mtd_oob_ops - oob operation operands
|
* struct mtd_oob_ops - oob operation operands
|
||||||
* @mode: operation mode
|
* @mode: operation mode
|
||||||
|
@ -92,7 +77,7 @@ typedef enum {
|
||||||
* @ooblen: number of oob bytes to write/read
|
* @ooblen: number of oob bytes to write/read
|
||||||
* @oobretlen: number of oob bytes written/read
|
* @oobretlen: number of oob bytes written/read
|
||||||
* @ooboffs: offset of oob data in the oob area (only relevant when
|
* @ooboffs: offset of oob data in the oob area (only relevant when
|
||||||
* mode = MTD_OOB_PLACE)
|
* mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW)
|
||||||
* @datbuf: data buffer - if NULL only oob data are read/written
|
* @datbuf: data buffer - if NULL only oob data are read/written
|
||||||
* @oobbuf: oob data buffer
|
* @oobbuf: oob data buffer
|
||||||
*
|
*
|
||||||
|
@ -101,7 +86,7 @@ typedef enum {
|
||||||
* OOB area.
|
* OOB area.
|
||||||
*/
|
*/
|
||||||
struct mtd_oob_ops {
|
struct mtd_oob_ops {
|
||||||
mtd_oob_mode_t mode;
|
unsigned int mode;
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
size_t ooblen;
|
size_t ooblen;
|
||||||
|
@ -133,13 +118,25 @@ struct mtd_info {
|
||||||
u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
|
u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
|
||||||
u_int32_t oobavail; /* Available OOB bytes per block */
|
u_int32_t oobavail; /* Available OOB bytes per block */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read ops return -EUCLEAN if max number of bitflips corrected on any
|
||||||
|
* one region comprising an ecc step equals or exceeds this value.
|
||||||
|
* Settable by driver, else defaults to ecc_strength. User can override
|
||||||
|
* in sysfs. N.B. The meaning of the -EUCLEAN return code has changed;
|
||||||
|
* see Documentation/ABI/testing/sysfs-class-mtd for more detail.
|
||||||
|
*/
|
||||||
|
unsigned int bitflip_threshold;
|
||||||
|
|
||||||
/* Kernel-only stuff starts here. */
|
/* Kernel-only stuff starts here. */
|
||||||
const char *name;
|
const char *name;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
/* ecc layout structure pointer - read only ! */
|
/* ECC layout structure pointer - read only! */
|
||||||
struct nand_ecclayout *ecclayout;
|
struct nand_ecclayout *ecclayout;
|
||||||
|
|
||||||
|
/* max number of correctible bit errors per ecc step */
|
||||||
|
unsigned int ecc_strength;
|
||||||
|
|
||||||
/* Data for variable erase regions. If numeraseregions is zero,
|
/* Data for variable erase regions. If numeraseregions is zero,
|
||||||
* it means that the whole device has erasesize as given above.
|
* it means that the whole device has erasesize as given above.
|
||||||
*/
|
*/
|
||||||
|
@ -147,25 +144,17 @@ struct mtd_info {
|
||||||
struct mtd_erase_region_info *eraseregions;
|
struct mtd_erase_region_info *eraseregions;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Erase is an asynchronous operation. Device drivers are supposed
|
* Do not call via these pointers, use corresponding mtd_*()
|
||||||
* to call instr->callback() whenever the operation completes, even
|
* wrappers instead.
|
||||||
* if it completes with a failure.
|
|
||||||
* Callers are supposed to pass a callback function and wait for it
|
|
||||||
* to be called before writing to the block.
|
|
||||||
*/
|
*/
|
||||||
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
|
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||||
|
int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
/* This stuff for eXecute-In-Place */
|
|
||||||
/* phys is optional and may be set to NULL */
|
|
||||||
int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
|
|
||||||
size_t *retlen, void **virt, phys_addr_t *phys);
|
size_t *retlen, void **virt, phys_addr_t *phys);
|
||||||
|
void (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||||
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
|
int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
size_t *retlen, u_char *buf);
|
||||||
|
int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, const u_char *buf);
|
||||||
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
|
||||||
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
|
||||||
|
|
||||||
/* In blackbox flight recorder like scenarios we want to make successful
|
/* In blackbox flight recorder like scenarios we want to make successful
|
||||||
writes in interrupt context. panic_write() is only intended to be
|
writes in interrupt context. panic_write() is only intended to be
|
||||||
|
@ -174,24 +163,35 @@ struct mtd_info {
|
||||||
longer, this function can break locks and delay to ensure the write
|
longer, this function can break locks and delay to ensure the write
|
||||||
succeeds (but not sleep). */
|
succeeds (but not sleep). */
|
||||||
|
|
||||||
int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
||||||
|
|
||||||
int (*read_oob) (struct mtd_info *mtd, loff_t from,
|
int (*_read_oob) (struct mtd_info *mtd, loff_t from,
|
||||||
struct mtd_oob_ops *ops);
|
struct mtd_oob_ops *ops);
|
||||||
int (*write_oob) (struct mtd_info *mtd, loff_t to,
|
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
|
||||||
struct mtd_oob_ops *ops);
|
struct mtd_oob_ops *ops);
|
||||||
|
int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len);
|
||||||
|
int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||||
|
size_t len, size_t *retlen, u_char *buf);
|
||||||
|
int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len);
|
||||||
|
int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||||
|
size_t len, size_t *retlen, u_char *buf);
|
||||||
|
int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, u_char *buf);
|
||||||
|
int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||||
|
size_t len);
|
||||||
|
void (*_sync) (struct mtd_info *mtd);
|
||||||
|
int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||||
|
int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||||
|
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||||
|
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||||
/*
|
/*
|
||||||
* Methods to access the protection register area, present in some
|
* If the driver is something smart, like UBI, it may need to maintain
|
||||||
* flash devices. The user data is one time programmable but the
|
* its own reference counting. The below functions are only for driver.
|
||||||
* factory data is read only.
|
|
||||||
*/
|
*/
|
||||||
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
|
int (*_get_device) (struct mtd_info *mtd);
|
||||||
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
void (*_put_device) (struct mtd_info *mtd);
|
||||||
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
|
|
||||||
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
|
||||||
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
|
||||||
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
|
|
||||||
|
|
||||||
/* XXX U-BOOT XXX */
|
/* XXX U-BOOT XXX */
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -201,18 +201,6 @@ struct mtd_info {
|
||||||
*/
|
*/
|
||||||
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
|
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Sync */
|
|
||||||
void (*sync) (struct mtd_info *mtd);
|
|
||||||
|
|
||||||
/* Chip-supported device locking */
|
|
||||||
int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
|
||||||
int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
|
||||||
|
|
||||||
/* Bad block management functions */
|
|
||||||
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
|
||||||
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
|
||||||
|
|
||||||
/* XXX U-BOOT XXX */
|
/* XXX U-BOOT XXX */
|
||||||
#if 0
|
#if 0
|
||||||
struct notifier_block reboot_notifier; /* default mode before reboot */
|
struct notifier_block reboot_notifier; /* default mode before reboot */
|
||||||
|
@ -227,15 +215,59 @@ struct mtd_info {
|
||||||
|
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
int usecount;
|
int usecount;
|
||||||
|
|
||||||
/* If the driver is something smart, like UBI, it may need to maintain
|
|
||||||
* its own reference counting. The below functions are only for driver.
|
|
||||||
* The driver may register its callbacks. These callbacks are not
|
|
||||||
* supposed to be called by MTD users */
|
|
||||||
int (*get_device) (struct mtd_info *mtd);
|
|
||||||
void (*put_device) (struct mtd_info *mtd);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||||
|
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||||
|
u_char *buf);
|
||||||
|
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
const u_char *buf);
|
||||||
|
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
const u_char *buf);
|
||||||
|
|
||||||
|
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
|
||||||
|
|
||||||
|
static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
|
struct mtd_oob_ops *ops)
|
||||||
|
{
|
||||||
|
ops->retlen = ops->oobretlen = 0;
|
||||||
|
if (!mtd->_write_oob)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
return mtd->_write_oob(mtd, to, ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len);
|
||||||
|
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, u_char *buf);
|
||||||
|
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len);
|
||||||
|
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, u_char *buf);
|
||||||
|
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, u_char *buf);
|
||||||
|
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
|
||||||
|
|
||||||
|
/* XXX U-BOOT XXX */
|
||||||
|
#if 0
|
||||||
|
int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||||
|
unsigned long count, loff_t to, size_t *retlen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void mtd_sync(struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
if (mtd->_sync)
|
||||||
|
mtd->_sync(mtd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||||
|
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||||
|
int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||||
|
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
|
||||||
|
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
|
||||||
|
|
||||||
static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
|
static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
do_div(sz, mtd->erasesize);
|
do_div(sz, mtd->erasesize);
|
||||||
|
@ -247,6 +279,16 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||||
return do_div(sz, mtd->erasesize);
|
return do_div(sz, mtd->erasesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int mtd_has_oob(const struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
return mtd->_read_oob && mtd->_write_oob;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mtd_can_have_bb(const struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
return !!mtd->_block_isbad;
|
||||||
|
}
|
||||||
|
|
||||||
/* Kernel-side ioctl definitions */
|
/* Kernel-side ioctl definitions */
|
||||||
|
|
||||||
extern int add_mtd_device(struct mtd_info *mtd);
|
extern int add_mtd_device(struct mtd_info *mtd);
|
||||||
|
@ -269,12 +311,6 @@ struct mtd_notifier {
|
||||||
|
|
||||||
extern void register_mtd_user (struct mtd_notifier *new);
|
extern void register_mtd_user (struct mtd_notifier *new);
|
||||||
extern int unregister_mtd_user (struct mtd_notifier *old);
|
extern int unregister_mtd_user (struct mtd_notifier *old);
|
||||||
|
|
||||||
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
|
||||||
unsigned long count, loff_t to, size_t *retlen);
|
|
||||||
|
|
||||||
int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
|
|
||||||
unsigned long count, loff_t from, size_t *retlen);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_PARTITIONS
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
|
@ -296,17 +332,34 @@ static inline void mtd_erase_callback(struct erase_info *instr)
|
||||||
#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
|
#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_DEBUG
|
#ifdef CONFIG_MTD_DEBUG
|
||||||
|
#define pr_debug(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||||
#define MTDDEBUG(n, args...) \
|
#define MTDDEBUG(n, args...) \
|
||||||
do { \
|
do { \
|
||||||
if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
|
if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
|
||||||
printk(KERN_INFO args); \
|
printk(KERN_INFO args); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#else /* CONFIG_MTD_DEBUG */
|
#else /* CONFIG_MTD_DEBUG */
|
||||||
|
#define pr_debug(args...)
|
||||||
#define MTDDEBUG(n, args...) \
|
#define MTDDEBUG(n, args...) \
|
||||||
do { \
|
do { \
|
||||||
if (0) \
|
if (0) \
|
||||||
printk(KERN_INFO args); \
|
printk(KERN_INFO args); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif /* CONFIG_MTD_DEBUG */
|
#endif /* CONFIG_MTD_DEBUG */
|
||||||
|
#define pr_info(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||||
|
#define pr_warn(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||||
|
#define pr_err(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||||
|
|
||||||
|
static inline int mtd_is_bitflip(int err) {
|
||||||
|
return err == -EUCLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mtd_is_eccerr(int err) {
|
||||||
|
return err == -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mtd_is_bitflip_or_eccerr(int err) {
|
||||||
|
return mtd_is_bitflip(err) || mtd_is_eccerr(err);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __MTD_MTD_H__ */
|
#endif /* __MTD_MTD_H__ */
|
||||||
|
|
|
@ -46,7 +46,7 @@ extern void nand_wait_ready(struct mtd_info *mtd);
|
||||||
* is supported now. If you add a chip with bigger oobsize/page
|
* is supported now. If you add a chip with bigger oobsize/page
|
||||||
* adjust this accordingly.
|
* adjust this accordingly.
|
||||||
*/
|
*/
|
||||||
#define NAND_MAX_OOBSIZE 576
|
#define NAND_MAX_OOBSIZE 640
|
||||||
#define NAND_MAX_PAGESIZE 8192
|
#define NAND_MAX_PAGESIZE 8192
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,6 +82,8 @@ extern void nand_wait_ready(struct mtd_info *mtd);
|
||||||
#define NAND_CMD_READID 0x90
|
#define NAND_CMD_READID 0x90
|
||||||
#define NAND_CMD_ERASE2 0xd0
|
#define NAND_CMD_ERASE2 0xd0
|
||||||
#define NAND_CMD_PARAM 0xec
|
#define NAND_CMD_PARAM 0xec
|
||||||
|
#define NAND_CMD_GET_FEATURES 0xee
|
||||||
|
#define NAND_CMD_SET_FEATURES 0xef
|
||||||
#define NAND_CMD_RESET 0xff
|
#define NAND_CMD_RESET 0xff
|
||||||
|
|
||||||
#define NAND_CMD_LOCK 0x2a
|
#define NAND_CMD_LOCK 0x2a
|
||||||
|
@ -142,7 +144,7 @@ typedef enum {
|
||||||
#define NAND_ECC_READ 0
|
#define NAND_ECC_READ 0
|
||||||
/* Reset Hardware ECC for write */
|
/* Reset Hardware ECC for write */
|
||||||
#define NAND_ECC_WRITE 1
|
#define NAND_ECC_WRITE 1
|
||||||
/* Enable Hardware ECC before syndrom is read back from flash */
|
/* Enable Hardware ECC before syndrome is read back from flash */
|
||||||
#define NAND_ECC_READSYN 2
|
#define NAND_ECC_READSYN 2
|
||||||
|
|
||||||
/* Bit mask for flags passed to do_nand_read_ecc */
|
/* Bit mask for flags passed to do_nand_read_ecc */
|
||||||
|
@ -153,9 +155,7 @@ typedef enum {
|
||||||
* Option constants for bizarre disfunctionality and real
|
* Option constants for bizarre disfunctionality and real
|
||||||
* features.
|
* features.
|
||||||
*/
|
*/
|
||||||
/* Chip can not auto increment pages */
|
/* Buswidth is 16 bit */
|
||||||
#define NAND_NO_AUTOINCR 0x00000001
|
|
||||||
/* Buswitdh is 16 bit */
|
|
||||||
#define NAND_BUSWIDTH_16 0x00000002
|
#define NAND_BUSWIDTH_16 0x00000002
|
||||||
/* Device supports partial programming without padding */
|
/* Device supports partial programming without padding */
|
||||||
#define NAND_NO_PADDING 0x00000004
|
#define NAND_NO_PADDING 0x00000004
|
||||||
|
@ -179,12 +179,6 @@ typedef enum {
|
||||||
* This happens with the Renesas AG-AND chips, possibly others.
|
* This happens with the Renesas AG-AND chips, possibly others.
|
||||||
*/
|
*/
|
||||||
#define BBT_AUTO_REFRESH 0x00000080
|
#define BBT_AUTO_REFRESH 0x00000080
|
||||||
/*
|
|
||||||
* Chip does not require ready check on read. true
|
|
||||||
* for all large page devices, as they do not support
|
|
||||||
* autoincrement.
|
|
||||||
*/
|
|
||||||
#define NAND_NO_READRDY 0x00000100
|
|
||||||
/* Chip does not allow subpage writes */
|
/* Chip does not allow subpage writes */
|
||||||
#define NAND_NO_SUBPAGE_WRITE 0x00000200
|
#define NAND_NO_SUBPAGE_WRITE 0x00000200
|
||||||
|
|
||||||
|
@ -202,34 +196,21 @@ typedef enum {
|
||||||
(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
|
(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
|
||||||
|
|
||||||
/* Macros to identify the above */
|
/* Macros to identify the above */
|
||||||
#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
|
|
||||||
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
|
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
|
||||||
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
|
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
|
||||||
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
|
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
|
||||||
#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
|
#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
|
||||||
|
|
||||||
/* Non chip related options */
|
/* Non chip related options */
|
||||||
/*
|
|
||||||
* Use a flash based bad block table. OOB identifier is saved in OOB area.
|
|
||||||
* This option is passed to the default bad block table function.
|
|
||||||
*/
|
|
||||||
#define NAND_USE_FLASH_BBT 0x00010000
|
|
||||||
/* This option skips the bbt scan during initialization. */
|
/* This option skips the bbt scan during initialization. */
|
||||||
#define NAND_SKIP_BBTSCAN 0x00020000
|
#define NAND_SKIP_BBTSCAN 0x00010000
|
||||||
/*
|
/*
|
||||||
* This option is defined if the board driver allocates its own buffers
|
* This option is defined if the board driver allocates its own buffers
|
||||||
* (e.g. because it needs them DMA-coherent).
|
* (e.g. because it needs them DMA-coherent).
|
||||||
*/
|
*/
|
||||||
#define NAND_OWN_BUFFERS 0x00040000
|
#define NAND_OWN_BUFFERS 0x00020000
|
||||||
/* Chip may not exist, so silence any errors in scan */
|
/* Chip may not exist, so silence any errors in scan */
|
||||||
#define NAND_SCAN_SILENT_NODEV 0x00080000
|
#define NAND_SCAN_SILENT_NODEV 0x00040000
|
||||||
/*
|
|
||||||
* If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch
|
|
||||||
* the OOB area.
|
|
||||||
*/
|
|
||||||
#define NAND_USE_FLASH_BBT_NO_OOB 0x00800000
|
|
||||||
/* Create an empty BBT with no vendor information if the BBT is available */
|
|
||||||
#define NAND_CREATE_EMPTY_BBT 0x01000000
|
|
||||||
|
|
||||||
/* Options set by nand scan */
|
/* Options set by nand scan */
|
||||||
/* bbt has already been read */
|
/* bbt has already been read */
|
||||||
|
@ -244,6 +225,21 @@ typedef enum {
|
||||||
/* Keep gcc happy */
|
/* Keep gcc happy */
|
||||||
struct nand_chip;
|
struct nand_chip;
|
||||||
|
|
||||||
|
/* ONFI timing mode, used in both asynchronous and synchronous mode */
|
||||||
|
#define ONFI_TIMING_MODE_0 (1 << 0)
|
||||||
|
#define ONFI_TIMING_MODE_1 (1 << 1)
|
||||||
|
#define ONFI_TIMING_MODE_2 (1 << 2)
|
||||||
|
#define ONFI_TIMING_MODE_3 (1 << 3)
|
||||||
|
#define ONFI_TIMING_MODE_4 (1 << 4)
|
||||||
|
#define ONFI_TIMING_MODE_5 (1 << 5)
|
||||||
|
#define ONFI_TIMING_MODE_UNKNOWN (1 << 6)
|
||||||
|
|
||||||
|
/* ONFI feature address */
|
||||||
|
#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1
|
||||||
|
|
||||||
|
/* ONFI subfeature parameters length */
|
||||||
|
#define ONFI_SUBFEATURE_PARAM_LEN 4
|
||||||
|
|
||||||
struct nand_onfi_params {
|
struct nand_onfi_params {
|
||||||
/* rev info and features block */
|
/* rev info and features block */
|
||||||
/* 'O' 'N' 'F' 'I' */
|
/* 'O' 'N' 'F' 'I' */
|
||||||
|
@ -326,27 +322,32 @@ struct nand_hw_control {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_ecc_ctrl - Control structure for ecc
|
* struct nand_ecc_ctrl - Control structure for ECC
|
||||||
* @mode: ecc mode
|
* @mode: ECC mode
|
||||||
* @steps: number of ecc steps per page
|
* @steps: number of ECC steps per page
|
||||||
* @size: data bytes per ecc step
|
* @size: data bytes per ECC step
|
||||||
* @bytes: ecc bytes per step
|
* @bytes: ECC bytes per step
|
||||||
* @total: total number of ecc bytes per page
|
* @strength: max number of correctible bits per ECC step
|
||||||
* @prepad: padding information for syndrome based ecc generators
|
* @total: total number of ECC bytes per page
|
||||||
* @postpad: padding information for syndrome based ecc generators
|
* @prepad: padding information for syndrome based ECC generators
|
||||||
|
* @postpad: padding information for syndrome based ECC generators
|
||||||
* @layout: ECC layout control struct pointer
|
* @layout: ECC layout control struct pointer
|
||||||
* @priv: pointer to private ecc control data
|
* @priv: pointer to private ECC control data
|
||||||
* @hwctl: function to control hardware ecc generator. Must only
|
* @hwctl: function to control hardware ECC generator. Must only
|
||||||
* be provided if an hardware ECC is available
|
* be provided if an hardware ECC is available
|
||||||
* @calculate: function for ecc calculation or readback from ecc hardware
|
* @calculate: function for ECC calculation or readback from ECC hardware
|
||||||
* @correct: function for ecc correction, matching to ecc generator (sw/hw)
|
* @correct: function for ECC correction, matching to ECC generator (sw/hw)
|
||||||
* @read_page_raw: function to read a raw page without ECC
|
* @read_page_raw: function to read a raw page without ECC
|
||||||
* @write_page_raw: function to write a raw page without ECC
|
* @write_page_raw: function to write a raw page without ECC
|
||||||
* @read_page: function to read a page according to the ecc generator
|
* @read_page: function to read a page according to the ECC generator
|
||||||
* requirements.
|
* requirements; returns maximum number of bitflips corrected in
|
||||||
* @read_subpage: function to read parts of the page covered by ECC.
|
* any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
|
||||||
* @write_page: function to write a page according to the ecc generator
|
* @read_subpage: function to read parts of the page covered by ECC;
|
||||||
|
* returns same as read_page()
|
||||||
|
* @write_page: function to write a page according to the ECC generator
|
||||||
* requirements.
|
* requirements.
|
||||||
|
* @write_oob_raw: function to write chip OOB data without ECC
|
||||||
|
* @read_oob_raw: function to read chip OOB data without ECC
|
||||||
* @read_oob: function to read chip OOB data
|
* @read_oob: function to read chip OOB data
|
||||||
* @write_oob: function to write chip OOB data
|
* @write_oob: function to write chip OOB data
|
||||||
*/
|
*/
|
||||||
|
@ -356,6 +357,7 @@ struct nand_ecc_ctrl {
|
||||||
int size;
|
int size;
|
||||||
int bytes;
|
int bytes;
|
||||||
int total;
|
int total;
|
||||||
|
int strength;
|
||||||
int prepad;
|
int prepad;
|
||||||
int postpad;
|
int postpad;
|
||||||
struct nand_ecclayout *layout;
|
struct nand_ecclayout *layout;
|
||||||
|
@ -366,25 +368,28 @@ struct nand_ecc_ctrl {
|
||||||
int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
|
int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
|
||||||
uint8_t *calc_ecc);
|
uint8_t *calc_ecc);
|
||||||
int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint8_t *buf, int page);
|
uint8_t *buf, int oob_required, int page);
|
||||||
void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf);
|
const uint8_t *buf, int oob_required);
|
||||||
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint8_t *buf, int page);
|
uint8_t *buf, int oob_required, int page);
|
||||||
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint32_t offs, uint32_t len, uint8_t *buf);
|
uint32_t offs, uint32_t len, uint8_t *buf);
|
||||||
void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf);
|
const uint8_t *buf, int oob_required);
|
||||||
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
|
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int sndcmd);
|
int page);
|
||||||
|
int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
int page);
|
||||||
|
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
|
||||||
int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int page);
|
int page);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_buffers - buffer structure for read/write
|
* struct nand_buffers - buffer structure for read/write
|
||||||
* @ecccalc: buffer for calculated ecc
|
* @ecccalc: buffer for calculated ECC
|
||||||
* @ecccode: buffer for ecc read from flash
|
* @ecccode: buffer for ECC read from flash
|
||||||
* @databuf: buffer for data - dynamically sized
|
* @databuf: buffer for data - dynamically sized
|
||||||
*
|
*
|
||||||
* Do not change the order of buffers. databuf and oobrbuf must be in
|
* Do not change the order of buffers. databuf and oobrbuf must be in
|
||||||
|
@ -418,7 +423,7 @@ struct nand_buffers {
|
||||||
* mtd->oobsize, mtd->writesize and so on.
|
* mtd->oobsize, mtd->writesize and so on.
|
||||||
* @id_data contains the 8 bytes values of NAND_CMD_READID.
|
* @id_data contains the 8 bytes values of NAND_CMD_READID.
|
||||||
* Return with the bus width.
|
* Return with the bus width.
|
||||||
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing
|
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing
|
||||||
* device ready/busy line. If set to NULL no access to
|
* device ready/busy line. If set to NULL no access to
|
||||||
* ready/busy is available and the ready/busy information
|
* ready/busy is available and the ready/busy information
|
||||||
* is read from the chip status register.
|
* is read from the chip status register.
|
||||||
|
@ -426,17 +431,17 @@ struct nand_buffers {
|
||||||
* commands to the chip.
|
* commands to the chip.
|
||||||
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on
|
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on
|
||||||
* ready.
|
* ready.
|
||||||
* @ecc: [BOARDSPECIFIC] ecc control ctructure
|
* @ecc: [BOARDSPECIFIC] ECC control structure
|
||||||
* @buffers: buffer structure for read/write
|
* @buffers: buffer structure for read/write
|
||||||
* @hwcontrol: platform-specific hardware control structure
|
* @hwcontrol: platform-specific hardware control structure
|
||||||
* @ops: oob operation operands
|
|
||||||
* @erase_cmd: [INTERN] erase command write function, selectable due
|
* @erase_cmd: [INTERN] erase command write function, selectable due
|
||||||
* to AND support.
|
* to AND support.
|
||||||
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
||||||
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring
|
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring
|
||||||
* data from array to read regs (tR).
|
* data from array to read regs (tR).
|
||||||
* @state: [INTERN] the current state of the NAND device
|
* @state: [INTERN] the current state of the NAND device
|
||||||
* @oob_poi: poison value buffer
|
* @oob_poi: "poison value buffer," used for laying out OOB data
|
||||||
|
* before writing
|
||||||
* @page_shift: [INTERN] number of address bits in a page (column
|
* @page_shift: [INTERN] number of address bits in a page (column
|
||||||
* address bits).
|
* address bits).
|
||||||
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
|
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
|
||||||
|
@ -445,10 +450,14 @@ struct nand_buffers {
|
||||||
* @options: [BOARDSPECIFIC] various chip options. They can partly
|
* @options: [BOARDSPECIFIC] various chip options. They can partly
|
||||||
* be set to inform nand_scan about special functionality.
|
* be set to inform nand_scan about special functionality.
|
||||||
* See the defines for further explanation.
|
* See the defines for further explanation.
|
||||||
|
* @bbt_options: [INTERN] bad block specific options. All options used
|
||||||
|
* here must come from bbm.h. By default, these options
|
||||||
|
* will be copied to the appropriate nand_bbt_descr's.
|
||||||
* @badblockpos: [INTERN] position of the bad block marker in the oob
|
* @badblockpos: [INTERN] position of the bad block marker in the oob
|
||||||
* area.
|
* area.
|
||||||
* @badblockbits: [INTERN] number of bits to left-shift the bad block
|
* @badblockbits: [INTERN] minimum number of set bits in a good block's
|
||||||
* number
|
* bad block marker position; i.e., BBM == 11110111b is
|
||||||
|
* not bad when badblockbits == 7
|
||||||
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
||||||
* @numchips: [INTERN] number of physical chips
|
* @numchips: [INTERN] number of physical chips
|
||||||
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
||||||
|
@ -460,7 +469,9 @@ struct nand_buffers {
|
||||||
* non 0 if ONFI supported.
|
* non 0 if ONFI supported.
|
||||||
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
|
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
|
||||||
* supported, 0 otherwise.
|
* supported, 0 otherwise.
|
||||||
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
|
* @onfi_set_features [REPLACEABLE] set the features for ONFI nand
|
||||||
|
* @onfi_get_features [REPLACEABLE] get the features for ONFI nand
|
||||||
|
* @ecclayout: [REPLACEABLE] the default ECC placement scheme
|
||||||
* @bbt: [INTERN] bad block table pointer
|
* @bbt: [INTERN] bad block table pointer
|
||||||
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
|
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
|
||||||
* lookup.
|
* lookup.
|
||||||
|
@ -468,9 +479,9 @@ struct nand_buffers {
|
||||||
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
|
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
|
||||||
* bad block scan.
|
* bad block scan.
|
||||||
* @controller: [REPLACEABLE] a pointer to a hardware controller
|
* @controller: [REPLACEABLE] a pointer to a hardware controller
|
||||||
* structure which is shared among multiple independend
|
* structure which is shared among multiple independent
|
||||||
* devices.
|
* devices.
|
||||||
* @priv: [OPTIONAL] pointer to private chip date
|
* @priv: [OPTIONAL] pointer to private chip data
|
||||||
* @errstat: [OPTIONAL] hardware specific function to perform
|
* @errstat: [OPTIONAL] hardware specific function to perform
|
||||||
* additional error status checks (determine if errors are
|
* additional error status checks (determine if errors are
|
||||||
* correctable).
|
* correctable).
|
||||||
|
@ -501,10 +512,16 @@ struct nand_chip {
|
||||||
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
|
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
|
||||||
int status, int page);
|
int status, int page);
|
||||||
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf, int page, int cached, int raw);
|
const uint8_t *buf, int oob_required, int page,
|
||||||
|
int cached, int raw);
|
||||||
|
int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
int feature_addr, uint8_t *subfeature_para);
|
||||||
|
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
int feature_addr, uint8_t *subfeature_para);
|
||||||
|
|
||||||
int chip_delay;
|
int chip_delay;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
|
unsigned int bbt_options;
|
||||||
|
|
||||||
int page_shift;
|
int page_shift;
|
||||||
int phys_erase_shift;
|
int phys_erase_shift;
|
||||||
|
@ -534,8 +551,6 @@ struct nand_chip {
|
||||||
struct nand_buffers *buffers;
|
struct nand_buffers *buffers;
|
||||||
struct nand_hw_control hwcontrol;
|
struct nand_hw_control hwcontrol;
|
||||||
|
|
||||||
struct mtd_oob_ops ops;
|
|
||||||
|
|
||||||
uint8_t *bbt;
|
uint8_t *bbt;
|
||||||
struct nand_bbt_descr *bbt_td;
|
struct nand_bbt_descr *bbt_td;
|
||||||
struct nand_bbt_descr *bbt_md;
|
struct nand_bbt_descr *bbt_md;
|
||||||
|
@ -557,6 +572,8 @@ struct nand_chip {
|
||||||
#define NAND_MFR_HYNIX 0xad
|
#define NAND_MFR_HYNIX 0xad
|
||||||
#define NAND_MFR_MICRON 0x2c
|
#define NAND_MFR_MICRON 0x2c
|
||||||
#define NAND_MFR_AMD 0x01
|
#define NAND_MFR_AMD 0x01
|
||||||
|
#define NAND_MFR_MACRONIX 0xc2
|
||||||
|
#define NAND_MFR_EON 0x92
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_flash_dev - NAND Flash Device ID Structure
|
* struct nand_flash_dev - NAND Flash Device ID Structure
|
||||||
|
@ -615,9 +632,9 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
* @partitions: mtd partition list
|
* @partitions: mtd partition list
|
||||||
* @chip_delay: R/B delay value in us
|
* @chip_delay: R/B delay value in us
|
||||||
* @options: Option flags, e.g. 16bit buswidth
|
* @options: Option flags, e.g. 16bit buswidth
|
||||||
* @ecclayout: ecc layout info structure
|
* @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
|
||||||
|
* @ecclayout: ECC layout info structure
|
||||||
* @part_probe_types: NULL-terminated array of probe types
|
* @part_probe_types: NULL-terminated array of probe types
|
||||||
* @priv: hardware controller specific settings
|
|
||||||
*/
|
*/
|
||||||
struct platform_nand_chip {
|
struct platform_nand_chip {
|
||||||
int nr_chips;
|
int nr_chips;
|
||||||
|
@ -627,8 +644,8 @@ struct platform_nand_chip {
|
||||||
struct nand_ecclayout *ecclayout;
|
struct nand_ecclayout *ecclayout;
|
||||||
int chip_delay;
|
int chip_delay;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
|
unsigned int bbt_options;
|
||||||
const char **part_probe_types;
|
const char **part_probe_types;
|
||||||
void *priv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keep gcc happy */
|
/* Keep gcc happy */
|
||||||
|
@ -650,6 +667,7 @@ struct platform_nand_ctrl {
|
||||||
int (*dev_ready)(struct mtd_info *mtd);
|
int (*dev_ready)(struct mtd_info *mtd);
|
||||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||||
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
||||||
|
unsigned char (*read_byte)(struct mtd_info *mtd);
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -679,4 +697,23 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||||
void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len);
|
void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||||
uint8_t nand_read_byte(struct mtd_info *mtd);
|
uint8_t nand_read_byte(struct mtd_info *mtd);
|
||||||
|
|
||||||
|
/* return the supported asynchronous timing mode. */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
||||||
|
static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
|
||||||
|
{
|
||||||
|
if (!chip->onfi_version)
|
||||||
|
return ONFI_TIMING_MODE_UNKNOWN;
|
||||||
|
return le16_to_cpu(chip->onfi_params.async_timing_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the supported synchronous timing mode. */
|
||||||
|
static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
|
||||||
|
{
|
||||||
|
if (!chip->onfi_version)
|
||||||
|
return ONFI_TIMING_MODE_UNKNOWN;
|
||||||
|
return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __LINUX_MTD_NAND_H */
|
#endif /* __LINUX_MTD_NAND_H */
|
||||||
|
|
|
@ -85,6 +85,9 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
|
||||||
#ifndef __HAVE_ARCH_MEMCHR
|
#ifndef __HAVE_ARCH_MEMCHR
|
||||||
extern void * memchr(const void *,int,__kernel_size_t);
|
extern void * memchr(const void *,int,__kernel_size_t);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __HAVE_ARCH_MEMCHR_INV
|
||||||
|
void *memchr_inv(const void *, int, size_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,25 @@ struct mtd_oob_buf {
|
||||||
unsigned char __user *ptr;
|
unsigned char __user *ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MTD operation modes
|
||||||
|
*
|
||||||
|
* @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default)
|
||||||
|
* @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas
|
||||||
|
* which are defined by the internal ecclayout
|
||||||
|
* @MTD_OPS_RAW: data are transferred as-is, with no error correction;
|
||||||
|
* this mode implies %MTD_OPS_PLACE_OOB
|
||||||
|
*
|
||||||
|
* These modes can be passed to ioctl(MEMWRITE) and are also used internally.
|
||||||
|
* See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs.
|
||||||
|
* %MTD_FILE_MODE_RAW.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
MTD_OPS_PLACE_OOB = 0,
|
||||||
|
MTD_OPS_AUTO_OOB = 1,
|
||||||
|
MTD_OPS_RAW = 2,
|
||||||
|
};
|
||||||
|
|
||||||
#define MTD_ABSENT 0
|
#define MTD_ABSENT 0
|
||||||
#define MTD_RAM 1
|
#define MTD_RAM 1
|
||||||
#define MTD_ROM 2
|
#define MTD_ROM 2
|
||||||
|
@ -82,24 +101,42 @@ struct otp_info {
|
||||||
uint32_t locked;
|
uint32_t locked;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Get basic MTD characteristics info (better to use sysfs) */
|
||||||
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
|
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
|
||||||
|
/* Erase segment of MTD */
|
||||||
#define MEMERASE _IOW('M', 2, struct erase_info_user)
|
#define MEMERASE _IOW('M', 2, struct erase_info_user)
|
||||||
|
/* Write out-of-band data from MTD */
|
||||||
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
|
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
|
||||||
|
/* Read out-of-band data from MTD */
|
||||||
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
|
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
|
||||||
|
/* Lock a chip (for MTD that supports it) */
|
||||||
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
|
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
|
||||||
|
/* Unlock a chip (for MTD that supports it) */
|
||||||
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
|
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
|
||||||
|
/* Get the number of different erase regions */
|
||||||
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
|
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
|
||||||
|
/* Get information about the erase region for a specific index */
|
||||||
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
|
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
|
||||||
|
/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
|
||||||
#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
|
#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
|
||||||
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
|
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
|
||||||
|
/* Check if an eraseblock is bad */
|
||||||
#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
|
#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
|
||||||
|
/* Mark an eraseblock as bad */
|
||||||
#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
|
#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
|
||||||
|
/* Set OTP (One-Time Programmable) mode (factory vs. user) */
|
||||||
#define OTPSELECT _IOR('M', 13, int)
|
#define OTPSELECT _IOR('M', 13, int)
|
||||||
|
/* Get number of OTP (One-Time Programmable) regions */
|
||||||
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
|
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
|
||||||
|
/* Get all OTP (One-Time Programmable) info about MTD */
|
||||||
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
|
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
|
||||||
|
/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */
|
||||||
#define OTPLOCK _IOR('M', 16, struct otp_info)
|
#define OTPLOCK _IOR('M', 16, struct otp_info)
|
||||||
|
/* Get ECC layout (deprecated) */
|
||||||
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
|
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
|
||||||
|
/* Get statistics about corrected/uncorrected errors */
|
||||||
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
|
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
|
||||||
|
/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */
|
||||||
#define MTDFILEMODE _IO('M', 19)
|
#define MTDFILEMODE _IO('M', 19)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -146,7 +183,21 @@ struct mtd_ecc_stats {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read/write file modes for access to MTD
|
* MTD file modes - for read/write access to MTD
|
||||||
|
*
|
||||||
|
* @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled
|
||||||
|
* @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode
|
||||||
|
* @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode
|
||||||
|
* @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled
|
||||||
|
*
|
||||||
|
* These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained
|
||||||
|
* separately for each open file descriptor.
|
||||||
|
*
|
||||||
|
* Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW -
|
||||||
|
* raw access to the flash, without error correction or autoplacement schemes.
|
||||||
|
* Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode
|
||||||
|
* (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is
|
||||||
|
* used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)).
|
||||||
*/
|
*/
|
||||||
enum mtd_file_modes {
|
enum mtd_file_modes {
|
||||||
MTD_MODE_NORMAL = MTD_OTP_OFF,
|
MTD_MODE_NORMAL = MTD_OTP_OFF,
|
|
@ -56,17 +56,17 @@ extern nand_info_t nand_info[];
|
||||||
|
|
||||||
static inline int nand_read(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)
|
static inline int nand_read(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)
|
||||||
{
|
{
|
||||||
return info->read(info, ofs, *len, (size_t *)len, buf);
|
return mtd_read(info, ofs, *len, (size_t *)len, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int nand_write(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)
|
static inline int nand_write(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)
|
||||||
{
|
{
|
||||||
return info->write(info, ofs, *len, (size_t *)len, buf);
|
return mtd_write(info, ofs, *len, (size_t *)len, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int nand_block_isbad(nand_info_t *info, loff_t ofs)
|
static inline int nand_block_isbad(nand_info_t *info, loff_t ofs)
|
||||||
{
|
{
|
||||||
return info->block_isbad(info, ofs);
|
return mtd_block_isbad(info, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int nand_erase(nand_info_t *info, loff_t off, size_t size)
|
static inline int nand_erase(nand_info_t *info, loff_t off, size_t size)
|
||||||
|
@ -78,7 +78,7 @@ static inline int nand_erase(nand_info_t *info, loff_t off, size_t size)
|
||||||
instr.len = size;
|
instr.len = size;
|
||||||
instr.callback = 0;
|
instr.callback = 0;
|
||||||
|
|
||||||
return info->erase(info, &instr);
|
return mtd_erase(info, &instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
59
lib/string.c
59
lib/string.c
|
@ -617,3 +617,62 @@ void *memchr(const void *s, int c, size_t n)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __HAVE_ARCH_MEMCHR_INV
|
||||||
|
static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes)
|
||||||
|
{
|
||||||
|
while (bytes) {
|
||||||
|
if (*start != value)
|
||||||
|
return (void *)start;
|
||||||
|
start++;
|
||||||
|
bytes--;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* memchr_inv - Find an unmatching character in an area of memory.
|
||||||
|
* @start: The memory area
|
||||||
|
* @c: Find a character other than c
|
||||||
|
* @bytes: The size of the area.
|
||||||
|
*
|
||||||
|
* returns the address of the first character other than @c, or %NULL
|
||||||
|
* if the whole buffer contains just @c.
|
||||||
|
*/
|
||||||
|
void *memchr_inv(const void *start, int c, size_t bytes)
|
||||||
|
{
|
||||||
|
u8 value = c;
|
||||||
|
u64 value64;
|
||||||
|
unsigned int words, prefix;
|
||||||
|
|
||||||
|
if (bytes <= 16)
|
||||||
|
return check_bytes8(start, value, bytes);
|
||||||
|
|
||||||
|
value64 = value;
|
||||||
|
value64 |= value64 << 8;
|
||||||
|
value64 |= value64 << 16;
|
||||||
|
value64 |= value64 << 32;
|
||||||
|
|
||||||
|
prefix = (unsigned long)start % 8;
|
||||||
|
if (prefix) {
|
||||||
|
u8 *r;
|
||||||
|
|
||||||
|
prefix = 8 - prefix;
|
||||||
|
r = check_bytes8(start, value, prefix);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
start += prefix;
|
||||||
|
bytes -= prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
words = bytes / 8;
|
||||||
|
|
||||||
|
while (words) {
|
||||||
|
if (*(u64 *)start != value64)
|
||||||
|
return check_bytes8(start, value, 8);
|
||||||
|
start += 8;
|
||||||
|
words--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return check_bytes8(start, value, bytes % 8);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue