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:
Sergey Lapin 2013-01-14 03:46:50 +00:00 committed by Scott Wood
parent a1b81ab26f
commit dfe64e2c89
48 changed files with 2204 additions and 1702 deletions

View file

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

View file

@ -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);

View file

@ -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);

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}

View file

@ -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;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
} }

View file

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

View file

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

View file

@ -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 */

View file

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

View file

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

View file

@ -71,14 +71,15 @@ 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 */
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
{"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"}
}; };

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */

View file

@ -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;
} }

View file

@ -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);

View file

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

View file

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

View file

@ -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);

View file

@ -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;
} }

View file

@ -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;
} }

View file

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

View file

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

View file

@ -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);

View file

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

View file

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

View file

@ -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__ */

View file

@ -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 */

View file

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

View file

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

View file

@ -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);
} }

View file

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