]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
mtd: resync with Linux-3.7.1
authorSergey Lapin <slapin@ossfans.org>
Mon, 14 Jan 2013 03:46:50 +0000 (03:46 +0000)
committerScott Wood <scottwood@freescale.com>
Fri, 31 May 2013 22:12:03 +0000 (17:12 -0500)
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>
48 files changed:
board/ait/cam_enc_4xx/cam_enc_4xx.c
common/cmd_nand.c
common/cmd_onenand.c
common/env_onenand.c
drivers/mtd/Makefile
drivers/mtd/cfi_mtd.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/bfin_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/mxs_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nand_util.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/nomadik.c
drivers/mtd/nand/omap_gpmc.c
drivers/mtd/nand/s3c2410_nand.c
drivers/mtd/nand/tegra_nand.c
drivers/mtd/nand/tegra_nand.h
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_bbt.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/vtbl.c
fs/yaffs2/yaffs_mtdif.c
fs/yaffs2/yaffs_mtdif2.c
include/configs/P1022DS.h
include/linux/mtd/bbm.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/string.h
include/mtd/mtd-abi.h [moved from include/linux/mtd/mtd-abi.h with 65% similarity]
include/nand.h
lib/string.c

index 644c445693b740936d43e8d1c6e5cfec5451ab03..80a78221b1f8be7d72cabe4dc3ded88e8b492dac 100644 (file)
@@ -120,7 +120,7 @@ int board_eth_init(bd_t *bis)
 #ifdef CONFIG_NAND_DAVINCI
 static int
 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;
        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;
 }
 
-static void davinci_std_write_page_syndrome(struct mtd_info *mtd,
-                                   struct nand_chip *chip, const uint8_t *buf)
+static int davinci_std_write_page_syndrome(struct mtd_info *mtd,
+                                   struct nand_chip *chip, const uint8_t *buf,
+                                   int oob_required)
 {
        unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE];
        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);
        if (i)
                chip->write_buf(mtd, oob, i);
+       return 0;
 }
 
 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,
-       struct nand_chip *chip, int page, int sndcmd)
+       struct nand_chip *chip, int page)
 {
        struct nand_chip *this = mtd->priv;
        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);
 
-       return 1;
+       return 0;
 }
 
 static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip)
index f20223cffc4061add0426afa96102535300b7854..8b1e01ae8094f9a4236f6d9897a8e341121f987c 100644 (file)
@@ -62,8 +62,8 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
        ops.oobbuf = oobbuf;
        ops.len = nand->writesize;
        ops.ooblen = nand->oobsize;
-       ops.mode = MTD_OOB_RAW;
-       i = nand->read_oob(nand, addr, &ops);
+       ops.mode = MTD_OPS_RAW;
+       i = mtd_read_oob(nand, addr, &ops);
        if (i < 0) {
                printf("Error (%d) reading page %08lx\n", i, off);
                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,
                        .len = nand->writesize,
                        .ooblen = nand->oobsize,
-                       .mode = MTD_OOB_RAW
+                       .mode = MTD_OPS_RAW
                };
 
                if (read)
-                       ret = nand->read_oob(nand, off, &ops);
+                       ret = mtd_read_oob(nand, off, &ops);
                else
-                       ret = nand->write_oob(nand, off, &ops);
+                       ret = mtd_write_oob(nand, off, &ops);
 
                if (ret) {
                        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 = {
                                .oobbuf = (u8 *)addr,
                                .ooblen = rwsize,
-                               .mode = MTD_OOB_RAW
+                               .mode = MTD_OPS_RAW
                        };
 
                        if (read)
-                               ret = nand->read_oob(nand, off, &ops);
+                               ret = mtd_read_oob(nand, off, &ops);
                        else
-                               ret = nand->write_oob(nand, off, &ops);
+                               ret = mtd_write_oob(nand, off, &ops);
                } else if (raw) {
                        ret = raw_access(nand, addr, off, pagecount, read);
                } else {
@@ -764,7 +764,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                while (argc > 0) {
                        addr = simple_strtoul(*argv, NULL, 16);
 
-                       if (nand->block_markbad(nand, addr)) {
+                       if (mtd_block_markbad(nand, addr)) {
                                printf("block 0x%08lx NOT marked "
                                        "as bad! ERROR %d\n",
                                        addr, ret);
index a0d25e55212a0c9633e89d62331f3ed223c694df..06cc1405675a64f6d3c6dd637e9562817527e5ac 100644 (file)
@@ -83,7 +83,7 @@ static int onenand_block_read(loff_t from, size_t len,
                ops.len = blocksize;
 
        while (blocks) {
-               ret = mtd->block_isbad(mtd, ofs);
+               ret = mtd_block_isbad(mtd, ofs);
                if (ret) {
                        printk("Bad blocks %d at 0x%x\n",
                               (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.retlen = 0;
-               ret = mtd->read_oob(mtd, ofs, &ops);
+               ret = mtd_read_oob(mtd, ofs, &ops);
                if (ret) {
                        printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
                        ofs += blocksize;
@@ -118,7 +118,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
        struct mtd_oob_ops ops = {
                .len = mtd->writesize,
                .ooblen = mtd->oobsize,
-               .mode = MTD_OOB_AUTO,
+               .mode = MTD_OPS_AUTO_OOB,
        };
        int page, ret = 0;
        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;
                ops.oobbuf = (u_char *)buf;
                buf += mtd->oobsize;
-               ret = mtd->write_oob(mtd, to, &ops);
+               ret = mtd_write_oob(mtd, to, &ops);
                if (ret)
                        break;
                to += mtd->writesize;
@@ -156,7 +156,7 @@ static int onenand_block_write(loff_t to, size_t len,
        ofs = to;
 
        while (blocks) {
-               ret = mtd->block_isbad(mtd, ofs);
+               ret = mtd_block_isbad(mtd, ofs);
                if (ret) {
                        printk("Bad blocks %d at 0x%x\n",
                               (u32)(ofs >> this->erase_shift), (u32)ofs);
@@ -165,7 +165,7 @@ static int onenand_block_write(loff_t to, size_t len,
                }
 
                if (!withoob)
-                       ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
+                       ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf);
                else
                        ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
                if (ret) {
@@ -195,7 +195,7 @@ static int onenand_block_erase(u32 start, u32 size, int force)
        int blocksize = 1 << this->erase_shift;
 
        for (ofs = start; ofs < (start + size); ofs += blocksize) {
-               ret = mtd->block_isbad(mtd, ofs);
+               ret = mtd_block_isbad(mtd, ofs);
                if (ret && !force) {
                        printf("Skip erase bad block %d at 0x%x\n",
                               (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.priv = force;
                instr.mtd = mtd;
-               ret = mtd->erase(mtd, &instr);
+               ret = mtd_erase(mtd, &instr);
                if (ret) {
                        printf("erase failed block %d at 0x%x\n",
                               (u32)(ofs >> this->erase_shift), (u32)ofs);
@@ -261,7 +261,7 @@ static int onenand_block_test(u32 start, u32 size)
        while (blocks < end_block) {
                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) {
                        printf("Skip erase bad block %d at 0x%x\n",
                               (u32)(ofs >> this->erase_shift), (u32)ofs);
@@ -270,19 +270,19 @@ static int onenand_block_test(u32 start, u32 size)
 
                instr.addr = ofs;
                instr.len = blocksize;
-               ret = mtd->erase(mtd, &instr);
+               ret = mtd_erase(mtd, &instr);
                if (ret) {
                        printk("Erase failed 0x%x, %d\n", (u32)ofs, ret);
                        goto next;
                }
 
-               ret = mtd->write(mtd, ofs, blocksize, &retlen, buf);
+               ret = mtd_write(mtd, ofs, blocksize, &retlen, buf);
                if (ret) {
                        printk("Write failed 0x%x, %d\n", (u32)ofs, ret);
                        goto next;
                }
 
-               ret = mtd->read(mtd, ofs, blocksize, &retlen, verify_buf);
+               ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf);
                if (ret) {
                        printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
                        goto next;
@@ -324,7 +324,7 @@ static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob)
        ops.len = mtd->writesize;
        ops.ooblen = mtd->oobsize;
        ops.retlen = 0;
-       i = mtd->read_oob(mtd, addr, &ops);
+       i = mtd_read_oob(mtd, addr, &ops);
        if (i < 0) {
                printf("Error (%d) reading page %08lx\n", i, off);
                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 */
        printf("\nDevice %d bad blocks:\n", 0);
        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);
        }
 
@@ -530,7 +530,7 @@ static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * cons
        while (argc > 0) {
                addr = simple_strtoul(*argv, NULL, 16);
 
-               if (mtd->block_markbad(mtd, addr)) {
+               if (mtd_block_markbad(mtd, addr)) {
                        printf("block 0x%08lx NOT marked "
                                "as bad! ERROR %d\n",
                                addr, ret);
index faa903d2f0251cd2459daef22d6d6514124dc86c..e8bde37266adb9553e192cea11c2341b58bf2103 100644 (file)
@@ -68,7 +68,7 @@ void env_relocate_spec(void)
        /* Check OneNAND exist */
        if (mtd->writesize)
                /* 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);
        else
                mtd->writesize = MAX_ONENAND_PAGESIZE;
@@ -113,12 +113,12 @@ int saveenv(void)
 #endif
        instr.addr = env_addr;
        instr.mtd = mtd;
-       if (mtd->erase(mtd, &instr)) {
+       if (mtd_erase(mtd, &instr)) {
                printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
                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)) {
                printf("OneNAND: write failed at 0x%llx\n", instr.addr);
                return 2;
index 543c845ff0173c6c6540a5827e1e4305e09c84a6..99f39fc752b902352036c85c679baab6f25245bb 100644 (file)
@@ -25,7 +25,9 @@ include $(TOPDIR)/config.mk
 
 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_CONCAT) += mtdconcat.o
 COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o
index 8d74fa94128a7348de33a4051ba3ef3f13d805a6..bbb71a19e7d04c23bdd541b38c4a8fc8fd30bffc 100644 (file)
@@ -244,12 +244,12 @@ int cfi_mtd_init(void)
                mtd->size               = fi->size;
                mtd->writesize          = 1;
 
-               mtd->erase              = cfi_mtd_erase;
-               mtd->read               = cfi_mtd_read;
-               mtd->write              = cfi_mtd_write;
-               mtd->sync               = cfi_mtd_sync;
-               mtd->lock               = cfi_mtd_lock;
-               mtd->unlock             = cfi_mtd_unlock;
+               mtd->_erase             = cfi_mtd_erase;
+               mtd->_read              = cfi_mtd_read;
+               mtd->_write             = cfi_mtd_write;
+               mtd->_sync              = cfi_mtd_sync;
+               mtd->_lock              = cfi_mtd_lock;
+               mtd->_unlock            = cfi_mtd_unlock;
                mtd->priv               = fi;
 
                if (add_mtd_device(mtd))
index e6d938417ded948b498c41590fc85435db00dfec..31e4289b1601a4bb9de7cb2df4862258dc34bae8 100644 (file)
@@ -70,14 +70,14 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
                        /* Entire transaction goes into this subdev */
                        size = len;
 
-               err = subdev->read(subdev, from, size, &retsize, buf);
+               err = mtd_read(subdev, from, size, &retsize, buf);
 
                /* Save information about bitflips! */
                if (unlikely(err)) {
-                       if (err == -EBADMSG) {
+                       if (mtd_is_eccerr(err)) {
                                mtd->ecc_stats.failed++;
                                ret = err;
-                       } else if (err == -EUCLEAN) {
+                       } else if (mtd_is_bitflip(err)) {
                                mtd->ecc_stats.corrected++;
                                /* Do not overwrite -EBADMSG !! */
                                if (!ret)
@@ -105,9 +105,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
        int err = -EINVAL;
        int i;
 
-       if (!(mtd->flags & MTD_WRITEABLE))
-               return -EROFS;
-
        *retlen = 0;
 
        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
                        size = len;
 
-               if (!(subdev->flags & MTD_WRITEABLE))
-                       err = -EROFS;
-               else
-                       err = subdev->write(subdev, to, size, &retsize, buf);
-
+               err = mtd_write(subdev, to, size, &retsize, buf);
                if (err)
                        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)
                        devops.len = subdev->size - from;
 
-               err = subdev->read_oob(subdev, from, &devops);
+               err = mtd_read_oob(subdev, from, &devops);
                ops->retlen += devops.retlen;
                ops->oobretlen += devops.oobretlen;
 
                /* Save information about bitflips! */
                if (unlikely(err)) {
-                       if (err == -EBADMSG) {
+                       if (mtd_is_eccerr(err)) {
                                mtd->ecc_stats.failed++;
                                ret = err;
-                       } else if (err == -EUCLEAN) {
+                       } else if (mtd_is_bitflip(err)) {
                                mtd->ecc_stats.corrected++;
                                /* Do not overwrite -EBADMSG !! */
                                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)
                        devops.len = subdev->size - to;
 
-               err = subdev->write_oob(subdev, to, &devops);
+               err = mtd_write_oob(subdev, to, &devops);
                ops->retlen += devops.retlen;
                if (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
         * not having the wait_queue head on the stack.
         */
-       err = mtd->erase(mtd, erase);
+       err = mtd_erase(mtd, erase);
        if (!err) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                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;
        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.
         * 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;
        }
 
-       instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
-
        /* make a local copy of instr to avoid modifying the caller's struct */
        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
                        erase->len = length;
 
-               if (!(subdev->flags & MTD_WRITEABLE)) {
-                       err = -EROFS;
-                       break;
-               }
                length -= erase->len;
                if ((err = concat_dev_erase(subdev, erase))) {
                        /* 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);
        int i, err = -EINVAL;
 
-       if ((len + ofs) > mtd->size)
-               return -EINVAL;
-
        for (i = 0; i < concat->num_subdev; i++) {
                struct mtd_info *subdev = concat->subdev[i];
                uint64_t size;
@@ -446,7 +421,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
                else
                        size = len;
 
-               err = subdev->lock(subdev, ofs, size);
+               err = mtd_lock(subdev, ofs, size);
 
                if (err)
                        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);
        int i, err = 0;
 
-       if ((len + ofs) > mtd->size)
-               return -EINVAL;
-
        for (i = 0; i < concat->num_subdev; i++) {
                struct mtd_info *subdev = concat->subdev[i];
                uint64_t size;
@@ -484,7 +456,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
                else
                        size = len;
 
-               err = subdev->unlock(subdev, ofs, size);
+               err = mtd_unlock(subdev, ofs, size);
 
                if (err)
                        break;
@@ -507,7 +479,7 @@ static void concat_sync(struct mtd_info *mtd)
 
        for (i = 0; i < concat->num_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);
        int i, res = 0;
 
-       if (!concat->subdev[0]->block_isbad)
+       if (!mtd_can_have_bb(concat->subdev[0]))
                return res;
 
-       if (ofs > mtd->size)
-               return -EINVAL;
-
        for (i = 0; i < concat->num_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;
                }
 
-               res = subdev->block_isbad(subdev, ofs);
+               res = mtd_block_isbad(subdev, ofs);
                break;
        }
 
@@ -542,12 +511,9 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct mtd_concat *concat = CONCAT(mtd);
        int i, err = -EINVAL;
 
-       if (!concat->subdev[0]->block_markbad)
+       if (!mtd_can_have_bb(concat->subdev[0]))
                return 0;
 
-       if (ofs > mtd->size)
-               return -EINVAL;
-
        for (i = 0; i < concat->num_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;
                }
 
-               err = subdev->block_markbad(subdev, ofs);
+               err = mtd_block_markbad(subdev, ofs);
                if (!err)
                        mtd->ecc_stats.badblocks++;
                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.oobsize = subdev[0]->oobsize;
        concat->mtd.oobavail = subdev[0]->oobavail;
-       if (subdev[0]->read_oob)
-               concat->mtd.read_oob = concat_read_oob;
-       if (subdev[0]->write_oob)
-               concat->mtd.write_oob = concat_write_oob;
-       if (subdev[0]->block_isbad)
-               concat->mtd.block_isbad = concat_block_isbad;
-       if (subdev[0]->block_markbad)
-               concat->mtd.block_markbad = concat_block_markbad;
+       if (subdev[0]->_read_oob)
+               concat->mtd._read_oob = concat_read_oob;
+       if (subdev[0]->_write_oob)
+               concat->mtd._write_oob = concat_write_oob;
+       if (subdev[0]->_block_isbad)
+               concat->mtd._block_isbad = concat_block_isbad;
+       if (subdev[0]->_block_markbad)
+               concat->mtd._block_markbad = concat_block_markbad;
 
        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 ||
                    concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
                    concat->mtd.oobsize    !=  subdev[i]->oobsize ||
-                   !concat->mtd.read_oob  != !subdev[i]->read_oob ||
-                   !concat->mtd.write_oob != !subdev[i]->write_oob) {
+                   !concat->mtd._read_oob  != !subdev[i]->_read_oob ||
+                   !concat->mtd._write_oob != !subdev[i]->_write_oob) {
                        kfree(concat);
                        printk("Incompatible OOB or ECC data on \"%s\"\n",
                               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->mtd.name = name;
 
-       concat->mtd.erase = concat_erase;
-       concat->mtd.read = concat_read;
-       concat->mtd.write = concat_write;
-       concat->mtd.sync = concat_sync;
-       concat->mtd.lock = concat_lock;
-       concat->mtd.unlock = concat_unlock;
+       concat->mtd._erase = concat_erase;
+       concat->mtd._read = concat_read;
+       concat->mtd._write = concat_write;
+       concat->mtd._sync = concat_sync;
+       concat->mtd._lock = concat_lock;
+       concat->mtd._unlock = concat_unlock;
 
        /*
         * Combine the erase block size info of the subdevices:
index 3a81adaf60d5563d805e230515f12a3ca444439e..49c08145a7fa63296cdb79dc058af7108b64a72b 100644 (file)
@@ -25,6 +25,11 @@ int add_mtd_device(struct mtd_info *mtd)
                        mtd->index = i;
                        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
                           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) */
+
+ /*
+ * 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);
+}
+
index cbfc6796c7d6a96b3c81d353c0c2a141ac80b62c..9dfe7bbc9a9244dbb7e56f328b3046d2d2c3fbe0 100644 (file)
@@ -52,17 +52,11 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
        int res;
 
        stats = part->master->ecc_stats;
-
-       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);
+       res = mtd_read(part->master, from + part->offset, len, retlen, buf);
        if (unlikely(res)) {
-               if (res == -EUCLEAN)
+               if (mtd_is_bitflip(res))
                        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;
        }
        return res;
@@ -78,12 +72,12 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
                return -EINVAL;
        if (ops->datbuf && from + ops->len > mtd->size)
                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 (res == -EUCLEAN)
+               if (mtd_is_bitflip(res))
                        mtd->ecc_stats.corrected++;
-               if (res == -EBADMSG)
+               if (mtd_is_eccerr(res))
                        mtd->ecc_stats.failed++;
        }
        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)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->read_user_prot_reg(part->master, from,
-                                       len, retlen, buf);
+       return mtd_read_user_prot_reg(part->master, from, len, retlen, buf);
 }
 
 static int part_get_user_prot_info(struct mtd_info *mtd,
                struct otp_info *buf, size_t len)
 {
        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,
                size_t len, size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->read_fact_prot_reg(part->master, from,
-                                       len, retlen, buf);
+       return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf);
 }
 
 static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
                size_t len)
 {
        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,
                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->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);
+       return mtd_write(part->master, to + part->offset, len, retlen, buf);
 }
 
 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);
 
-       if (!(mtd->flags & MTD_WRITEABLE))
-               return -EROFS;
-
        if (to >= mtd->size)
                return -EINVAL;
        if (ops->datbuf && to + ops->len > mtd->size)
                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,
                size_t len, size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->write_user_prot_reg(part->master, from,
-                                       len, retlen, buf);
+       return mtd_write_user_prot_reg(part->master, from, len, retlen, buf);
 }
 
 static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
                size_t len)
 {
        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)
 {
        struct mtd_part *part = PART(mtd);
        int ret;
-       if (!(mtd->flags & MTD_WRITEABLE))
-               return -EROFS;
-       if (instr->addr >= mtd->size)
-               return -EINVAL;
+
        instr->addr += part->offset;
-       ret = part->master->erase(part->master, instr);
+       ret = mtd_erase(part->master, instr);
        if (ret) {
                if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
                        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)
 {
-       if (instr->mtd->erase == part_erase) {
+       if (instr->mtd->_erase == part_erase) {
                struct mtd_part *part = PART(instr->mtd);
 
                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)
 {
        struct mtd_part *part = PART(mtd);
-       if ((len + ofs) > mtd->size)
-               return -EINVAL;
-       return part->master->lock(part->master, ofs + part->offset, len);
+       return mtd_lock(part->master, ofs + part->offset, len);
 }
 
 static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct mtd_part *part = PART(mtd);
-       if ((len + ofs) > mtd->size)
-               return -EINVAL;
-       return part->master->unlock(part->master, ofs + part->offset, len);
+       return mtd_unlock(part->master, ofs + part->offset, len);
 }
 
 static void part_sync(struct mtd_info *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)
 {
        struct mtd_part *part = PART(mtd);
-       if (ofs >= mtd->size)
-               return -EINVAL;
        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)
@@ -244,12 +202,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct mtd_part *part = PART(mtd);
        int res;
 
-       if (!(mtd->flags & MTD_WRITEABLE))
-               return -EROFS;
-       if (ofs >= mtd->size)
-               return -EINVAL;
        ofs += part->offset;
-       res = part->master->block_markbad(part->master, ofs);
+       res = mtd_block_markbad(part->master, ofs);
        if (!res)
                mtd->ecc_stats.badblocks++;
        return res;
@@ -303,39 +257,36 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
        slave->mtd.name = part->name;
        slave->mtd.owner = master->owner;
 
-       slave->mtd.read = part_read;
-       slave->mtd.write = part_write;
-
-       if (master->panic_write)
-               slave->mtd.panic_write = part_panic_write;
-
-       if (master->read_oob)
-               slave->mtd.read_oob = part_read_oob;
-       if (master->write_oob)
-               slave->mtd.write_oob = part_write_oob;
-       if (master->read_user_prot_reg)
-               slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
-       if (master->read_fact_prot_reg)
-               slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
-       if (master->write_user_prot_reg)
-               slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
-       if (master->lock_user_prot_reg)
-               slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
-       if (master->get_user_prot_info)
-               slave->mtd.get_user_prot_info = part_get_user_prot_info;
-       if (master->get_fact_prot_info)
-               slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
-       if (master->sync)
-               slave->mtd.sync = part_sync;
-       if (master->lock)
-               slave->mtd.lock = part_lock;
-       if (master->unlock)
-               slave->mtd.unlock = part_unlock;
-       if (master->block_isbad)
-               slave->mtd.block_isbad = part_block_isbad;
-       if (master->block_markbad)
-               slave->mtd.block_markbad = part_block_markbad;
-       slave->mtd.erase = part_erase;
+       slave->mtd._read = part_read;
+       slave->mtd._write = part_write;
+
+       if (master->_read_oob)
+               slave->mtd._read_oob = part_read_oob;
+       if (master->_write_oob)
+               slave->mtd._write_oob = part_write_oob;
+       if (master->_read_user_prot_reg)
+               slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
+       if (master->_read_fact_prot_reg)
+               slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
+       if (master->_write_user_prot_reg)
+               slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
+       if (master->_lock_user_prot_reg)
+               slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
+       if (master->_get_user_prot_info)
+               slave->mtd._get_user_prot_info = part_get_user_prot_info;
+       if (master->_get_fact_prot_info)
+               slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
+       if (master->_sync)
+               slave->mtd._sync = part_sync;
+       if (master->_lock)
+               slave->mtd._lock = part_lock;
+       if (master->_unlock)
+               slave->mtd._unlock = part_unlock;
+       if (master->_block_isbad)
+               slave->mtd._block_isbad = part_block_isbad;
+       if (master->_block_markbad)
+               slave->mtd._block_markbad = part_block_markbad;
+       slave->mtd._erase = part_erase;
        slave->master = master;
        slave->offset = part->offset;
        slave->index = partno;
@@ -416,12 +367,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
        }
 
        slave->mtd.ecclayout = master->ecclayout;
-       if (master->block_isbad) {
+       if (master->_block_isbad) {
                uint64_t offs = 0;
 
                while (offs < slave->mtd.size) {
-                       if (master->block_isbad(master,
-                                               offs + slave->offset))
+                       if (mtd_block_isbad(master, offs + slave->offset))
                                slave->mtd.ecc_stats.badblocks++;
                        offs += slave->mtd.erasesize;
                }
index 994dd9f0952516cf760b192841b9c9f0c04ec1ea..3bfbaf8ac9fc192297b3653f6254ef74143023ee 100644 (file)
@@ -489,7 +489,7 @@ normal_check:
 }
 
 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;
        int eccsize = chip->ecc.size;
@@ -529,8 +529,9 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        return 0;
 }
 
-static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf)
+static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+               struct nand_chip *chip, const uint8_t *buf,
+               int oob_required)
 {
        struct atmel_nand_host *host = chip->priv;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -557,7 +558,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 
        if (!timeout) {
                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++) {
@@ -570,6 +571,8 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
                }
        }
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+out:
+       return 0;
 }
 
 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.write_page = atmel_nand_pmecc_write_page;
+       nand->ecc.strength = cap;
 
        atmel_pmecc_core_init(mtd);
 
@@ -775,9 +779,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
  * mtd:        mtd info structure
  * chip:       nand chip info structure
  * 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,
-               struct nand_chip *chip, uint8_t *buf, int page)
+static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               uint8_t *buf, int oob_required, int page)
 {
        int eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
index c7ddbb21d8ed95edd8463cbe69349df3e0d03b1a..7e755e8965aa54d6957576cbbaf224783ce949a0 100644 (file)
@@ -374,9 +374,11 @@ int board_nand_init(struct nand_chip *chip)
                if (!NAND_IS_512()) {
                        chip->ecc.bytes = 3;
                        chip->ecc.size = 256;
+                       chip->ecc.strength = 1;
                } else {
                        chip->ecc.bytes = 6;
                        chip->ecc.size = 512;
+                       chip->ecc.strength = 2;
                }
                chip->ecc.mode = NAND_ECC_HW;
                chip->ecc.calculate = bfin_nfc_calculate_ecc;
index e8506ddd9bdde79aac0acf6c9cddbda1858b2290..90f59857fd597f3021735030a06ff9c408c4a581 100644 (file)
@@ -607,12 +607,13 @@ void davinci_nand_init(struct nand_chip *nand)
 {
        nand->chip_delay  = 0;
 #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
-       nand->options     |= NAND_USE_FLASH_BBT;
+       nand->bbt_options         |= NAND_BBT_USE_FLASH;
 #endif
 #ifdef CONFIG_SYS_NAND_HW_ECC
        nand->ecc.mode = NAND_ECC_HW;
        nand->ecc.size = 512;
        nand->ecc.bytes = 3;
+       nand->ecc.strength = 1;
        nand->ecc.calculate = nand_davinci_calculate_ecc;
        nand->ecc.correct  = nand_davinci_correct_data;
        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.size = 512;
        nand->ecc.bytes = 10;
+       nand->ecc.strength = 4;
        nand->ecc.calculate = nand_davinci_4bit_calculate_ecc;
        nand->ecc.correct = nand_davinci_4bit_correct_data;
        nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc;
index edf3a099ba78d7148563e7328cf81e9251c1d0b0..4cd741ebbb48d2b03840b7d0e85f3db734da5fb9 100644 (file)
@@ -134,7 +134,7 @@ static struct rs_control *rs_decoder;
 
 /*
  * 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.
  *
  * 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);
        parity = ecc[1];
 
-       /* Initialize the syndrom buffer */
+       /* Initialize the syndrome buffer */
        for (i = 0; i < NROOTS; i++)
                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);
        else
                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");
                ret = 0;
        }
@@ -1073,7 +1073,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
        size_t retlen;
 
        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)
                        continue;
                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
           mediaheader on return, so we'll have to re-read the one we found. */
        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) {
                /* Insanity.  Give up. */
                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.size          = 512;
        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->virtadr            = virtadr;
index fb34d129b1559726536c445156b1dd1507e3b503..0fa776ae91947541cfde27385b5b852403512122 100644 (file)
@@ -640,9 +640,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return fsl_elbc_read_byte(mtd);
 }
 
-static int fsl_elbc_read_page(struct mtd_info *mtd,
-                             struct nand_chip *chip,
-                             uint8_t *buf, int page)
+static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                             uint8_t *buf, int oob_required, int page)
 {
        fsl_elbc_read_buf(mtd, buf, mtd->writesize);
        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
  * waitfunc.
  */
-static void fsl_elbc_write_page(struct mtd_info *mtd,
-                               struct nand_chip *chip,
-                               const uint8_t *buf)
+static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               const uint8_t *buf, int oob_required)
 {
        fsl_elbc_write_buf(mtd, buf, mtd->writesize);
        fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 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;
 
        /* set up nand options */
-       nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
-                       NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
+       nand->options = NAND_NO_SUBPAGE_WRITE;
+       nand->bbt_options = NAND_BBT_USE_FLASH;
 
        nand->controller = &elbc_ctrl->controller;
        nand->priv = priv;
@@ -769,6 +769,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
                nand->ecc.size = 512;
                nand->ecc.bytes = 3;
                nand->ecc.steps = 1;
+               nand->ecc.strength = 1;
        } else {
                /* otherwise fall back to default software ECC */
                nand->ecc.mode = NAND_ECC_SOFT;
index 49cfb335690f3f76fd0904e8879439eaaef0d891..439822c5a24563cce7fa9bc1fee54436f1a30d88 100644 (file)
@@ -686,9 +686,8 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return nand_fsr;
 }
 
-static int fsl_ifc_read_page(struct mtd_info *mtd,
-                             struct nand_chip *chip,
-                             uint8_t *buf, int page)
+static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                            uint8_t *buf, int oob_required, int page)
 {
        struct fsl_ifc_mtd *priv = chip->priv;
        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
  * waitfunc.
  */
-static void fsl_ifc_write_page(struct mtd_info *mtd,
-                               struct nand_chip *chip,
-                               const uint8_t *buf)
+static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                              const uint8_t *buf, int oob_required)
 {
        fsl_ifc_write_buf(mtd, buf, mtd->writesize);
        fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 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;
 
        /* set up nand options */
-       nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
-                       NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
+       nand->options = NAND_NO_SUBPAGE_WRITE;
+       nand->bbt_options = NAND_BBT_USE_FLASH;
 
        if (cspr & CSPR_PORT_SIZE_16) {
                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;
                }
 
+               nand->ecc.strength = 4;
                priv->bufnum_mask = 15;
                break;
 
        case CSOR_NAND_PGS_2K:
                layout = &oob_2048_ecc4;
+               nand->ecc.strength = 4;
                priv->bufnum_mask = 3;
                break;
 
@@ -902,8 +904,10 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
                if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
                    CSOR_NAND_ECC_MODE_4) {
                        layout = &oob_4096_ecc4;
+                       nand->ecc.strength = 4;
                } else {
                        layout = &oob_4096_ecc8;
+                       nand->ecc.strength = 8;
                        nand->ecc.bytes = 16;
                }
 
index 7a61d88cc573232b2530159d7725505c34fd8eb0..fab2aebc313f69e51ff20ab3f81b61cd49978c55 100644 (file)
@@ -341,6 +341,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
+ * @oob_required:      caller expects OOB data read to chip->oob_poi
  * @page:      page number to read
  *
  * 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)
  */
 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;
        int i, j, s, stat, eccsize = chip->ecc.size;
@@ -452,6 +453,7 @@ int fsmc_nand_init(struct nand_chip *nand)
        switch (fsmc_version) {
        case FSMC_VER8:
                nand->ecc.bytes = 13;
+               nand->ecc.strength = 8;
                nand->ecc.correct = fsmc_bch8_correct_data;
                nand->ecc.read_page = fsmc_read_page_hwecc;
                if (mtd->writesize == 512)
@@ -466,6 +468,7 @@ int fsmc_nand_init(struct nand_chip *nand)
                break;
        default:
                nand->ecc.bytes = 3;
+               nand->ecc.strength = 1;
                nand->ecc.layout = &fsmc_ecc1_layout;
                nand->ecc.correct = nand_correct_data;
                break;
index 3ec34f3c9b1d71fda10160f80c62472cf5f28263..a691fbc40397d747df6acf11f8872e2da89ddedd 100644 (file)
@@ -253,6 +253,7 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.mode          = NAND_ECC_HW_OOB_FIRST;
        nand->ecc.size          = CONFIG_SYS_NAND_ECCSIZE;
        nand->ecc.bytes         = CONFIG_SYS_NAND_ECCBYTES;
+       nand->ecc.strength      = 4;
        nand->ecc.layout        = &qi_lb60_ecclayout_2gb;
        nand->chip_delay        = 50;
        nand->options           = NAND_USE_FLASH_BBT;
index e6b7a706619ca1eb1c7c7eab2d0a910413cba86d..e53f341dcf81a2f809cc9532f8eb7b022f8474ea 100644 (file)
@@ -621,7 +621,7 @@ int board_nand_init(struct nand_chip *chip)
        chip->write_buf = mpc5121_nfc_write_buf;
        chip->verify_buf = mpc5121_nfc_verify_buf;
        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;
 
        /* Reset NAND Flash controller */
index eeba521942b78e76e0887e7648c8681b9019172b..ac435f205045e8a5f1d55643f7cdea20af98beac 100644 (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)
 static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
                                      struct nand_chip *chip,
-                                     int page, int sndcmd)
+                                     int page)
 {
        struct mxc_nand_host *host = chip->priv;
        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,
                                           struct nand_chip *chip,
                                           uint8_t *buf,
+                                          int oob_required,
                                           int page)
 {
        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,
                                       struct nand_chip *chip,
                                       uint8_t *buf,
+                                      int oob_required,
                                       int page)
 {
        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;
 }
 
-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,
-                                            const uint8_t *buf)
+                                            const uint8_t *buf,
+                                            int oob_required)
 {
        struct mxc_nand_host *host = chip->priv;
        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);
        if (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,
-                                        const uint8_t *buf)
+                                        const uint8_t *buf,
+                                        int oob_required)
 {
        struct mxc_nand_host *host = chip->priv;
        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);
        if (i)
                chip->write_buf(mtd, oob, i);
+       return 0;
 }
 
 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
 
 #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_md = &bbt_mirror_descr;
 #endif
@@ -1236,6 +1242,13 @@ int board_nand_init(struct nand_chip *this)
                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;
 
        this->ecc.size = 512;
index e38e15125407bb0f2361ac04e96edae893294c7d..7ba48c1201587a3e99e96274b4ee69f9c5107df8 100644 (file)
@@ -546,7 +546,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
  * Read a page from 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_dma_desc *d;
@@ -691,8 +692,9 @@ rtn:
 /*
  * Write a page to NAND.
  */
-static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
-                               struct nand_chip *nand, const uint8_t *buf)
+static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
+                               struct nand_chip *nand, const uint8_t *buf,
+                               int oob_required)
 {
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
@@ -748,6 +750,7 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
 
 rtn:
        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;
        int ret;
 
-       if (ops->mode == MTD_OOB_RAW)
+       if (ops->mode == MTD_OPS_RAW)
                nand_info->raw_oob_mode = 1;
        else
                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;
        int ret;
 
-       if (ops->mode == MTD_OOB_RAW)
+       if (ops->mode == MTD_OPS_RAW)
                nand_info->raw_oob_mode = 1;
        else
                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.
  */
 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;
 
@@ -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);
 
        /* Hook some operations at the MTD level. */
-       if (mtd->read_oob != mxs_nand_hook_read_oob) {
-               nand_info->hooked_read_oob = mtd->read_oob;
-               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;
+               mtd->_read_oob = mxs_nand_hook_read_oob;
        }
 
-       if (mtd->write_oob != mxs_nand_hook_write_oob) {
-               nand_info->hooked_write_oob = mtd->write_oob;
-               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;
+               mtd->_write_oob = mxs_nand_hook_write_oob;
        }
 
-       if (mtd->block_markbad != mxs_nand_hook_block_markbad) {
-               nand_info->hooked_block_markbad = mtd->block_markbad;
-               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;
+               mtd->_block_markbad = mxs_nand_hook_block_markbad;
        }
 
        /* 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.bytes         = 9;
        nand->ecc.size          = 512;
+       nand->ecc.strength      = 8;
 
        return 0;
 
index 3d846592ca5192364fa1a24688da3fa98576c293..9e05cef4179f3ddfc10e26f7e116f32c399364e2 100644 (file)
@@ -21,7 +21,7 @@
  *  TODO:
  *     Enable cached programming for 2k page size chips
  *     Check, if mtd->ecctype should be set to MTD_ECC_HW
- *     if we have HW ecc support.
+ *     if we have HW ECC support.
  *     The AG-AND chips have nice features for speed improvement,
  *     which are not supported yet. Read / program 4 pages in one go.
  *     BBT table is not serialized, has to be fixed
@@ -134,21 +134,14 @@ static int check_offs_len(struct mtd_info *mtd,
                ret = -EINVAL;
        }
 
-       /* Do not allow past end of device */
-       if (ofs + len > mtd->size) {
-               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n",
-                                       __func__);
-               ret = -EINVAL;
-       }
-
        return ret;
 }
 
 /**
  * nand_release_device - [GENERIC] release chip
- * @mtd:       MTD device structure
+ * @mtd: MTD device structure
  *
- * Deselect, release chip lock and wake up anyone waiting on the device
+ * Deselect, release chip lock and wake up anyone waiting on the device.
  */
 static void nand_release_device(struct mtd_info *mtd)
 {
@@ -160,9 +153,9 @@ static void nand_release_device(struct mtd_info *mtd)
 
 /**
  * nand_read_byte - [DEFAULT] read one byte from the chip
- * @mtd:       MTD device structure
+ * @mtd: MTD device structure
  *
- * Default read function for 8bit buswith
+ * Default read function for 8bit buswidth.
  */
 uint8_t nand_read_byte(struct mtd_info *mtd)
 {
@@ -172,10 +165,11 @@ uint8_t nand_read_byte(struct mtd_info *mtd)
 
 /**
  * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
- * @mtd:       MTD device structure
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
+ * @mtd: MTD device structure
+ *
+ * Default read function for 16bit buswidth with endianness conversion.
  *
- * Default read function for 16bit buswith with
- * endianess conversion
  */
 static uint8_t nand_read_byte16(struct mtd_info *mtd)
 {
@@ -185,10 +179,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)
 
 /**
  * nand_read_word - [DEFAULT] read one word from the chip
- * @mtd:       MTD device structure
+ * @mtd: MTD device structure
  *
- * Default read function for 16bit buswith without
- * endianess conversion
+ * Default read function for 16bit buswidth without endianness conversion.
  */
 static u16 nand_read_word(struct mtd_info *mtd)
 {
@@ -198,8 +191,8 @@ static u16 nand_read_word(struct mtd_info *mtd)
 
 /**
  * nand_select_chip - [DEFAULT] control CE line
- * @mtd:       MTD device structure
- * @chipnr:    chipnumber to select, -1 for deselect
+ * @mtd: MTD device structure
+ * @chipnr: chipnumber to select, -1 for deselect
  *
  * Default select function for 1 chip devices.
  */
@@ -221,11 +214,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
 
 /**
  * nand_write_buf - [DEFAULT] write buffer to chip
- * @mtd:       MTD device structure
- * @buf:       data buffer
- * @len:       number of bytes to write
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
  *
- * Default write function for 8bit buswith
+ * Default write function for 8bit buswidth.
  */
 void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
@@ -238,11 +231,11 @@ void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 /**
  * nand_read_buf - [DEFAULT] read chip data into buffer
- * @mtd:       MTD device structure
- * @buf:       buffer to store date
- * @len:       number of bytes to read
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
  *
- * Default read function for 8bit buswith
+ * Default read function for 8bit buswidth.
  */
 void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
@@ -255,11 +248,11 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 /**
  * nand_verify_buf - [DEFAULT] Verify chip data against buffer
- * @mtd:       MTD device structure
- * @buf:       buffer containing the data to compare
- * @len:       number of bytes to compare
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
  *
- * Default verify function for 8bit buswith
+ * Default verify function for 8bit buswidth.
  */
 static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
@@ -274,11 +267,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 /**
  * nand_write_buf16 - [DEFAULT] write buffer to chip
- * @mtd:       MTD device structure
- * @buf:       data buffer
- * @len:       number of bytes to write
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
  *
- * Default write function for 16bit buswith
+ * Default write function for 16bit buswidth.
  */
 void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
@@ -294,11 +287,11 @@ void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 /**
  * nand_read_buf16 - [DEFAULT] read chip data into buffer
- * @mtd:       MTD device structure
- * @buf:       buffer to store date
- * @len:       number of bytes to read
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
  *
- * Default read function for 16bit buswith
+ * Default read function for 16bit buswidth.
  */
 void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
@@ -313,11 +306,11 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 
 /**
  * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
- * @mtd:       MTD device structure
- * @buf:       buffer containing the data to compare
- * @len:       number of bytes to compare
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
  *
- * Default verify function for 16bit buswith
+ * Default verify function for 16bit buswidth.
  */
 static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
@@ -335,19 +328,19 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 /**
  * nand_block_bad - [DEFAULT] Read bad block marker from the chip
- * @mtd:       MTD device structure
- * @ofs:       offset from device start
- * @getchip:   0, if the chip is already selected
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ * @getchip: 0, if the chip is already selected
  *
  * Check, if the block is bad.
  */
 static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 {
-       int page, chipnr, res = 0;
+       int page, chipnr, res = 0, i = 0;
        struct nand_chip *chip = mtd->priv;
        u16 bad;
 
-       if (chip->options & NAND_BBT_SCANLASTPAGE)
+       if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
                ofs += mtd->erasesize - mtd->writesize;
 
        page = (int)(ofs >> chip->page_shift) & chip->pagemask;
@@ -361,23 +354,29 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                chip->select_chip(mtd, chipnr);
        }
 
-       if (chip->options & NAND_BUSWIDTH_16) {
-               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
-                             page);
-               bad = cpu_to_le16(chip->read_word(mtd));
-               if (chip->badblockpos & 0x1)
-                       bad >>= 8;
-               else
-                       bad &= 0xFF;
-       } else {
-               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
-               bad = chip->read_byte(mtd);
-       }
+       do {
+               if (chip->options & NAND_BUSWIDTH_16) {
+                       chip->cmdfunc(mtd, NAND_CMD_READOOB,
+                                       chip->badblockpos & 0xFE, page);
+                       bad = cpu_to_le16(chip->read_word(mtd));
+                       if (chip->badblockpos & 0x1)
+                               bad >>= 8;
+                       else
+                               bad &= 0xFF;
+               } else {
+                       chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
+                                       page);
+                       bad = chip->read_byte(mtd);
+               }
 
-       if (likely(chip->badblockbits == 8))
-               res = bad != 0xFF;
-       else
-               res = hweight8(bad) < chip->badblockbits;
+               if (likely(chip->badblockbits == 8))
+                       res = bad != 0xFF;
+               else
+                       res = hweight8(bad) < chip->badblockbits;
+               ofs += mtd->writesize;
+               page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+               i++;
+       } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
        if (getchip)
                nand_release_device(mtd);
@@ -387,57 +386,83 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
 /**
  * nand_default_block_markbad - [DEFAULT] mark a block bad
- * @mtd:       MTD device structure
- * @ofs:       offset from device start
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
  *
- * This is the default implementation, which can be overridden by
- * a hardware specific driver.
+ * This is the default implementation, which can be overridden by a hardware
+ * specific driver. We try operations in the following order, according to our
+ * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ *  (1) erase the affected block, to allow OOB marker to be written cleanly
+ *  (2) update in-memory BBT
+ *  (3) write bad block marker to OOB area of affected block
+ *  (4) update flash-based BBT
+ * Note that we retain the first error encountered in (3) or (4), finish the
+ * procedures, and dump the error in the end.
 */
 static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
        struct nand_chip *chip = mtd->priv;
        uint8_t buf[2] = { 0, 0 };
-       int block, ret, i = 0;
+       int block, res, ret = 0, i = 0;
+       int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
 
-       if (chip->options & NAND_BBT_SCANLASTPAGE)
-               ofs += mtd->erasesize - mtd->writesize;
+       if (write_oob) {
+               struct erase_info einfo;
+
+               /* Attempt erase before marking OOB */
+               memset(&einfo, 0, sizeof(einfo));
+               einfo.mtd = mtd;
+               einfo.addr = ofs;
+               einfo.len = 1 << chip->phys_erase_shift;
+               nand_erase_nand(mtd, &einfo, 0);
+       }
 
        /* Get block number */
        block = (int)(ofs >> chip->bbt_erase_shift);
+       /* Mark block bad in memory-based BBT */
        if (chip->bbt)
                chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
-       /* Do we have a flash based bad block table ? */
-       if (chip->options & NAND_USE_FLASH_BBT)
-               ret = nand_update_bbt(mtd, ofs);
-       else {
+       /* Write bad block marker to OOB */
+       if (write_oob) {
+               struct mtd_oob_ops ops;
+               loff_t wr_ofs = ofs;
+
                nand_get_device(chip, mtd, FL_WRITING);
 
-               /* Write to first two pages and to byte 1 and 6 if necessary.
-                * If we write to more than one location, the first error
-                * encountered quits the procedure. We write two bytes per
-                * location, so we dont have to mess with 16 bit access.
-                */
-               do {
-                       chip->ops.len = chip->ops.ooblen = 2;
-                       chip->ops.datbuf = NULL;
-                       chip->ops.oobbuf = buf;
-                       chip->ops.ooboffs = chip->badblockpos & ~0x01;
+               ops.datbuf = NULL;
+               ops.oobbuf = buf;
+               ops.ooboffs = chip->badblockpos;
+               if (chip->options & NAND_BUSWIDTH_16) {
+                       ops.ooboffs &= ~0x01;
+                       ops.len = ops.ooblen = 2;
+               } else {
+                       ops.len = ops.ooblen = 1;
+               }
+               ops.mode = MTD_OPS_PLACE_OOB;
 
-                       ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+               /* Write to first/last page(s) if necessary */
+               if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+                       wr_ofs += mtd->erasesize - mtd->writesize;
+               do {
+                       res = nand_do_write_oob(mtd, wr_ofs, &ops);
+                       if (!ret)
+                               ret = res;
 
-                       if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) {
-                               chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS
-                                       & ~0x01;
-                               ret = nand_do_write_oob(mtd, ofs, &chip->ops);
-                       }
                        i++;
-                       ofs += mtd->writesize;
-               } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) &&
-                               i < 2);
+                       wr_ofs += mtd->writesize;
+               } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
 
                nand_release_device(mtd);
        }
+
+       /* Update flash-based bad block table */
+       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+               res = nand_update_bbt(mtd, ofs);
+               if (!ret)
+                       ret = res;
+       }
+
        if (!ret)
                mtd->ecc_stats.badblocks++;
 
@@ -446,16 +471,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
 /**
  * nand_check_wp - [GENERIC] check if the chip is write protected
- * @mtd:       MTD device structure
- * Check, if the device is write protected
+ * @mtd: MTD device structure
  *
- * The function expects, that the device is already selected
+ * Check, if the device is write protected. The function expects, that the
+ * device is already selected.
  */
 static int nand_check_wp(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
 
-       /* broken xD cards report WP despite being writable */
+       /* Broken xD cards report WP despite being writable */
        if (chip->options & NAND_BROKEN_XD)
                return 0;
 
@@ -466,10 +491,10 @@ static int nand_check_wp(struct mtd_info *mtd)
 
 /**
  * nand_block_checkbad - [GENERIC] Check if a block is marked bad
- * @mtd:       MTD device structure
- * @ofs:       offset from device start
- * @getchip:   0, if the chip is already selected
- * @allowbbt:  1, if its allowed to access the bbt area
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ * @getchip: 0, if the chip is already selected
+ * @allowbbt: 1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
@@ -491,10 +516,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
        return nand_isbad_bbt(mtd, ofs, allowbbt);
 }
 
-/*
- * Wait for the ready pin, after a command
- * The timeout is catched later.
- */
+/* Wait for the ready pin, after a command. The timeout is caught later. */
 void nand_wait_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
@@ -503,7 +525,7 @@ void nand_wait_ready(struct mtd_info *mtd)
 
        time_start = get_timer(0);
 
-       /* wait until command is processed or timeout occures */
+       /* Wait until command is processed or timeout occurs */
        while (get_timer(time_start) < timeo) {
                if (chip->dev_ready)
                        if (chip->dev_ready(mtd))
@@ -513,13 +535,13 @@ void nand_wait_ready(struct mtd_info *mtd)
 
 /**
  * nand_command - [DEFAULT] Send command to NAND device
- * @mtd:       MTD device structure
- * @command:   the command to be sent
- * @column:    the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
  *
- * Send command to NAND device. This function is used for small page
- * devices (256/512 Bytes per page)
+ * Send command to NAND device. This function is used for small page devices
+ * (256/512 Bytes per page).
  */
 static void nand_command(struct mtd_info *mtd, unsigned int command,
                         int column, int page_addr)
@@ -528,9 +550,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
        uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;
 
-       /*
-        * Write out the command to the device.
-        */
+       /* Write out the command to the device */
        if (command == NAND_CMD_SEQIN) {
                int readcmd;
 
@@ -550,9 +570,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        }
        chip->cmd_ctrl(mtd, command, ctrl);
 
-       /*
-        * Address cycle, when necessary
-        */
+       /* Address cycle, when necessary */
        ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
        /* Serially input address */
        if (column != -1) {
@@ -573,8 +591,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
 
        /*
-        * program and erase have their own busy handlers
-        * status and sequential in needs no delay
+        * Program and erase have their own busy handlers status and sequential
+        * in needs no delay
         */
        switch (command) {
 
@@ -608,8 +626,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
                        return;
                }
        }
-       /* Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine. */
+       /*
+        * Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine.
+        */
        ndelay(100);
 
        nand_wait_ready(mtd);
@@ -617,14 +637,14 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
 
 /**
  * nand_command_lp - [DEFAULT] Send command to NAND large page device
- * @mtd:       MTD device structure
- * @command:   the command to be sent
- * @column:    the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
  *
  * Send command to NAND device. This is the version for the new large page
- * devices We dont have the separate regions as we have in the small page
- * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible.
+ * devices. We don't have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
  */
 static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                            int column, int page_addr)
@@ -667,8 +687,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
 
        /*
-        * program and erase have their own busy handlers
-        * status, sequential in, and deplete1 need no delay
+        * Program and erase have their own busy handlers status, sequential
+        * in, and deplete1 need no delay.
         */
        switch (command) {
 
@@ -682,14 +702,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        case NAND_CMD_DEPLETE1:
                return;
 
-               /*
-                * read error status commands require only a short delay
-                */
        case NAND_CMD_STATUS_ERROR:
        case NAND_CMD_STATUS_ERROR0:
        case NAND_CMD_STATUS_ERROR1:
        case NAND_CMD_STATUS_ERROR2:
        case NAND_CMD_STATUS_ERROR3:
+               /* Read error status commands require only a short delay */
                udelay(chip->chip_delay);
                return;
 
@@ -723,7 +741,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        default:
                /*
                 * If we don't have access to the busy pin, we apply the given
-                * command delay
+                * command delay.
                 */
                if (!chip->dev_ready) {
                        udelay(chip->chip_delay);
@@ -731,8 +749,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                }
        }
 
-       /* Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine. */
+       /*
+        * Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine.
+        */
        ndelay(100);
 
        nand_wait_ready(mtd);
@@ -740,9 +760,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 
 /**
  * nand_get_device - [GENERIC] Get chip for selected access
- * @chip:      the nand chip descriptor
- * @mtd:       MTD device structure
- * @new_state: the state which is requested
+ * @chip: the nand chip descriptor
+ * @mtd: MTD device structure
+ * @new_state: the state which is requested
  *
  * Get the device and lock it for exclusive access
  */
@@ -754,13 +774,13 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
 }
 
 /**
- * nand_wait - [DEFAULT]  wait until the command is done
- * @mtd:       MTD device structure
- * @chip:      NAND chip structure
+ * nand_wait - [DEFAULT] wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
  *
- * Wait for command done. This applies to erase and program only
- * Erase can take up to 400ms and program up to 20ms according to
- * general NAND and SmartMedia specs
+ * Wait for command done. This applies to erase and program only. Erase can
+ * take up to 400ms and program up to 20ms according to general NAND and
+ * SmartMedia specs.
  */
 static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
@@ -804,34 +824,37 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 }
 
 /**
- * nand_read_page_raw - [Intern] read raw page data without ecc
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- * @page:      page number to read
+ * nand_read_page_raw - [INTERN] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
  *
- * Not for syndrome calculating ecc controllers, which use a special oob layout
+ * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
 static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf, int page)
+                             uint8_t *buf, int oob_required, int page)
 {
        chip->read_buf(mtd, buf, mtd->writesize);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       if (oob_required)
+               chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
        return 0;
 }
 
 /**
- * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- * @page:      page number to read
+ * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
  *
  * We need a special oob layout and handling even when OOB isn't used.
  */
 static int nand_read_page_raw_syndrome(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)
 {
        int eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -864,14 +887,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
 }
 
 /**
- * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- * @page:      page number to read
+ * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
  */
 static int nand_read_page_swecc(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 eccbytes = chip->ecc.bytes;
@@ -881,7 +905,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        uint8_t *ecc_code = chip->buffers->ecccode;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
 
-       chip->ecc.read_page_raw(mtd, chip, buf, page);
+       chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
                chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -905,12 +929,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @data_offs: offset of requested data within the page
- * @readlen:   data length
- * @bufpoi:    buffer to store read data
+ * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
  */
 static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
                        uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
@@ -923,12 +947,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
        int index = 0;
 
-       /* Column address wihin the page aligned to ECC size (256bytes). */
+       /* Column address within the page aligned to ECC size (256bytes) */
        start_step = data_offs / chip->ecc.size;
        end_step = (data_offs + readlen - 1) / chip->ecc.size;
        num_steps = end_step - start_step + 1;
 
-       /* Data size aligned to ECC ecc.size*/
+       /* Data size aligned to ECC ecc.size */
        datafrag_len = num_steps * chip->ecc.size;
        eccfrag_len = num_steps * chip->ecc.bytes;
 
@@ -940,13 +964,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        p = bufpoi + data_col_addr;
        chip->read_buf(mtd, p, datafrag_len);
 
-       /* Calculate  ECC */
+       /* Calculate ECC */
        for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
                chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
 
-       /* The performance is faster if to position offsets
-          according to ecc.pos. Let make sure here that
-          there are no gaps in ecc positions */
+       /*
+        * The performance is faster if we position offsets according to
+        * ecc.pos. Let's make sure that there are no gaps in ECC positions.
+        */
        for (i = 0; i < eccfrag_len - 1; i++) {
                if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=
                        eccpos[i + start_step * chip->ecc.bytes + 1]) {
@@ -958,8 +983,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
                chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
                chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
        } else {
-               /* send the command to read the particular ecc bytes */
-               /* take care about buswidth alignment in read_buf */
+               /*
+                * Send the command to read the particular ECC bytes take care
+                * about buswidth alignment in read_buf.
+                */
                index = start_step * chip->ecc.bytes;
 
                aligned_pos = eccpos[index] & ~(busw - 1);
@@ -992,16 +1019,17 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- * @page:      page number to read
+ * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
  *
- * Not for syndrome calculating ecc controllers which need a special oob layout
+ * Not for syndrome calculating ECC controllers which need a special oob layout.
  */
 static int nand_read_page_hwecc(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 eccbytes = chip->ecc.bytes;
@@ -1037,21 +1065,21 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- * @page:      page number to read
+ * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
  *
- * Hardware ECC for large page chips, require OOB to be read first.
- * For this ECC mode, the write_page method is re-used from ECC_HW.
- * These methods read/write ECC from the OOB area, unlike the
- * ECC_HW_SYNDROME support with multiple ECC steps, follows the
- * "infix ECC" scheme and reads/writes ECC from the data area, by
- * overwriting the NAND manufacturer bad block markings.
+ * Hardware ECC for large page chips, require OOB to be read first. For this
+ * ECC mode, the write_page method is re-used from ECC_HW. These methods
+ * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
+ * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
+ * the data area, by overwriting the NAND manufacturer bad block markings.
  */
 static int nand_read_page_hwecc_oob_first(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)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1086,17 +1114,18 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 }
 
 /**
- * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- * @page:      page number to read
+ * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
  *
- * The hw generator calculates the error syndrome automatically. Therefor
- * we need a special oob layout and handling.
+ * The hw generator calculates the error syndrome automatically. Therefore we
+ * need a special oob layout and handling.
  */
 static int nand_read_page_syndrome(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 eccbytes = chip->ecc.bytes;
@@ -1141,29 +1170,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_transfer_oob - [Internal] Transfer oob to client buffer
- * @chip:      nand chip structure
- * @oob:       oob destination address
- * @ops:       oob ops structure
- * @len:       size of oob to transfer
+ * nand_transfer_oob - [INTERN] Transfer oob to client buffer
+ * @chip: nand chip structure
+ * @oob: oob destination address
+ * @ops: oob ops structure
+ * @len: size of oob to transfer
  */
 static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
                                  struct mtd_oob_ops *ops, size_t len)
 {
        switch (ops->mode) {
 
-       case MTD_OOB_PLACE:
-       case MTD_OOB_RAW:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_RAW:
                memcpy(oob, chip->oob_poi + ops->ooboffs, len);
                return oob + len;
 
-       case MTD_OOB_AUTO: {
+       case MTD_OPS_AUTO_OOB: {
                struct nand_oobfree *free = chip->ecc.layout->oobfree;
                uint32_t boffs = 0, roffs = ops->ooboffs;
                size_t bytes = 0;
 
                for (; free->length && len; free++, len -= bytes) {
-                       /* Read request not from offset 0 ? */
+                       /* Read request not from offset 0? */
                        if (unlikely(roffs)) {
                                if (roffs >= free->length) {
                                        roffs -= free->length;
@@ -1189,26 +1218,23 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
 }
 
 /**
- * nand_do_read_ops - [Internal] Read data with ECC
- *
- * @mtd:       MTD device structure
- * @from:      offset to read from
- * @ops:       oob ops structure
+ * nand_do_read_ops - [INTERN] Read data with ECC
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob ops structure
  *
  * Internal function. Called with chip held.
  */
 static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                            struct mtd_oob_ops *ops)
 {
-       int chipnr, page, realpage, col, bytes, aligned;
+       int chipnr, page, realpage, col, bytes, aligned, oob_required;
        struct nand_chip *chip = mtd->priv;
        struct mtd_ecc_stats stats;
-       int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
-       int sndcmd = 1;
        int ret = 0;
        uint32_t readlen = ops->len;
        uint32_t oobreadlen = ops->ooblen;
-       uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ?
+       uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
                mtd->oobavail : mtd->oobsize;
 
        uint8_t *bufpoi, *oob, *buf;
@@ -1225,6 +1251,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
        buf = ops->datbuf;
        oob = ops->oobbuf;
+       oob_required = oob ? 1 : 0;
 
        while (1) {
                WATCHDOG_RESET();
@@ -1232,41 +1259,46 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                bytes = min(mtd->writesize - col, readlen);
                aligned = (bytes == mtd->writesize);
 
-               /* Is the current page in the buffer ? */
+               /* Is the current page in the buffer? */
                if (realpage != chip->pagebuf || oob) {
                        bufpoi = aligned ? buf : chip->buffers->databuf;
 
-                       if (likely(sndcmd)) {
-                               chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
-                               sndcmd = 0;
-                       }
+                       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
                        /* Now read the page into the buffer */
-                       if (unlikely(ops->mode == MTD_OOB_RAW))
-                               ret = chip->ecc.read_page_raw(mtd, chip,
-                                                             bufpoi, page);
+                       if (unlikely(ops->mode == MTD_OPS_RAW))
+                               ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
+                                                             oob_required,
+                                                             page);
                        else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
                            !oob)
                                ret = chip->ecc.read_subpage(mtd, chip,
                                                        col, bytes, bufpoi);
                        else
                                ret = chip->ecc.read_page(mtd, chip, bufpoi,
-                                                         page);
-                       if (ret < 0)
+                                                         oob_required, page);
+                       if (ret < 0) {
+                               if (!aligned)
+                                       /* Invalidate page cache */
+                                       chip->pagebuf = -1;
                                break;
+                       }
 
                        /* Transfer not aligned data */
                        if (!aligned) {
                                if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
-                                   !(mtd->ecc_stats.failed - stats.failed))
+                                   !(mtd->ecc_stats.failed - stats.failed) &&
+                                   (ops->mode != MTD_OPS_RAW))
                                        chip->pagebuf = realpage;
+                               else
+                                       /* Invalidate page cache */
+                                       chip->pagebuf = -1;
                                memcpy(buf, chip->buffers->databuf + col, bytes);
                        }
 
                        buf += bytes;
 
                        if (unlikely(oob)) {
-
                                int toread = min(oobreadlen, max_oobsize);
 
                                if (toread) {
@@ -1275,20 +1307,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                        oobreadlen -= toread;
                                }
                        }
-
-                       if (!(chip->options & NAND_NO_READRDY)) {
-                               /*
-                                * Apply delay or wait for ready/busy pin. Do
-                                * this before the AUTOINCR check, so no
-                                * problems arise if a chip which does auto
-                                * increment is marked as NOAUTOINCR by the
-                                * board driver.
-                                */
-                               if (!chip->dev_ready)
-                                       udelay(chip->chip_delay);
-                               else
-                                       nand_wait_ready(mtd);
-                       }
                } else {
                        memcpy(buf, chip->buffers->databuf + col, bytes);
                        buf += bytes;
@@ -1299,7 +1317,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                if (!readlen)
                        break;
 
-               /* For subsequent reads align to page boundary. */
+               /* For subsequent reads align to page boundary */
                col = 0;
                /* Increment page address */
                realpage++;
@@ -1311,12 +1329,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        chip->select_chip(mtd, -1);
                        chip->select_chip(mtd, chipnr);
                }
-
-               /* Check, if the chip supports auto page increment
-                * or if we have hit a block boundary.
-                */
-               if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
-                       sndcmd = 1;
        }
 
        ops->retlen = ops->len - (size_t) readlen;
@@ -1334,69 +1346,55 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
 /**
  * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
- * @mtd:       MTD device structure
- * @from:      offset to read from
- * @len:       number of bytes to read
- * @retlen:    pointer to variable to store the number of read bytes
- * @buf:       the databuffer to put data
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put data
  *
- * Get hold of the chip and call nand_do_read
+ * Get hold of the chip and call nand_do_read.
  */
 static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, uint8_t *buf)
 {
        struct nand_chip *chip = mtd->priv;
+       struct mtd_oob_ops ops;
        int ret;
 
-       /* Do not allow reads past end of device */
-       if ((from + len) > mtd->size)
-               return -EINVAL;
-       if (!len)
-               return 0;
-
        nand_get_device(chip, mtd, FL_READING);
-
-       chip->ops.len = len;
-       chip->ops.datbuf = buf;
-       chip->ops.oobbuf = NULL;
-
-       ret = nand_do_read_ops(mtd, from, &chip->ops);
-
-       *retlen = chip->ops.retlen;
-
+       ops.len = len;
+       ops.datbuf = buf;
+       ops.oobbuf = NULL;
+       ops.mode = MTD_OPS_PLACE_OOB;
+       ret = nand_do_read_ops(mtd, from, &ops);
+       *retlen = ops.retlen;
        nand_release_device(mtd);
-
        return ret;
 }
 
 /**
- * nand_read_oob_std - [REPLACABLE] the most common OOB data read function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @page:      page number to read
- * @sndcmd:    flag whether to issue read command or not
+ * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
  */
 static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-                            int page, int sndcmd)
+                            int page)
 {
-       if (sndcmd) {
-               chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
-               sndcmd = 0;
-       }
+       chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-       return sndcmd;
+       return 0;
 }
 
 /**
- * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC
+ * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
  *                         with syndromes
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @page:      page number to read
- * @sndcmd:    flag whether to issue read command or not
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
  */
 static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                                 int page, int sndcmd)
+                                 int page)
 {
        uint8_t *buf = chip->oob_poi;
        int length = mtd->oobsize;
@@ -1423,14 +1421,14 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
        if (length > 0)
                chip->read_buf(mtd, bufpoi, length);
 
-       return 1;
+       return 0;
 }
 
 /**
- * nand_write_oob_std - [REPLACABLE] the most common OOB data write function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @page:      page number to write
+ * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
  */
 static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
                              int page)
@@ -1450,11 +1448,11 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC
- *                          with syndrome - only for large page flash !
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @page:      page number to write
+ * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
+ *                          with syndrome - only for large page flash
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
  */
 static int nand_write_oob_syndrome(struct mtd_info *mtd,
                                   struct nand_chip *chip, int page)
@@ -1509,27 +1507,30 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
 }
 
 /**
- * nand_do_read_oob - [Intern] NAND read out-of-band
- * @mtd:       MTD device structure
- * @from:      offset to read from
- * @ops:       oob operations description structure
+ * nand_do_read_oob - [INTERN] NAND read out-of-band
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operations description structure
  *
- * NAND read out-of-band data from the spare area
+ * NAND read out-of-band data from the spare area.
  */
 static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                            struct mtd_oob_ops *ops)
 {
-       int page, realpage, chipnr, sndcmd = 1;
+       int page, realpage, chipnr;
        struct nand_chip *chip = mtd->priv;
-       int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
+       struct mtd_ecc_stats stats;
        int readlen = ops->ooblen;
        int len;
        uint8_t *buf = ops->oobbuf;
+       int ret = 0;
 
        MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n",
                        __func__, (unsigned long long)from, readlen);
 
-       if (ops->mode == MTD_OOB_AUTO)
+       stats = mtd->ecc_stats;
+
+       if (ops->mode == MTD_OPS_AUTO_OOB)
                len = chip->ecc.layout->oobavail;
        else
                len = mtd->oobsize;
@@ -1558,24 +1559,17 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 
        while (1) {
                WATCHDOG_RESET();
-               sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
+               if (ops->mode == MTD_OPS_RAW)
+                       ret = chip->ecc.read_oob_raw(mtd, chip, page);
+               else
+                       ret = chip->ecc.read_oob(mtd, chip, page);
+
+               if (ret < 0)
+                       break;
 
                len = min(len, readlen);
                buf = nand_transfer_oob(chip, buf, ops, len);
 
-               if (!(chip->options & NAND_NO_READRDY)) {
-                       /*
-                        * Apply delay or wait for ready/busy pin. Do this
-                        * before the AUTOINCR check, so no problems arise if a
-                        * chip which does auto increment is marked as
-                        * NOAUTOINCR by the board driver.
-                        */
-                       if (!chip->dev_ready)
-                               udelay(chip->chip_delay);
-                       else
-                               nand_wait_ready(mtd);
-               }
-
                readlen -= len;
                if (!readlen)
                        break;
@@ -1590,25 +1584,26 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                        chip->select_chip(mtd, -1);
                        chip->select_chip(mtd, chipnr);
                }
-
-               /* Check, if the chip supports auto page increment
-                * or if we have hit a block boundary.
-                */
-               if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
-                       sndcmd = 1;
        }
 
-       ops->oobretlen = ops->ooblen;
-       return 0;
+       ops->oobretlen = ops->ooblen - readlen;
+
+       if (ret < 0)
+               return ret;
+
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
 /**
  * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
- * @mtd:       MTD device structure
- * @from:      offset to read from
- * @ops:       oob operation description structure
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
  *
- * NAND read data and/or out-of-band data
+ * NAND read data and/or out-of-band data.
  */
 static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops)
@@ -1628,9 +1623,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
        nand_get_device(chip, mtd, FL_READING);
 
        switch (ops->mode) {
-       case MTD_OOB_PLACE:
-       case MTD_OOB_AUTO:
-       case MTD_OOB_RAW:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_AUTO_OOB:
+       case MTD_OPS_RAW:
                break;
 
        default:
@@ -1649,31 +1644,36 @@ out:
 
 
 /**
- * nand_write_page_raw - [Intern] raw page write function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       data buffer
+ * nand_write_page_raw - [INTERN] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
  *
- * Not for syndrome calculating ecc controllers, which use a special oob layout
+ * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf)
+static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                               const uint8_t *buf, int oob_required)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       if (oob_required)
+               chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /**
- * nand_write_page_raw_syndrome - [Intern] raw page write function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       data buffer
+ * nand_write_page_raw_syndrome - [INTERN] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
  *
  * We need a special oob layout and handling even when ECC isn't checked.
  */
-static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
+static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
                                        struct nand_chip *chip,
-                                       const uint8_t *buf)
+                                       const uint8_t *buf, int oob_required)
 {
        int eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1701,15 +1701,18 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
        size = mtd->oobsize - (oob - chip->oob_poi);
        if (size)
                chip->write_buf(mtd, oob, size);
+
+       return 0;
 }
 /**
- * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       data buffer
+ * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
  */
-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf)
+static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+                                 const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1718,24 +1721,25 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        const uint8_t *p = buf;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
 
-       /* Software ecc calculation */
+       /* Software ECC calculation */
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
                chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
        for (i = 0; i < chip->ecc.total; i++)
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-       chip->ecc.write_page_raw(mtd, chip, buf);
+       return chip->ecc.write_page_raw(mtd, chip, buf, 1);
 }
 
 /**
- * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       data buffer
+ * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
  */
-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf)
+static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+                                 const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1754,19 +1758,23 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /**
- * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       data buffer
+ * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
  *
- * The hw generator calculates the error syndrome automatically. Therefor
- * we need a special oob layout and handling.
+ * The hw generator calculates the error syndrome automatically. Therefore we
+ * need a special oob layout and handling.
  */
-static void nand_write_page_syndrome(struct mtd_info *mtd,
-                                   struct nand_chip *chip, const uint8_t *buf)
+static int nand_write_page_syndrome(struct mtd_info *mtd,
+                                   struct nand_chip *chip,
+                                   const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1798,32 +1806,39 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
        i = mtd->oobsize - (oob - chip->oob_poi);
        if (i)
                chip->write_buf(mtd, oob, i);
+
+       return 0;
 }
 
 /**
  * nand_write_page - [REPLACEABLE] write one page
- * @mtd:       MTD device structure
- * @chip:      NAND chip descriptor
- * @buf:       the data to write
- * @page:      page number to write
- * @cached:    cached programming
- * @raw:       use _raw version of write_page
+ * @mtd: MTD device structure
+ * @chip: NAND chip descriptor
+ * @buf: the data to write
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ * @cached: cached programming
+ * @raw: use _raw version of write_page
  */
 static int nand_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 status;
 
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
-               chip->ecc.write_page_raw(mtd, chip, buf);
+               status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
        else
-               chip->ecc.write_page(mtd, chip, buf);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+       if (status < 0)
+               return status;
 
        /*
-        * Cached progamming disabled for now, Not sure if its worth the
-        * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
+        * Cached progamming disabled for now. Not sure if it's worth the
+        * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
         */
        cached = 0;
 
@@ -1833,7 +1848,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                status = chip->waitfunc(mtd, chip);
                /*
                 * See if operation failed and additional status checks are
-                * available
+                * available.
                 */
                if ((status & NAND_STATUS_FAIL) && (chip->errstat))
                        status = chip->errstat(mtd, chip, FL_WRITING, status,
@@ -1852,34 +1867,45 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (chip->verify_buf(mtd, buf, mtd->writesize))
                return -EIO;
+
+       /* Make sure the next page prog is preceded by a status read */
+       chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
 #endif
        return 0;
 }
 
 /**
- * nand_fill_oob - [Internal] Transfer client buffer to oob
- * @chip:      nand chip structure
- * @oob:       oob data buffer
- * @len:       oob data write length
- * @ops:       oob ops structure
+ * nand_fill_oob - [INTERN] Transfer client buffer to oob
+ * @mtd: MTD device structure
+ * @oob: oob data buffer
+ * @len: oob data write length
+ * @ops: oob ops structure
  */
-static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
-                                               struct mtd_oob_ops *ops)
+static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
+                             struct mtd_oob_ops *ops)
 {
+       struct nand_chip *chip = mtd->priv;
+
+       /*
+        * Initialise to all 0xFF, to avoid the possibility of left over OOB
+        * data from a previous OOB read.
+        */
+       memset(chip->oob_poi, 0xff, mtd->oobsize);
+
        switch (ops->mode) {
 
-       case MTD_OOB_PLACE:
-       case MTD_OOB_RAW:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_RAW:
                memcpy(chip->oob_poi + ops->ooboffs, oob, len);
                return oob + len;
 
-       case MTD_OOB_AUTO: {
+       case MTD_OPS_AUTO_OOB: {
                struct nand_oobfree *free = chip->ecc.layout->oobfree;
                uint32_t boffs = 0, woffs = ops->ooboffs;
                size_t bytes = 0;
 
                for (; free->length && len; free++, len -= bytes) {
-                       /* Write request not from offset 0 ? */
+                       /* Write request not from offset 0? */
                        if (unlikely(woffs)) {
                                if (woffs >= free->length) {
                                        woffs -= free->length;
@@ -1907,12 +1933,12 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
 #define NOTALIGNED(x)  ((x & (chip->subpagesize - 1)) != 0)
 
 /**
- * nand_do_write_ops - [Internal] NAND write with ECC
- * @mtd:       MTD device structure
- * @to:                offset to write to
- * @ops:       oob operations description structure
+ * nand_do_write_ops - [INTERN] NAND write with ECC
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operations description structure
  *
- * NAND write with ECC
+ * NAND write with ECC.
  */
 static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops)
@@ -1922,12 +1948,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        uint32_t writelen = ops->len;
 
        uint32_t oobwritelen = ops->ooblen;
-       uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ?
+       uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
                                mtd->oobavail : mtd->oobsize;
 
        uint8_t *oob = ops->oobbuf;
        uint8_t *buf = ops->datbuf;
        int ret, subpage;
+       int oob_required = oob ? 1 : 0;
 
        ops->retlen = 0;
        if (!writelen)
@@ -1957,10 +1984,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
            (chip->pagebuf << chip->page_shift) < (to + ops->len))
                chip->pagebuf = -1;
 
-       /* If we're not given explicit OOB data, let it be 0xFF */
-       if (likely(!oob))
-               memset(chip->oob_poi, 0xff, mtd->oobsize);
-
        /* Don't allow multipage oob writes with offset */
        if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
                return -EINVAL;
@@ -1972,7 +1995,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                int cached = writelen > bytes && page != blockmask;
                uint8_t *wbuf = buf;
 
-               /* Partial page write ? */
+               /* Partial page write? */
                if (unlikely(column || writelen < mtd->writesize)) {
                        cached = 0;
                        bytes = min_t(int, bytes - column, (int) writelen);
@@ -1984,12 +2007,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
                if (unlikely(oob)) {
                        size_t len = min(oobwritelen, oobmaxlen);
-                       oob = nand_fill_oob(chip, oob, len, ops);
+                       oob = nand_fill_oob(mtd, oob, len, ops);
                        oobwritelen -= len;
+               } else {
+                       /* We still need to erase leftover OOB data */
+                       memset(chip->oob_poi, 0xff, mtd->oobsize);
                }
 
-               ret = chip->write_page(mtd, chip, wbuf, page, cached,
-                                      (ops->mode == MTD_OOB_RAW));
+               ret = chip->write_page(mtd, chip, wbuf, oob_required, page,
+                                      cached, (ops->mode == MTD_OPS_RAW));
                if (ret)
                        break;
 
@@ -2018,48 +2044,39 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
 /**
  * nand_write - [MTD Interface] NAND write with ECC
- * @mtd:       MTD device structure
- * @to:                offset to write to
- * @len:       number of bytes to write
- * @retlen:    pointer to variable to store the number of written bytes
- * @buf:       the data to write
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @len: number of bytes to write
+ * @retlen: pointer to variable to store the number of written bytes
+ * @buf: the data to write
  *
- * NAND write with ECC
+ * NAND write with ECC.
  */
 static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
                          size_t *retlen, const uint8_t *buf)
 {
        struct nand_chip *chip = mtd->priv;
+       struct mtd_oob_ops ops;
        int ret;
 
-       /* Do not allow writes past end of device */
-       if ((to + len) > mtd->size)
-               return -EINVAL;
-       if (!len)
-               return 0;
-
        nand_get_device(chip, mtd, FL_WRITING);
-
-       chip->ops.len = len;
-       chip->ops.datbuf = (uint8_t *)buf;
-       chip->ops.oobbuf = NULL;
-
-       ret = nand_do_write_ops(mtd, to, &chip->ops);
-
-       *retlen = chip->ops.retlen;
-
+       ops.len = len;
+       ops.datbuf = (uint8_t *)buf;
+       ops.oobbuf = NULL;
+       ops.mode = MTD_OPS_PLACE_OOB;
+       ret = nand_do_write_ops(mtd, to, &ops);
+       *retlen = ops.retlen;
        nand_release_device(mtd);
-
        return ret;
 }
 
 /**
  * nand_do_write_oob - [MTD Interface] NAND write out-of-band
- * @mtd:       MTD device structure
- * @to:                offset to write to
- * @ops:       oob operation description structure
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
  *
- * NAND write out-of-band
+ * NAND write out-of-band.
  */
 static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops)
@@ -2070,7 +2087,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
                         __func__, (unsigned int)to, (int)ops->ooblen);
 
-       if (ops->mode == MTD_OOB_AUTO)
+       if (ops->mode == MTD_OPS_AUTO_OOB)
                len = chip->ecc.layout->oobavail;
        else
                len = mtd->oobsize;
@@ -2120,10 +2137,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        if (page == chip->pagebuf)
                chip->pagebuf = -1;
 
-       memset(chip->oob_poi, 0xff, mtd->oobsize);
-       nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
-       status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
-       memset(chip->oob_poi, 0xff, mtd->oobsize);
+       nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
+
+       if (ops->mode == MTD_OPS_RAW)
+               status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
+       else
+               status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
 
        if (status)
                return status;
@@ -2135,9 +2154,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 
 /**
  * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
- * @mtd:       MTD device structure
- * @to:                offset to write to
- * @ops:       oob operation description structure
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
  */
 static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                          struct mtd_oob_ops *ops)
@@ -2157,9 +2176,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
        nand_get_device(chip, mtd, FL_WRITING);
 
        switch (ops->mode) {
-       case MTD_OOB_PLACE:
-       case MTD_OOB_AUTO:
-       case MTD_OOB_RAW:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_AUTO_OOB:
+       case MTD_OPS_RAW:
                break;
 
        default:
@@ -2177,11 +2196,11 @@ out:
 }
 
 /**
- * single_erease_cmd - [GENERIC] NAND standard block erase command function
- * @mtd:       MTD device structure
- * @page:      the page address of the block which will be erased
+ * single_erase_cmd - [GENERIC] NAND standard block erase command function
+ * @mtd: MTD device structure
+ * @page: the page address of the block which will be erased
  *
- * Standard erase command for NAND chips
+ * Standard erase command for NAND chips.
  */
 static void single_erase_cmd(struct mtd_info *mtd, int page)
 {
@@ -2192,12 +2211,11 @@ static void single_erase_cmd(struct mtd_info *mtd, int page)
 }
 
 /**
- * multi_erease_cmd - [GENERIC] AND specific block erase command function
- * @mtd:       MTD device structure
- * @page:      the page address of the block which will be erased
+ * multi_erase_cmd - [GENERIC] AND specific block erase command function
+ * @mtd: MTD device structure
+ * @page: the page address of the block which will be erased
  *
- * AND multi block erase command function
- * Erase 4 consecutive blocks
+ * AND multi block erase command function. Erase 4 consecutive blocks.
  */
 static void multi_erase_cmd(struct mtd_info *mtd, int page)
 {
@@ -2212,10 +2230,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page)
 
 /**
  * nand_erase - [MTD Interface] erase block(s)
- * @mtd:       MTD device structure
- * @instr:     erase instruction
+ * @mtd: MTD device structure
+ * @instr: erase instruction
  *
- * Erase one ore more blocks
+ * Erase one ore more blocks.
  */
 static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
@@ -2224,12 +2242,12 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 
 #define BBT_PAGE_MASK  0xffffff3f
 /**
- * nand_erase_nand - [Internal] erase block(s)
- * @mtd:       MTD device structure
- * @instr:     erase instruction
- * @allowbbt:  allow erasing the bbt area
+ * nand_erase_nand - [INTERN] erase block(s)
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ * @allowbbt: allow erasing the bbt area
  *
- * Erase one ore more blocks
+ * Erase one ore more blocks.
  */
 int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                    int allowbbt)
@@ -2247,8 +2265,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
        if (check_offs_len(mtd, instr->addr, instr->len))
                return -EINVAL;
 
-       instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
-
        /* Grab the lock and see if the device is available */
        nand_get_device(chip, mtd, FL_ERASING);
 
@@ -2274,7 +2290,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
         * If BBT requires refresh, set the BBT page mask to see if the BBT
         * should be rewritten. Otherwise the mask is set to 0xffffffff which
         * can not be matched. This is also done when the bbt is actually
-        * erased to avoid recusrsive updates
+        * erased to avoid recursive updates.
         */
        if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
                bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
@@ -2286,20 +2302,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
        while (len) {
                WATCHDOG_RESET();
-               /*
-                * heck if we have a bad block, we do not erase bad blocks !
-                */
+               /* Check if we have a bad block, we do not erase bad blocks! */
                if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
                                        chip->page_shift, 0, allowbbt)) {
-                       printk(KERN_WARNING "%s: attempt to erase a bad block "
-                                       "at page 0x%08x\n", __func__, page);
+                       pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
+                                  __func__, page);
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
                }
 
                /*
                 * Invalidate the page cache, if we erase the block which
-                * contains the current cached page
+                * contains the current cached page.
                 */
                if (page <= chip->pagebuf && chip->pagebuf <
                    (page + pages_per_block))
@@ -2329,7 +2343,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
                /*
                 * If BBT requires refresh, set the BBT rewrite flag to the
-                * page being erased
+                * page being erased.
                 */
                if (bbt_masked_page != 0xffffffff &&
                    (page & BBT_PAGE_MASK) == bbt_masked_page)
@@ -2348,7 +2362,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
                        /*
                         * If BBT requires refresh and BBT-PERCHIP, set the BBT
-                        * page mask to see if this BBT should be rewritten
+                        * page mask to see if this BBT should be rewritten.
                         */
                        if (bbt_masked_page != 0xffffffff &&
                            (chip->bbt_td->options & NAND_BBT_PERCHIP))
@@ -2371,7 +2385,7 @@ erase_exit:
 
        /*
         * If BBT requires refresh and erase was successful, rewrite any
-        * selected bad block tables
+        * selected bad block tables.
         */
        if (bbt_masked_page == 0xffffffff || ret)
                return ret;
@@ -2379,7 +2393,7 @@ erase_exit:
        for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
                if (!rewrite_bbt[chipnr])
                        continue;
-               /* update the BBT for chip */
+               /* Update the BBT for chip */
                MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt "
                        "(%d:0x%0llx 0x%0x)\n", __func__, chipnr,
                        rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]);
@@ -2392,9 +2406,9 @@ erase_exit:
 
 /**
  * nand_sync - [MTD Interface] sync
- * @mtd:       MTD device structure
+ * @mtd: MTD device structure
  *
- * Sync is actually a wait for chip ready function
+ * Sync is actually a wait for chip ready function.
  */
 static void nand_sync(struct mtd_info *mtd)
 {
@@ -2410,22 +2424,18 @@ static void nand_sync(struct mtd_info *mtd)
 
 /**
  * nand_block_isbad - [MTD Interface] Check if block at offset is bad
- * @mtd:       MTD device structure
- * @offs:      offset relative to mtd start
+ * @mtd: MTD device structure
+ * @offs: offset relative to mtd start
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
-       /* Check for invalid offset */
-       if (offs > mtd->size)
-               return -EINVAL;
-
        return nand_block_checkbad(mtd, offs, 1, 0);
 }
 
 /**
  * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
- * @mtd:       MTD device structure
- * @ofs:       offset relative to mtd start
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
  */
 static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
@@ -2434,7 +2444,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
        ret = nand_block_isbad(mtd, ofs);
        if (ret) {
-               /* If it was bad already, return success and do nothing. */
+               /* If it was bad already, return success and do nothing */
                if (ret > 0)
                        return 0;
                return ret;
@@ -2443,9 +2453,51 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return chip->block_markbad(mtd, ofs);
 }
 
-/*
- * Set default functions
+ /**
+ * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
  */
+static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+                       int addr, uint8_t *subfeature_param)
+{
+       int status;
+
+       if (!chip->onfi_version)
+               return -EINVAL;
+
+       chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
+       chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
+       status = chip->waitfunc(mtd, chip);
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+       return 0;
+}
+
+/**
+ * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+                       int addr, uint8_t *subfeature_param)
+{
+       if (!chip->onfi_version)
+               return -EINVAL;
+
+       /* clear the sub feature parameters */
+       memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
+
+       chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
+       chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
+       return 0;
+}
+
+/* Set default functions */
 static void nand_set_defaults(struct nand_chip *chip, int busw)
 {
        /* check for proper chip_delay setup, set 20us if not */
@@ -2483,23 +2535,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 }
 
 #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
-/*
- * sanitize ONFI strings so we can safely print them
- */
+/* Sanitize ONFI strings so we can safely print them */
 static void sanitize_string(char *s, size_t len)
 {
        ssize_t i;
 
-       /* null terminate */
+       /* Null terminate */
        s[len - 1] = 0;
 
-       /* remove non printable chars */
+       /* Remove non printable chars */
        for (i = 0; i < len - 1; i++) {
                if (s[i] < ' ' || s[i] > 127)
                        s[i] = '?';
        }
 
-       /* remove trailing spaces */
+       /* Remove trailing spaces */
        strim(s);
 }
 
@@ -2516,7 +2566,7 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
 }
 
 /*
- * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
 static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                                        int *busw)
@@ -2525,20 +2575,18 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        int i;
        int val;
 
-       /* try ONFI for unknow chip or LP */
+       /* Try ONFI for unknown chip or LP */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
        if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
                chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
                return 0;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL0, "ONFI flash detected\n");
        chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
        for (i = 0; i < 3; i++) {
                chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
                if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
                                le16_to_cpu(p->crc)) {
-                       MTDDEBUG(MTD_DEBUG_LEVEL0,
-                                "ONFI param page %d valid\n", i);
+                       pr_info("ONFI param page %d valid\n", i);
                        break;
                }
        }
@@ -2546,7 +2594,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        if (i == 3)
                return 0;
 
-       /* check version */
+       /* Check version */
        val = le16_to_cpu(p->revision);
        if (val & (1 << 5))
                chip->onfi_version = 23;
@@ -2562,8 +2610,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                chip->onfi_version = 0;
 
        if (!chip->onfi_version) {
-               printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
-                                                               __func__, val);
+               pr_info("%s: unsupported ONFI version: %d\n", __func__, val);
                return 0;
        }
 
@@ -2580,8 +2627,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        if (le16_to_cpu(p->features) & 1)
                *busw = NAND_BUSWIDTH_16;
 
-       chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR;
-
+       pr_info("ONFI flash detected\n");
        return 1;
 }
 #else
@@ -2594,7 +2640,248 @@ static inline int nand_flash_detect_onfi(struct mtd_info *mtd,
 #endif
 
 /*
- * Get the flash and manufacturer id and lookup if the type is supported
+ * nand_id_has_period - Check if an ID string has a given wraparound period
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+ * @period: the period of repitition
+ *
+ * Check if an ID string is repeated within a given sequence of bytes at
+ * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
+ * period of 2). This is a helper function for nand_id_len(). Returns non-zero
+ * if the repetition has a period of @period; otherwise, returns zero.
+ */
+static int nand_id_has_period(u8 *id_data, int arrlen, int period)
+{
+       int i, j;
+       for (i = 0; i < period; i++)
+               for (j = i + period; j < arrlen; j += period)
+                       if (id_data[i] != id_data[j])
+                               return 0;
+       return 1;
+}
+
+/*
+ * nand_id_len - Get the length of an ID string returned by CMD_READID
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+
+ * Returns the length of the ID string, according to known wraparound/trailing
+ * zero patterns. If no pattern exists, returns the length of the array.
+ */
+static int nand_id_len(u8 *id_data, int arrlen)
+{
+       int last_nonzero, period;
+
+       /* Find last non-zero byte */
+       for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
+               if (id_data[last_nonzero])
+                       break;
+
+       /* All zeros */
+       if (last_nonzero < 0)
+               return 0;
+
+       /* Calculate wraparound period */
+       for (period = 1; period < arrlen; period++)
+               if (nand_id_has_period(id_data, arrlen, period))
+                       break;
+
+       /* There's a repeated pattern */
+       if (period < arrlen)
+               return period;
+
+       /* There are trailing zeros */
+       if (last_nonzero < arrlen - 1)
+               return last_nonzero + 1;
+
+       /* No pattern detected */
+       return arrlen;
+}
+
+/*
+ * Many new NAND share similar device ID codes, which represent the size of the
+ * chip. The rest of the parameters must be decoded according to generic or
+ * manufacturer-specific "extended ID" decoding patterns.
+ */
+static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
+                               u8 id_data[8], int *busw)
+{
+       int extid, id_len;
+       /* The 3rd id byte holds MLC / multichip data */
+       chip->cellinfo = id_data[2];
+       /* The 4th id byte is the important one */
+       extid = id_data[3];
+
+       id_len = nand_id_len(id_data, 8);
+
+       /*
+        * Field definitions are in the following datasheets:
+        * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
+        * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
+        * Hynix MLC   (6 byte ID): Hynix H27UBG8T2B (p.22)
+        *
+        * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
+        * ID to decide what to do.
+        */
+       if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
+                       (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                       id_data[5] != 0x00) {
+               /* Calc pagesize */
+               mtd->writesize = 2048 << (extid & 0x03);
+               extid >>= 2;
+               /* Calc oobsize */
+               switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
+               case 1:
+                       mtd->oobsize = 128;
+                       break;
+               case 2:
+                       mtd->oobsize = 218;
+                       break;
+               case 3:
+                       mtd->oobsize = 400;
+                       break;
+               case 4:
+                       mtd->oobsize = 436;
+                       break;
+               case 5:
+                       mtd->oobsize = 512;
+                       break;
+               case 6:
+               default: /* Other cases are "reserved" (unknown) */
+                       mtd->oobsize = 640;
+                       break;
+               }
+               extid >>= 2;
+               /* Calc blocksize */
+               mtd->erasesize = (128 * 1024) <<
+                       (((extid >> 1) & 0x04) | (extid & 0x03));
+               *busw = 0;
+       } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
+                       (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+               unsigned int tmp;
+
+               /* Calc pagesize */
+               mtd->writesize = 2048 << (extid & 0x03);
+               extid >>= 2;
+               /* Calc oobsize */
+               switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
+               case 0:
+                       mtd->oobsize = 128;
+                       break;
+               case 1:
+                       mtd->oobsize = 224;
+                       break;
+               case 2:
+                       mtd->oobsize = 448;
+                       break;
+               case 3:
+                       mtd->oobsize = 64;
+                       break;
+               case 4:
+                       mtd->oobsize = 32;
+                       break;
+               case 5:
+                       mtd->oobsize = 16;
+                       break;
+               default:
+                       mtd->oobsize = 640;
+                       break;
+               }
+               extid >>= 2;
+               /* Calc blocksize */
+               tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
+               if (tmp < 0x03)
+                       mtd->erasesize = (128 * 1024) << tmp;
+               else if (tmp == 0x03)
+                       mtd->erasesize = 768 * 1024;
+               else
+                       mtd->erasesize = (64 * 1024) << tmp;
+               *busw = 0;
+       } else {
+               /* Calc pagesize */
+               mtd->writesize = 1024 << (extid & 0x03);
+               extid >>= 2;
+               /* Calc oobsize */
+               mtd->oobsize = (8 << (extid & 0x01)) *
+                       (mtd->writesize >> 9);
+               extid >>= 2;
+               /* Calc blocksize. Blocksize is multiples of 64KiB */
+               mtd->erasesize = (64 * 1024) << (extid & 0x03);
+               extid >>= 2;
+               /* Get buswidth information */
+               *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+       }
+}
+
+ /*
+ * Old devices have chip data hardcoded in the device ID table. nand_decode_id
+ * decodes a matching ID table entry and assigns the MTD size parameters for
+ * the chip.
+ */
+static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
+                               const struct nand_flash_dev *type, u8 id_data[8],
+                               int *busw)
+{
+       int maf_id = id_data[0];
+
+       mtd->erasesize = type->erasesize;
+       mtd->writesize = type->pagesize;
+       mtd->oobsize = mtd->writesize / 32;
+       *busw = type->options & NAND_BUSWIDTH_16;
+
+       /*
+        * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+        * some Spansion chips have erasesize that conflicts with size
+        * listed in nand_ids table.
+        * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+        */
+       if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
+                       && id_data[6] == 0x00 && id_data[7] == 0x00
+                       && mtd->writesize == 512) {
+               mtd->erasesize = 128 * 1024;
+               mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+       }
+}
+
+ /*
+ * Set the bad block marker/indicator (BBM/BBI) patterns according to some
+ * heuristic patterns using various detected parameters (e.g., manufacturer,
+ * page size, cell-type information).
+ */
+static void nand_decode_bbm_options(struct mtd_info *mtd,
+                                   struct nand_chip *chip, u8 id_data[8])
+{
+       int maf_id = id_data[0];
+
+       /* Set the bad block position */
+       if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
+               chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+       else
+               chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+
+       /*
+        * Bad block marker is stored in the last page of each block on Samsung
+        * and Hynix MLC devices; stored in first two pages of each block on
+        * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
+        * AMD/Spansion, and Macronix.  All others scan only the first page.
+        */
+       if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                       (maf_id == NAND_MFR_SAMSUNG ||
+                        maf_id == NAND_MFR_HYNIX))
+               chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+       else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                               (maf_id == NAND_MFR_SAMSUNG ||
+                                maf_id == NAND_MFR_HYNIX ||
+                                maf_id == NAND_MFR_TOSHIBA ||
+                                maf_id == NAND_MFR_AMD ||
+                                maf_id == NAND_MFR_MACRONIX)) ||
+                       (mtd->writesize == 2048 &&
+                        maf_id == NAND_MFR_MICRON))
+               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+}
+
+/*
+ * Get the flash and manufacturer id and lookup if the type is supported.
  */
 static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                                                  struct nand_chip *chip,
@@ -2605,14 +2892,13 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        const char *name;
        int i, maf_idx;
        u8 id_data[8];
-       int ret;
 
        /* Select the device */
        chip->select_chip(mtd, 0);
 
        /*
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
-        * after power-up
+        * after power-up.
         */
        chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
 
@@ -2623,7 +2909,8 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        *maf_id = chip->read_byte(mtd);
        *dev_id = chip->read_byte(mtd);
 
-       /* Try again to make sure, as some systems the bus-hold or other
+       /*
+        * Try again to make sure, as some systems the bus-hold or other
         * interface concerns can cause random data which looks like a
         * possibly credible NAND flash to appear. If the two results do
         * not match, ignore the device completely.
@@ -2631,13 +2918,14 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 
-       for (i = 0; i < 2; i++)
+       /* Read entire ID string */
+       for (i = 0; i < 8; i++)
                id_data[i] = chip->read_byte(mtd);
 
        if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
-               printk(KERN_INFO "%s: second ID read did not match "
-                      "%02x,%02x against %02x,%02x\n", __func__,
-                      *maf_id, *dev_id, id_data[0], id_data[1]);
+               pr_info("%s: second ID read did not match "
+                       "%02x,%02x against %02x,%02x\n", __func__,
+                       *maf_id, *dev_id, id_data[0], id_data[1]);
                return ERR_PTR(-ENODEV);
        }
 
@@ -2651,18 +2939,10 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        chip->onfi_version = 0;
        if (!type->name || !type->pagesize) {
                /* Check is chip is ONFI compliant */
-               ret = nand_flash_detect_onfi(mtd, chip, &busw);
-               if (ret)
+               if (nand_flash_detect_onfi(mtd, chip, &busw))
                        goto ident_done;
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
-       /* Read entire ID string */
-
-       for (i = 0; i < 8; i++)
-               id_data[i] = chip->read_byte(mtd);
-
        if (!type->name)
                return ERR_PTR(-ENODEV);
 
@@ -2672,101 +2952,25 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        chip->chipsize = (uint64_t)type->chipsize << 20;
 
        if (!type->pagesize && chip->init_size) {
-               /* set the pagesize, oobsize, erasesize by the driver*/
+               /* Set the pagesize, oobsize, erasesize by the driver */
                busw = chip->init_size(mtd, chip, id_data);
        } else if (!type->pagesize) {
-               int extid;
-               /* The 3rd id byte holds MLC / multichip data */
-               chip->cellinfo = id_data[2];
-               /* The 4th id byte is the important one */
-               extid = id_data[3];
-
-               /*
-                * Field definitions are in the following datasheets:
-                * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
-                * New style   (6 byte ID): Samsung K9GBG08U0M (p.40)
-                *
-                * Check for wraparound + Samsung ID + nonzero 6th byte
-                * to decide what to do.
-                */
-               if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
-                               id_data[0] == NAND_MFR_SAMSUNG &&
-                               (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
-                               id_data[5] != 0x00) {
-                       /* Calc pagesize */
-                       mtd->writesize = 2048 << (extid & 0x03);
-                       extid >>= 2;
-                       /* Calc oobsize */
-                       switch (extid & 0x03) {
-                       case 1:
-                               mtd->oobsize = 128;
-                               break;
-                       case 2:
-                               mtd->oobsize = 218;
-                               break;
-                       case 3:
-                               mtd->oobsize = 400;
-                               break;
-                       default:
-                               mtd->oobsize = 436;
-                               break;
-                       }
-                       extid >>= 2;
-                       /* Calc blocksize */
-                       mtd->erasesize = (128 * 1024) <<
-                               (((extid >> 1) & 0x04) | (extid & 0x03));
-                       busw = 0;
-               } else {
-                       /* Calc pagesize */
-                       mtd->writesize = 1024 << (extid & 0x03);
-                       extid >>= 2;
-                       /* Calc oobsize */
-                       mtd->oobsize = (8 << (extid & 0x01)) *
-                               (mtd->writesize >> 9);
-                       extid >>= 2;
-                       /* Calc blocksize. Blocksize is multiples of 64KiB */
-                       mtd->erasesize = (64 * 1024) << (extid & 0x03);
-                       extid >>= 2;
-                       /* Get buswidth information */
-                       busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-               }
+               /* Decode parameters from extended ID */
+               nand_decode_ext_id(mtd, chip, id_data, &busw);
        } else {
-               /*
-                * Old devices have chip data hardcoded in the device id table
-                */
-               mtd->erasesize = type->erasesize;
-               mtd->writesize = type->pagesize;
-               mtd->oobsize = mtd->writesize / 32;
-               busw = type->options & NAND_BUSWIDTH_16;
-
-               /*
-                * Check for Spansion/AMD ID + repeating 5th, 6th byte since
-                * some Spansion chips have erasesize that conflicts with size
-                * listed in nand_ids table
-                * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
-                */
-               if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
-                               id_data[5] == 0x00 && id_data[6] == 0x00 &&
-                               id_data[7] == 0x00 && mtd->writesize == 512) {
-                       mtd->erasesize = 128 * 1024;
-                       mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
-               }
+               nand_decode_id(mtd, chip, type, id_data, &busw);
        }
        /* Get chip options, preserve non chip based options */
        chip->options |= type->options;
 
-       /* Check if chip is a not a samsung device. Do not clear the
-        * options for chips which are not having an extended id.
+       /*
+        * Check if chip is not a Samsung device. Do not clear the
+        * options for chips which do not have an extended id.
         */
        if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
                chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
 ident_done:
 
-       /*
-        * Set chip as a default. Board drivers can override it, if necessary
-        */
-       chip->options |= NAND_NO_AUTOINCR;
-
        /* Try to identify manufacturer */
        for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
                if (nand_manuf_ids[maf_idx].id == *maf_id)
@@ -2775,21 +2979,23 @@ ident_done:
 
        /*
         * Check, if buswidth is correct. Hardware drivers should set
-        * chip correct !
+        * chip correct!
         */
        if (busw != (chip->options & NAND_BUSWIDTH_16)) {
-               printk(KERN_INFO "NAND device: Manufacturer ID:"
-                      " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
-                      *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
-               printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
-                      (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
-                      busw ? 16 : 8);
+               pr_info("NAND device: Manufacturer ID:"
+                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
+                       *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
+               pr_warn("NAND bus width %d instead %d bit\n",
+                          (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
+                          busw ? 16 : 8);
                return ERR_PTR(-EINVAL);
        }
 
+       nand_decode_bbm_options(mtd, chip, id_data);
+
        /* Calculate the address shift from the page size */
        chip->page_shift = ffs(mtd->writesize) - 1;
-       /* Convert chipsize to number of pages per chip -1. */
+       /* Convert chipsize to number of pages per chip -1 */
        chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
 
        chip->bbt_erase_shift = chip->phys_erase_shift =
@@ -2803,73 +3009,38 @@ ident_done:
 
        chip->badblockbits = 8;
 
-       /* Set the bad block position */
-       if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16))
-               chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
-       else
-               chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
-
-       /*
-        * Bad block marker is stored in the last page of each block
-        * on Samsung and Hynix MLC devices; stored in first two pages
-        * of each block on Micron devices with 2KiB pages and on
-        * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan
-        * only the first page.
-        */
-       if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
-                       (*maf_id == NAND_MFR_SAMSUNG ||
-                        *maf_id == NAND_MFR_HYNIX))
-               chip->options |= NAND_BBT_SCANLASTPAGE;
-       else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
-                               (*maf_id == NAND_MFR_SAMSUNG ||
-                                *maf_id == NAND_MFR_HYNIX ||
-                                *maf_id == NAND_MFR_TOSHIBA ||
-                                *maf_id == NAND_MFR_AMD)) ||
-                       (mtd->writesize == 2048 &&
-                        *maf_id == NAND_MFR_MICRON))
-               chip->options |= NAND_BBT_SCAN2NDPAGE;
-
-       /*
-        * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6
-        */
-       if (!(busw & NAND_BUSWIDTH_16) &&
-                       *maf_id == NAND_MFR_STMICRO &&
-                       mtd->writesize == 2048) {
-               chip->options |= NAND_BBT_SCANBYTE1AND6;
-               chip->badblockpos = 0;
-       }
-
        /* Check for AND chips with 4 page planes */
        if (chip->options & NAND_4PAGE_ARRAY)
                chip->erase_cmd = multi_erase_cmd;
        else
                chip->erase_cmd = single_erase_cmd;
 
-       /* Do not replace user supplied command function ! */
+       /* Do not replace user supplied command function! */
        if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
                chip->cmdfunc = nand_command_lp;
 
-       /* TODO onfi flash name */
        name = type->name;
 #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
        if (chip->onfi_version)
                name = chip->onfi_params.model;
 #endif
-       MTDDEBUG(MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
-                " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
-                nand_manuf_ids[maf_idx].name, name);
+       pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
+               " page size: %d, OOB size: %d\n",
+               *maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
+               name,
+               mtd->writesize, mtd->oobsize);
 
        return type;
 }
 
 /**
  * nand_scan_ident - [NAND Interface] Scan for the NAND device
- * @mtd:            MTD device structure
- * @maxchips:       Number of chips to scan for
- * @table:          Alternative NAND ID table
+ * @mtd: MTD device structure
+ * @maxchips: number of chips to scan for
+ * @table: alternative NAND ID table
  *
- * This is the first phase of the normal nand_scan() function. It
- * reads the flash ID and sets up MTD fields accordingly.
+ * This is the first phase of the normal nand_scan() function. It reads the
+ * flash ID and sets up MTD fields accordingly.
  *
  * The mtd->owner field must be set to the module of the caller.
  */
@@ -2891,7 +3062,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 
        if (IS_ERR(type)) {
 #ifndef CONFIG_SYS_NAND_QUIET_TEST
-               printk(KERN_WARNING "No NAND device found!!!\n");
+               pr_warn("No NAND device found\n");
 #endif
                chip->select_chip(mtd, -1);
                return PTR_ERR(type);
@@ -2911,7 +3082,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        }
 #ifdef DEBUG
        if (i > 1)
-               printk(KERN_INFO "%d NAND chips detected\n", i);
+               pr_info("%d NAND chips detected\n", i);
 #endif
 
        /* Store the number of chips and calc total size for mtd */
@@ -2924,17 +3095,21 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
- * @mtd:           MTD device structure
+ * @mtd: MTD device structure
  *
- * This is the second phase of the normal nand_scan() function. It
- * fills out all the uninitialized function pointers with the defaults
- * and scans for a bad block table if appropriate.
+ * This is the second phase of the normal nand_scan() function. It fills out
+ * all the uninitialized function pointers with the defaults and scans for a
+ * bad block table if appropriate.
  */
 int nand_scan_tail(struct mtd_info *mtd)
 {
        int i;
        struct nand_chip *chip = mtd->priv;
 
+       /* New bad blocks should be marked in OOB, flash-based BBT, or both */
+       BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+                       !(chip->bbt_options & NAND_BBT_USE_FLASH));
+
        if (!(chip->options & NAND_OWN_BUFFERS))
                chip->buffers = memalign(ARCH_DMA_MINALIGN,
                                         sizeof(*chip->buffers));
@@ -2945,7 +3120,7 @@ int nand_scan_tail(struct mtd_info *mtd)
        chip->oob_poi = chip->buffers->databuf + mtd->writesize;
 
        /*
-        * If no default placement scheme is given, select an appropriate one
+        * If no default placement scheme is given, select an appropriate one.
         */
        if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
                switch (mtd->oobsize) {
@@ -2962,16 +3137,22 @@ int nand_scan_tail(struct mtd_info *mtd)
                        chip->ecc.layout = &nand_oob_128;
                        break;
                default:
-                       printk(KERN_WARNING "No oob scheme defined for "
-                              "oobsize %d\n", mtd->oobsize);
+                       pr_warn("No oob scheme defined for oobsize %d\n",
+                                  mtd->oobsize);
                }
        }
 
        if (!chip->write_page)
                chip->write_page = nand_write_page;
 
+       /* set for ONFI nand */
+       if (!chip->onfi_set_features)
+               chip->onfi_set_features = nand_onfi_set_features;
+       if (!chip->onfi_get_features)
+               chip->onfi_get_features = nand_onfi_get_features;
+
        /*
-        * check ECC mode, default to software if 3byte/512byte hardware ECC is
+        * Check ECC mode, default to software if 3byte/512byte hardware ECC is
         * selected and we have 256 byte pagesize fallback to software ECC
         */
 
@@ -2980,15 +3161,15 @@ int nand_scan_tail(struct mtd_info *mtd)
                /* Similar to NAND_ECC_HW, but a separate read_page handle */
                if (!chip->ecc.calculate || !chip->ecc.correct ||
                     !chip->ecc.hwctl) {
-                       printk(KERN_WARNING "No ECC functions supplied; "
-                              "Hardware ECC not possible\n");
+                       pr_warn("No ECC functions supplied; "
+                                  "hardware ECC not possible\n");
                        BUG();
                }
                if (!chip->ecc.read_page)
                        chip->ecc.read_page = nand_read_page_hwecc_oob_first;
 
        case NAND_ECC_HW:
-               /* Use standard hwecc read page function ? */
+               /* Use standard hwecc read page function? */
                if (!chip->ecc.read_page)
                        chip->ecc.read_page = nand_read_page_hwecc;
                if (!chip->ecc.write_page)
@@ -3009,11 +3190,11 @@ int nand_scan_tail(struct mtd_info *mtd)
                     chip->ecc.read_page == nand_read_page_hwecc ||
                     !chip->ecc.write_page ||
                     chip->ecc.write_page == nand_write_page_hwecc)) {
-                       printk(KERN_WARNING "No ECC functions supplied; "
-                              "Hardware ECC not possible\n");
+                       pr_warn("No ECC functions supplied; "
+                                  "hardware ECC not possible\n");
                        BUG();
                }
-               /* Use standard syndrome read/write page function ? */
+               /* Use standard syndrome read/write page function? */
                if (!chip->ecc.read_page)
                        chip->ecc.read_page = nand_read_page_syndrome;
                if (!chip->ecc.write_page)
@@ -3027,11 +3208,16 @@ int nand_scan_tail(struct mtd_info *mtd)
                if (!chip->ecc.write_oob)
                        chip->ecc.write_oob = nand_write_oob_syndrome;
 
-               if (mtd->writesize >= chip->ecc.size)
+               if (mtd->writesize >= chip->ecc.size) {
+                       if (!chip->ecc.strength) {
+                               pr_warn("Driver must set ecc.strength when using hardware ECC\n");
+                               BUG();
+                       }
                        break;
-               printk(KERN_WARNING "%d byte HW ECC not possible on "
-                      "%d byte page size, fallback to SW ECC\n",
-                      chip->ecc.size, mtd->writesize);
+               }
+               pr_warn("%d byte HW ECC not possible on "
+                          "%d byte page size, fallback to SW ECC\n",
+                          chip->ecc.size, mtd->writesize);
                chip->ecc.mode = NAND_ECC_SOFT;
 
        case NAND_ECC_SOFT:
@@ -3047,11 +3233,12 @@ int nand_scan_tail(struct mtd_info *mtd)
                if (!chip->ecc.size)
                        chip->ecc.size = 256;
                chip->ecc.bytes = 3;
+               chip->ecc.strength = 1;
                break;
 
        case NAND_ECC_SOFT_BCH:
                if (!mtd_nand_has_bch()) {
-                       printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n");
+                       pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");
                        return -EINVAL;
                }
                chip->ecc.calculate = nand_bch_calculate_ecc;
@@ -3066,8 +3253,8 @@ int nand_scan_tail(struct mtd_info *mtd)
                /*
                 * Board driver should supply ecc.size and ecc.bytes values to
                 * select how many bits are correctable; see nand_bch_init()
-                * for details.
-                * Otherwise, default to 4 bits for large page devices
+                * for details. Otherwise, default to 4 bits for large page
+                * devices.
                 */
                if (!chip->ecc.size && (mtd->oobsize >= 64)) {
                        chip->ecc.size = 512;
@@ -3078,13 +3265,14 @@ int nand_scan_tail(struct mtd_info *mtd)
                                               chip->ecc.bytes,
                                               &chip->ecc.layout);
                if (!chip->ecc.priv)
-                       printk(KERN_WARNING "BCH ECC initialization failed!\n");
-
+                       pr_warn("BCH ECC initialization failed!\n");
+               chip->ecc.strength =
+                       chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);
                break;
 
        case NAND_ECC_NONE:
-               printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
-                      "This is not recommended !!\n");
+               pr_warn("NAND_ECC_NONE selected by board driver. "
+                       "This is not recommended !!\n");
                chip->ecc.read_page = nand_read_page_raw;
                chip->ecc.write_page = nand_write_page_raw;
                chip->ecc.read_oob = nand_read_oob_std;
@@ -3096,14 +3284,19 @@ int nand_scan_tail(struct mtd_info *mtd)
                break;
 
        default:
-               printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
-                      chip->ecc.mode);
+               pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);
                BUG();
        }
 
+       /* For many systems, the standard OOB write also works for raw */
+       if (!chip->ecc.read_oob_raw)
+               chip->ecc.read_oob_raw = chip->ecc.read_oob;
+       if (!chip->ecc.write_oob_raw)
+               chip->ecc.write_oob_raw = chip->ecc.write_oob;
+
        /*
         * The number of bytes available for a client to place data into
-        * the out of band area
+        * the out of band area.
         */
        chip->ecc.layout->oobavail = 0;
        for (i = 0; chip->ecc.layout->oobfree[i].length
@@ -3114,19 +3307,16 @@ int nand_scan_tail(struct mtd_info *mtd)
 
        /*
         * Set the number of read / write steps for one page depending on ECC
-        * mode
+        * mode.
         */
        chip->ecc.steps = mtd->writesize / chip->ecc.size;
        if (chip->ecc.steps * chip->ecc.size != mtd->writesize) {
-               printk(KERN_WARNING "Invalid ecc parameters\n");
+               pr_warn("Invalid ECC parameters\n");
                BUG();
        }
        chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
 
-       /*
-        * Allow subpage writes up to ecc.steps. Not possible for MLC
-        * FLASH.
-        */
+       /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
        if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
            !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
                switch (chip->ecc.steps) {
@@ -3159,21 +3349,29 @@ int nand_scan_tail(struct mtd_info *mtd)
        mtd->type = MTD_NANDFLASH;
        mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
                                                MTD_CAP_NANDFLASH;
-       mtd->erase = nand_erase;
-       mtd->point = NULL;
-       mtd->unpoint = NULL;
-       mtd->read = nand_read;
-       mtd->write = nand_write;
-       mtd->read_oob = nand_read_oob;
-       mtd->write_oob = nand_write_oob;
-       mtd->sync = nand_sync;
-       mtd->lock = NULL;
-       mtd->unlock = NULL;
-       mtd->block_isbad = nand_block_isbad;
-       mtd->block_markbad = nand_block_markbad;
-
-       /* propagate ecc.layout to mtd_info */
+       mtd->_erase = nand_erase;
+       mtd->_point = NULL;
+       mtd->_unpoint = NULL;
+       mtd->_read = nand_read;
+       mtd->_write = nand_write;
+       mtd->_read_oob = nand_read_oob;
+       mtd->_write_oob = nand_write_oob;
+       mtd->_sync = nand_sync;
+       mtd->_lock = NULL;
+       mtd->_unlock = NULL;
+       mtd->_block_isbad = nand_block_isbad;
+       mtd->_block_markbad = nand_block_markbad;
+
+       /* propagate ecc info to mtd_info */
        mtd->ecclayout = chip->ecc.layout;
+       mtd->ecc_strength = chip->ecc.strength;
+       /*
+        * Initialize bitflip_threshold to its default prior scan_bbt() call.
+        * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+        * properly set.
+        */
+       if (!mtd->bitflip_threshold)
+               mtd->bitflip_threshold = mtd->ecc_strength;
 
        /* Check, if we should skip the bad block table scan */
        if (chip->options & NAND_SKIP_BBTSCAN)
@@ -3184,15 +3382,13 @@ int nand_scan_tail(struct mtd_info *mtd)
 
 /**
  * nand_scan - [NAND Interface] Scan for the NAND device
- * @mtd:       MTD device structure
- * @maxchips:  Number of chips to scan for
- *
- * This fills out all the uninitialized function pointers
- * with the defaults.
- * The flash ID is read and the mtd/chip structures are
- * filled with the appropriate values.
- * The mtd->owner field must be set to the module of the caller
+ * @mtd: MTD device structure
+ * @maxchips: number of chips to scan for
  *
+ * This fills out all the uninitialized function pointers with the defaults.
+ * The flash ID is read and the mtd/chip structures are filled with the
+ * appropriate values. The mtd->owner field must be set to the module of the
+ * caller.
  */
 int nand_scan(struct mtd_info *mtd, int maxchips)
 {
@@ -3206,8 +3402,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
 
 /**
  * nand_release - [NAND Interface] Free resources held by the NAND device
- * @mtd:       MTD device structure
-*/
+ * @mtd: MTD device structure
+ */
 void nand_release(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
index 74a7061b055efe51defdb2a0f2271364d34029bc..8ef58451d522131ba3b9bec3c116531c94217681 100644 (file)
@@ -4,7 +4,7 @@
  *  Overview:
  *   Bad block table support for the NAND driver
  *
- *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
+ *  Copyright Â© 2004 Thomas Gleixner (tglx@linutronix.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -14,7 +14,7 @@
  *
  * When nand_scan_bbt is called, then it tries to find the bad block table
  * depending on the options in the BBT descriptor(s). If no flash based BBT
- * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory
+ * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
  * marked good / bad blocks. This information is used to create a memory BBT.
  * Once a new bad block is discovered then the "factory" information is updated
  * on the device.
@@ -22,7 +22,7 @@
  * BBT on flash. If a BBT is found then the contents are read and the memory
  * based BBT is created. If a mirrored BBT is selected then the mirror is
  * searched too and the versions are compared. If the mirror has a greater
- * version number than the mirror BBT is used to build the memory based BBT.
+ * version number, then the mirror BBT is used to build the memory based BBT.
  * If the tables are not versioned, then we "or" the bad block information.
  * If one of the BBTs is out of date or does not exist it is (re)created.
  * If no BBT exists at all then the device is scanned for factory marked
@@ -36,9 +36,9 @@
  * The table is marked in the OOB area with an ident pattern and a version
  * number which indicates which of both tables is more up to date. If the NAND
  * controller needs the complete OOB area for the ECC information then the
- * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern
- * and the version byte into the data area and the OOB area will remain
- * untouched.
+ * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
+ * course): it moves the ident pattern and the version byte into the data area
+ * and the OOB area will remain untouched.
  *
  * The table uses 2 bits per block
  * 11b:                block is good
 #include <malloc.h>
 #include <linux/compat.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/bbm.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/bitops.h>
+#include <linux/string.h>
 
 #include <asm/errno.h>
 
 static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
 {
-       int ret;
-
-       ret = memcmp(buf, td->pattern, td->len);
-       if (!ret)
-               return ret;
-       return -1;
+       if (memcmp(buf, td->pattern, td->len))
+               return -1;
+       return 0;
 }
 
 /**
  * check_pattern - [GENERIC] check if a pattern is in the buffer
- * @buf:       the buffer to search
- * @len:       the length of buffer to search
- * @paglen:    the pagelength
- * @td:                search pattern descriptor
- *
- * Check for a pattern at the given place. Used to search bad block
- * tables and good / bad block identifiers.
- * If the SCAN_EMPTY option is set then check, if all bytes except the
- * pattern area contain 0xff
+ * @buf: the buffer to search
+ * @len: the length of buffer to search
+ * @paglen: the pagelength
+ * @td: search pattern descriptor
  *
-*/
+ * Check for a pattern at the given place. Used to search bad block tables and
+ * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
+ * all bytes except the pattern area contain 0xff.
+ */
 static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
-       int i, end = 0;
+       int end = 0;
        uint8_t *p = buf;
 
        if (td->options & NAND_BBT_NO_OOB)
                return check_pattern_no_oob(buf, td);
 
        end = paglen + td->offs;
-       if (td->options & NAND_BBT_SCANEMPTY) {
-               for (i = 0; i < end; i++) {
-                       if (p[i] != 0xff)
-                               return -1;
-               }
-       }
+       if (td->options & NAND_BBT_SCANEMPTY)
+               if (memchr_inv(p, 0xff, end))
+                       return -1;
        p += end;
 
        /* Compare the pattern */
-       for (i = 0; i < td->len; i++) {
-               if (p[i] != td->pattern[i])
-                       return -1;
-       }
-
-       /* Check both positions 1 and 6 for pattern? */
-       if (td->options & NAND_BBT_SCANBYTE1AND6) {
-               if (td->options & NAND_BBT_SCANEMPTY) {
-                       p += td->len;
-                       end += NAND_SMALL_BADBLOCK_POS - td->offs;
-                       /* Check region between positions 1 and 6 */
-                       for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len;
-                                       i++) {
-                               if (*p++ != 0xff)
-                                       return -1;
-                       }
-               }
-               else {
-                       p += NAND_SMALL_BADBLOCK_POS - td->offs;
-               }
-               /* Compare the pattern */
-               for (i = 0; i < td->len; i++) {
-                       if (p[i] != td->pattern[i])
-                               return -1;
-               }
-       }
+       if (memcmp(p, td->pattern, td->len))
+               return -1;
 
        if (td->options & NAND_BBT_SCANEMPTY) {
                p += td->len;
                end += td->len;
-               for (i = end; i < len; i++) {
-                       if (*p++ != 0xff)
-                               return -1;
-               }
+               if (memchr_inv(p, 0xff, len - end))
+                       return -1;
        }
        return 0;
 }
 
 /**
  * check_short_pattern - [GENERIC] check if a pattern is in the buffer
- * @buf:       the buffer to search
- * @td:                search pattern descriptor
+ * @buf: the buffer to search
+ * @td:        search pattern descriptor
  *
- * Check for a pattern at the given place. Used to search bad block
- * tables and good / bad block identifiers. Same as check_pattern, but
- * no optional empty check
- *
-*/
+ * Check for a pattern at the given place. Used to search bad block tables and
+ * good / bad block identifiers. Same as check_pattern, but no optional empty
+ * check.
+ */
 static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
 {
-       int i;
-       uint8_t *p = buf;
-
        /* Compare the pattern */
-       for (i = 0; i < td->len; i++) {
-               if (p[td->offs + i] != td->pattern[i])
-                       return -1;
-       }
-       /* Need to check location 1 AND 6? */
-       if (td->options & NAND_BBT_SCANBYTE1AND6) {
-               for (i = 0; i < td->len; i++) {
-                       if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i])
-                               return -1;
-               }
-       }
+       if (memcmp(buf + td->offs, td->pattern, td->len))
+               return -1;
        return 0;
 }
 
 /**
  * add_marker_len - compute the length of the marker in data area
- * @td:                BBT descriptor used for computation
+ * @td: BBT descriptor used for computation
  *
- * The length will be 0 if the markeris located in OOB area.
+ * The length will be 0 if the marker is located in OOB area.
  */
 static u32 add_marker_len(struct nand_bbt_descr *td)
 {
@@ -199,34 +154,33 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
 
 /**
  * read_bbt - [GENERIC] Read the bad block table starting from page
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @page:      the starting page
- * @num:       the number of bbt descriptors to read
- * @td:                the bbt describtion table
- * @offs:      offset in the memory table
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @page: the starting page
+ * @num: the number of bbt descriptors to read
+ * @td: the bbt describtion table
+ * @offs: offset in the memory table
  *
  * Read the bad block table starting from page.
- *
  */
 static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                struct nand_bbt_descr *td, int offs)
 {
-       int res, i, j, act = 0;
+       int res, ret = 0, i, j, act = 0;
        struct nand_chip *this = mtd->priv;
        size_t retlen, len, totlen;
        loff_t from;
        int bits = td->options & NAND_BBT_NRBITS_MSK;
-       uint8_t msk = (uint8_t) ((1 << bits) - 1);
+       uint8_t msk = (uint8_t)((1 << bits) - 1);
        u32 marker_len;
        int reserved_block_code = td->reserved_block_code;
 
        totlen = (num * bits) >> 3;
        marker_len = add_marker_len(td);
-       from = ((loff_t) page) << this->page_shift;
+       from = ((loff_t)page) << this->page_shift;
 
        while (totlen) {
-               len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
+               len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
                if (marker_len) {
                        /*
                         * In case the BBT marker is not in the OOB area it
@@ -236,13 +190,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                        from += marker_len;
                        marker_len = 0;
                }
-               res = mtd->read(mtd, from, len, &retlen, buf);
+               res = mtd_read(mtd, from, len, &retlen, buf);
                if (res < 0) {
-                       if (retlen != len) {
-                               printk(KERN_INFO "nand_bbt: Error reading bad block table\n");
+                       if (mtd_is_eccerr(res)) {
+                               pr_info("nand_bbt: ECC error in BBT at "
+                                       "0x%012llx\n", from & ~mtd->writesize);
+                               return res;
+                       } else if (mtd_is_bitflip(res)) {
+                               pr_info("nand_bbt: corrected error in BBT at "
+                                       "0x%012llx\n", from & ~mtd->writesize);
+                               ret = res;
+                       } else {
+                               pr_info("nand_bbt: error reading BBT\n");
                                return res;
                        }
-                       printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");
                }
 
                /* Analyse data */
@@ -253,17 +214,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                if (tmp == msk)
                                        continue;
                                if (reserved_block_code && (tmp == reserved_block_code)) {
-                                       printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
-                                              (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+                                       pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
+                                                (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
                                        this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
                                        mtd->ecc_stats.bbtblocks++;
                                        continue;
                                }
-                               MTDDEBUG(MTD_DEBUG_LEVEL0, "nand_read_bbt: " \
-                                       "Bad block at 0x%012llx\n",
+                               pr_info("nand_read_bbt: Bad block at 0x%012llx\n",
                                        (loff_t)((offs << 2) + (act >> 1))
                                        << this->bbt_erase_shift);
-                               /* Factory marked bad or worn out ? */
+                               /* Factory marked bad or worn out? */
                                if (tmp == 0)
                                        this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
                                else
@@ -274,20 +234,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                totlen -= len;
                from += len;
        }
-       return 0;
+       return ret;
 }
 
 /**
  * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @td:                descriptor for the bad block table
- * @chip:      read the table for a specific chip, -1 read all chips.
- *             Applies only if NAND_BBT_PERCHIP option is set
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @chip: read the table for a specific chip, -1 read all chips; applies only if
+ *        NAND_BBT_PERCHIP option is set
  *
- * Read the bad block table for all chips starting at a given page
- * We assume that the bbt bits are in consecutive order.
-*/
+ * Read the bad block table for all chips starting at a given page. We assume
+ * that the bbt bits are in consecutive order.
+ */
 static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
 {
        struct nand_chip *this = mtd->priv;
@@ -313,10 +273,8 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
        return 0;
 }
 
-/*
- * BBT marker is in the first page, no OOB.
- */
-static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+/* BBT marker is in the first page, no OOB */
+static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         struct nand_bbt_descr *td)
 {
        size_t retlen;
@@ -326,70 +284,73 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
        if (td->options & NAND_BBT_VERSION)
                len++;
 
-       return mtd->read(mtd, offs, len, &retlen, buf);
+       return mtd_read(mtd, offs, len, &retlen, buf);
 }
 
-/*
- * Scan read raw data from flash
+/**
+ * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @offs: offset at which to scan
+ * @len: length of data region to read
+ *
+ * Scan read data from data+OOB. May traverse multiple pages, interleaving
+ * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
+ * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
  */
-static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         size_t len)
 {
        struct mtd_oob_ops ops;
-       int res;
+       int res, ret = 0;
 
-       ops.mode = MTD_OOB_RAW;
+       ops.mode = MTD_OPS_PLACE_OOB;
        ops.ooboffs = 0;
        ops.ooblen = mtd->oobsize;
 
-
        while (len > 0) {
-               if (len <= mtd->writesize) {
-                       ops.oobbuf = buf + len;
-                       ops.datbuf = buf;
-                       ops.len = len;
-                       return mtd->read_oob(mtd, offs, &ops);
-               } else {
-                       ops.oobbuf = buf + mtd->writesize;
-                       ops.datbuf = buf;
-                       ops.len = mtd->writesize;
-                       res = mtd->read_oob(mtd, offs, &ops);
+               ops.datbuf = buf;
+               ops.len = min(len, (size_t)mtd->writesize);
+               ops.oobbuf = buf + ops.len;
 
-                       if (res)
+               res = mtd_read_oob(mtd, offs, &ops);
+               if (res) {
+                       if (!mtd_is_bitflip_or_eccerr(res))
                                return res;
+                       else if (mtd_is_eccerr(res) || !ret)
+                               ret = res;
                }
 
                buf += mtd->oobsize + mtd->writesize;
                len -= mtd->writesize;
+               offs += mtd->writesize;
        }
-       return 0;
+       return ret;
 }
 
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         size_t len, struct nand_bbt_descr *td)
 {
        if (td->options & NAND_BBT_NO_OOB)
-               return scan_read_raw_data(mtd, buf, offs, td);
+               return scan_read_data(mtd, buf, offs, td);
        else
-               return scan_read_raw_oob(mtd, buf, offs, len);
+               return scan_read_oob(mtd, buf, offs, len);
 }
 
-/*
- * Scan write data with oob to flash
- */
+/* Scan write data with oob to flash */
 static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
                          uint8_t *buf, uint8_t *oob)
 {
        struct mtd_oob_ops ops;
 
-       ops.mode = MTD_OOB_PLACE;
+       ops.mode = MTD_OPS_PLACE_OOB;
        ops.ooboffs = 0;
        ops.ooblen = mtd->oobsize;
        ops.datbuf = buf;
        ops.oobbuf = oob;
        ops.len = len;
 
-       return mtd->write_oob(mtd, offs, &ops);
+       return mtd_write_oob(mtd, offs, &ops);
 }
 
 static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
@@ -403,65 +364,60 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
 
 /**
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @td:                descriptor for the bad block table
- * @md:                descriptor for the bad block table mirror
- *
- * Read the bad block table(s) for all chips starting at a given page
- * We assume that the bbt bits are in consecutive order.
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @md:        descriptor for the bad block table mirror
  *
-*/
-static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
-                        struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+ * Read the bad block table(s) for all chips starting at a given page. We
+ * assume that the bbt bits are in consecutive order.
+ */
+static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+                         struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
        struct nand_chip *this = mtd->priv;
 
        /* Read the primary version, if available */
        if (td->options & NAND_BBT_VERSION) {
-               scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+               scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
                              mtd->writesize, td);
                td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
-               printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
-                      td->pages[0], td->version[0]);
+               pr_info("Bad block table at page %d, version 0x%02X\n",
+                        td->pages[0], td->version[0]);
        }
 
        /* Read the mirror version, if available */
        if (md && (md->options & NAND_BBT_VERSION)) {
-               scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
-                             mtd->writesize, td);
+               scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+                             mtd->writesize, md);
                md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
-               printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
-                      md->pages[0], md->version[0]);
+               pr_info("Bad block table at page %d, version 0x%02X\n",
+                        md->pages[0], md->version[0]);
        }
-       return 1;
 }
 
-/*
- * Scan a given block full
- */
+/* Scan a given block full */
 static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
                           loff_t offs, uint8_t *buf, size_t readlen,
-                          int scanlen, int len)
+                          int scanlen, int numpages)
 {
        int ret, j;
 
-       ret = scan_read_raw_oob(mtd, buf, offs, readlen);
-       if (ret)
+       ret = scan_read_oob(mtd, buf, offs, readlen);
+       /* Ignore ECC errors when checking for BBM */
+       if (ret && !mtd_is_bitflip_or_eccerr(ret))
                return ret;
 
-       for (j = 0; j < len; j++, buf += scanlen) {
+       for (j = 0; j < numpages; j++, buf += scanlen) {
                if (check_pattern(buf, scanlen, mtd->writesize, bd))
                        return 1;
        }
        return 0;
 }
 
-/*
- * Scan a given block partially
- */
+/* Scan a given block partially */
 static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
-                          loff_t offs, uint8_t *buf, int len)
+                          loff_t offs, uint8_t *buf, int numpages)
 {
        struct mtd_oob_ops ops;
        int j, ret;
@@ -470,16 +426,16 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
        ops.oobbuf = buf;
        ops.ooboffs = 0;
        ops.datbuf = NULL;
-       ops.mode = MTD_OOB_PLACE;
+       ops.mode = MTD_OPS_PLACE_OOB;
 
-       for (j = 0; j < len; j++) {
+       for (j = 0; j < numpages; j++) {
                /*
-                * Read the full oob until read_oob is fixed to
-                * handle single byte reads for 16 bit
-                * buswidth
+                * Read the full oob until read_oob is fixed to handle single
+                * byte reads for 16 bit buswidth.
                 */
-               ret = mtd->read_oob(mtd, offs, &ops);
-               if (ret)
+               ret = mtd_read_oob(mtd, offs, &ops);
+               /* Ignore ECC errors when checking for BBM */
+               if (ret && !mtd_is_bitflip_or_eccerr(ret))
                        return ret;
 
                if (check_short_pattern(buf, bd))
@@ -492,32 +448,32 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 
 /**
  * create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @bd:                descriptor for the good/bad block search pattern
- * @chip:      create the table for a specific chip, -1 read all chips.
- *             Applies only if NAND_BBT_PERCHIP option is set
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @bd: descriptor for the good/bad block search pattern
+ * @chip: create the table for a specific chip, -1 read all chips; applies only
+ *        if NAND_BBT_PERCHIP option is set
  *
- * Create a bad block table by scanning the device
- * for the given good/bad block identify pattern
+ * Create a bad block table by scanning the device for the given good/bad block
+ * identify pattern.
  */
 static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
        struct nand_bbt_descr *bd, int chip)
 {
        struct nand_chip *this = mtd->priv;
-       int i, numblocks, len, scanlen;
+       int i, numblocks, numpages, scanlen;
        int startblock;
        loff_t from;
        size_t readlen;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");
+       pr_info("Scanning device for bad blocks\n");
 
        if (bd->options & NAND_BBT_SCANALLPAGES)
-               len = 1 << (this->bbt_erase_shift - this->page_shift);
+               numpages = 1 << (this->bbt_erase_shift - this->page_shift);
        else if (bd->options & NAND_BBT_SCAN2NDPAGE)
-               len = 2;
+               numpages = 2;
        else
-               len = 1;
+               numpages = 1;
 
        if (!(bd->options & NAND_BBT_SCANEMPTY)) {
                /* We need only read few bytes from the OOB area */
@@ -526,18 +482,20 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
        } else {
                /* Full page content should be read */
                scanlen = mtd->writesize + mtd->oobsize;
-               readlen = len * mtd->writesize;
+               readlen = numpages * mtd->writesize;
        }
 
        if (chip == -1) {
-               /* Note that numblocks is 2 * (real numblocks) here, see i+=2
-                * below as it makes shifting and masking less painful */
+               /*
+                * Note that numblocks is 2 * (real numblocks) here, see i+=2
+                * below as it makes shifting and masking less painful
+                */
                numblocks = mtd->size >> (this->bbt_erase_shift - 1);
                startblock = 0;
                from = 0;
        } else {
                if (chip >= this->numchips) {
-                       printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
+                       pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
                               chip + 1, this->numchips);
                        return -EINVAL;
                }
@@ -547,8 +505,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
                from = (loff_t)startblock << (this->bbt_erase_shift - 1);
        }
 
-       if (this->options & NAND_BBT_SCANLASTPAGE)
-               from += mtd->erasesize - (mtd->writesize * len);
+       if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
+               from += mtd->erasesize - (mtd->writesize * numpages);
 
        for (i = startblock; i < numblocks;) {
                int ret;
@@ -557,17 +515,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
                if (bd->options & NAND_BBT_SCANALLPAGES)
                        ret = scan_block_full(mtd, bd, from, buf, readlen,
-                                             scanlen, len);
+                                             scanlen, numpages);
                else
-                       ret = scan_block_fast(mtd, bd, from, buf, len);
+                       ret = scan_block_fast(mtd, bd, from, buf, numpages);
 
                if (ret < 0)
                        return ret;
 
                if (ret) {
                        this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-                       MTDDEBUG(MTD_DEBUG_LEVEL0,
-                                 "Bad eraseblock %d at 0x%012llx\n",
+                       pr_warn("Bad eraseblock %d at 0x%012llx\n",
                                  i >> 1, (unsigned long long)from);
                        mtd->ecc_stats.badblocks++;
                }
@@ -580,20 +537,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 /**
  * search_bbt - [GENERIC] scan the device for a specific bad block table
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @td:                descriptor for the bad block table
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
  *
- * Read the bad block table by searching for a given ident pattern.
- * Search is preformed either from the beginning up or from the end of
- * the device downwards. The search starts always at the start of a
- * block.
- * If the option NAND_BBT_PERCHIP is given, each chip is searched
- * for a bbt, which contains the bad block information of this chip.
- * This is necessary to provide support for certain DOC devices.
+ * Read the bad block table by searching for a given ident pattern. Search is
+ * preformed either from the beginning up or from the end of the device
+ * downwards. The search starts always at the start of a block. If the option
+ * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
+ * the bad block information of this chip. This is necessary to provide support
+ * for certain DOC devices.
  *
- * The bbt ident pattern resides in the oob area of the first page
- * in a block.
+ * The bbt ident pattern resides in the oob area of the first page in a block.
  */
 static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
 {
@@ -604,7 +559,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
        int bbtblocks;
        int blocktopage = this->bbt_erase_shift - this->page_shift;
 
-       /* Search direction top -> down ? */
+       /* Search direction top -> down? */
        if (td->options & NAND_BBT_LASTBLOCK) {
                startblock = (mtd->size >> this->bbt_erase_shift) - 1;
                dir = -1;
@@ -613,7 +568,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                dir = 1;
        }
 
-       /* Do we have a bbt per chip ? */
+       /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP) {
                chips = this->numchips;
                bbtblocks = this->chipsize >> this->bbt_erase_shift;
@@ -634,7 +589,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                        loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
 
                        /* Read first page */
-                       scan_read_raw(mtd, buf, offs, mtd->writesize, td);
+                       scan_read(mtd, buf, offs, mtd->writesize, td);
                        if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
                                td->pages[i] = actblock << blocktopage;
                                if (td->options & NAND_BBT_VERSION) {
@@ -649,10 +604,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
        /* Check, if we found a bbt for each requested chip */
        for (i = 0; i < chips; i++) {
                if (td->pages[i] == -1)
-                       printk(KERN_WARNING "Bad block table not found for chip %d\n", i);
+                       pr_warn("Bad block table not found for chip %d\n", i);
                else
-                       MTDDEBUG(MTD_DEBUG_LEVEL0, "Bad block table found " \
-                               "at page %d, version 0x%02X\n", td->pages[i],
+                       pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[i],
                                td->version[i]);
        }
        return 0;
@@ -660,14 +614,16 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 
 /**
  * search_read_bbts - [GENERIC] scan the device for bad block table(s)
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @td:                descriptor for the bad block table
- * @md:                descriptor for the bad block table mirror
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @md: descriptor for the bad block table mirror
  *
- * Search and read the bad block table(s)
-*/
-static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+ * Search and read the bad block table(s).
+ */
+static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+                            struct nand_bbt_descr *td,
+                            struct nand_bbt_descr *md)
 {
        /* Search the primary table */
        search_bbt(mtd, buf, td);
@@ -675,23 +631,18 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt
        /* Search the mirror table */
        if (md)
                search_bbt(mtd, buf, md);
-
-       /* Force result check */
-       return 1;
 }
 
 /**
  * write_bbt - [GENERIC] (Re)write the bad block table
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @md: descriptor for the bad block table mirror
+ * @chipsel: selector for a specific chip, -1 for all
  *
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @td:                descriptor for the bad block table
- * @md:                descriptor for the bad block table mirror
- * @chipsel:   selector for a specific chip, -1 for all
- *
- * (Re)write the bad block table
- *
-*/
+ * (Re)write the bad block table.
+ */
 static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
                     int chipsel)
@@ -710,14 +661,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
        ops.ooblen = mtd->oobsize;
        ops.ooboffs = 0;
        ops.datbuf = NULL;
-       ops.mode = MTD_OOB_PLACE;
+       ops.mode = MTD_OPS_PLACE_OOB;
 
        if (!rcode)
                rcode = 0xff;
-       /* Write bad block table per chip rather than per device ? */
+       /* Write bad block table per chip rather than per device? */
        if (td->options & NAND_BBT_PERCHIP) {
                numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
-               /* Full device write or specific chip ? */
+               /* Full device write or specific chip? */
                if (chipsel == -1) {
                        nrchips = this->numchips;
                } else {
@@ -731,8 +682,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 
        /* Loop through the chips */
        for (; chip < nrchips; chip++) {
-
-               /* There was already a version of the table, reuse the page
+               /*
+                * There was already a version of the table, reuse the page
                 * This applies for absolute placement too, as we have the
                 * page nr. in td->pages.
                 */
@@ -741,8 +692,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        goto write;
                }
 
-               /* Automatic placement of the bad block table */
-               /* Search direction top -> down ? */
+               /*
+                * Automatic placement of the bad block table. Search direction
+                * top -> down?
+                */
                if (td->options & NAND_BBT_LASTBLOCK) {
                        startblock = numblocks * (chip + 1) - 1;
                        dir = -1;
@@ -766,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        if (!md || md->pages[chip] != page)
                                goto write;
                }
-               printk(KERN_ERR "No space left to write bad block table\n");
+               pr_err("No space left to write bad block table\n");
                return -ENOSPC;
        write:
 
@@ -791,29 +744,27 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 
                bbtoffs = chip * (numblocks >> 2);
 
-               to = ((loff_t) page) << this->page_shift;
+               to = ((loff_t)page) << this->page_shift;
 
-               /* Must we save the block contents ? */
+               /* Must we save the block contents? */
                if (td->options & NAND_BBT_SAVECONTENT) {
                        /* Make it block aligned */
-                       to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
+                       to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
                        len = 1 << this->bbt_erase_shift;
-                       res = mtd->read(mtd, to, len, &retlen, buf);
+                       res = mtd_read(mtd, to, len, &retlen, buf);
                        if (res < 0) {
                                if (retlen != len) {
-                                       printk(KERN_INFO "nand_bbt: Error "
-                                              "reading block for writing "
-                                              "the bad block table\n");
+                                       pr_info("nand_bbt: error reading block "
+                                               "for writing the bad block table\n");
                                        return res;
                                }
-                               printk(KERN_WARNING "nand_bbt: ECC error "
-                                      "while reading block for writing "
-                                      "bad block table\n");
+                               pr_warn("nand_bbt: ECC error while reading "
+                                       "block for writing bad block table\n");
                        }
                        /* Read oob data */
                        ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
                        ops.oobbuf = &buf[len];
-                       res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
+                       res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
                        if (res < 0 || ops.oobretlen != ops.ooblen)
                                goto outerr;
 
@@ -821,19 +772,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        pageoffs = page - (int)(to >> this->page_shift);
                        offs = pageoffs << this->page_shift;
                        /* Preset the bbt area with 0xff */
-                       memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
+                       memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
                        ooboffs = len + (pageoffs * mtd->oobsize);
 
                } else if (td->options & NAND_BBT_NO_OOB) {
                        ooboffs = 0;
                        offs = td->len;
-                       /* the version byte */
+                       /* The version byte */
                        if (td->options & NAND_BBT_VERSION)
                                offs++;
                        /* Calc length */
-                       len = (size_t) (numblocks >> sft);
+                       len = (size_t)(numblocks >> sft);
                        len += offs;
-                       /* Make it page aligned ! */
+                       /* Make it page aligned! */
                        len = ALIGN(len, mtd->writesize);
                        /* Preset the buffer with 0xff */
                        memset(buf, 0xff, len);
@@ -841,8 +792,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        memcpy(buf, td->pattern, td->len);
                } else {
                        /* Calc length */
-                       len = (size_t) (numblocks >> sft);
-                       /* Make it page aligned ! */
+                       len = (size_t)(numblocks >> sft);
+                       /* Make it page aligned! */
                        len = ALIGN(len, mtd->writesize);
                        /* Preset the buffer with 0xff */
                        memset(buf, 0xff, len +
@@ -856,13 +807,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                if (td->options & NAND_BBT_VERSION)
                        buf[ooboffs + td->veroffs] = td->version[chip];
 
-               /* walk through the memory table */
+               /* Walk through the memory table */
                for (i = 0; i < numblocks;) {
                        uint8_t dat;
                        dat = this->bbt[bbtoffs + (i >> 2)];
                        for (j = 0; j < 4; j++, i++) {
                                int sftcnt = (i << (3 - sft)) & sftmsk;
-                               /* Do not store the reserved bbt blocks ! */
+                               /* Do not store the reserved bbt blocks! */
                                buf[offs + (i >> sft)] &=
                                        ~(msk[dat & 0x03] << sftcnt);
                                dat >>= 2;
@@ -883,8 +834,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                if (res < 0)
                        goto outerr;
 
-               printk(KERN_DEBUG "Bad block table written to 0x%012llx, version "
-                      "0x%02X\n", (unsigned long long)to, td->version[chip]);
+               pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
+                        (unsigned long long)to, td->version[chip]);
 
                /* Mark it as used */
                td->pages[chip] = page;
@@ -892,19 +843,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
        return 0;
 
  outerr:
-       printk(KERN_WARNING
-              "nand_bbt: Error while writing bad block table %d\n", res);
+       pr_warn("nand_bbt: error while writing bad block table %d\n", res);
        return res;
 }
 
 /**
  * nand_memory_bbt - [GENERIC] create a memory based bad block table
- * @mtd:       MTD device structure
- * @bd:                descriptor for the good/bad block search pattern
+ * @mtd: MTD device structure
+ * @bd: descriptor for the good/bad block search pattern
  *
- * The function creates a memory based bbt by scanning the device
- * for manufacturer / software marked good / bad blocks
-*/
+ * The function creates a memory based bbt by scanning the device for
+ * manufacturer / software marked good / bad blocks.
+ */
 static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
        struct nand_chip *this = mtd->priv;
@@ -915,25 +865,24 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
 
 /**
  * check_create - [GENERIC] create and write bbt(s) if necessary
- * @mtd:       MTD device structure
- * @buf:       temporary buffer
- * @bd:                descriptor for the good/bad block search pattern
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @bd: descriptor for the good/bad block search pattern
  *
- * The function checks the results of the previous call to read_bbt
- * and creates / updates the bbt(s) if necessary
- * Creation is necessary if no bbt was found for the chip/device
- * Update is necessary if one of the tables is missing or the
- * version nr. of one table is less than the other
-*/
+ * The function checks the results of the previous call to read_bbt and creates
+ * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
+ * for the chip/device. Update is necessary if one of the tables is missing or
+ * the version nr. of one table is less than the other.
+ */
 static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
 {
-       int i, chips, writeops, chipsel, res;
+       int i, chips, writeops, create, chipsel, res, res2;
        struct nand_chip *this = mtd->priv;
        struct nand_bbt_descr *td = this->bbt_td;
        struct nand_bbt_descr *md = this->bbt_md;
        struct nand_bbt_descr *rd, *rd2;
 
-       /* Do we have a bbt per chip ? */
+       /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP)
                chips = this->numchips;
        else
@@ -941,86 +890,98 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
        for (i = 0; i < chips; i++) {
                writeops = 0;
+               create = 0;
                rd = NULL;
                rd2 = NULL;
-               /* Per chip or per device ? */
+               res = res2 = 0;
+               /* Per chip or per device? */
                chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
-               /* Mirrored table available ? */
+               /* Mirrored table available? */
                if (md) {
                        if (td->pages[i] == -1 && md->pages[i] == -1) {
+                               create = 1;
                                writeops = 0x03;
-                               goto create;
-                       }
-
-                       if (td->pages[i] == -1) {
+                       } else if (td->pages[i] == -1) {
                                rd = md;
-                               td->version[i] = md->version[i];
-                               writeops = 1;
-                               goto writecheck;
-                       }
-
-                       if (md->pages[i] == -1) {
+                               writeops = 0x01;
+                       } else if (md->pages[i] == -1) {
                                rd = td;
-                               md->version[i] = td->version[i];
-                               writeops = 2;
-                               goto writecheck;
-                       }
-
-                       if (td->version[i] == md->version[i]) {
+                               writeops = 0x02;
+                       } else if (td->version[i] == md->version[i]) {
                                rd = td;
                                if (!(td->options & NAND_BBT_VERSION))
                                        rd2 = md;
-                               goto writecheck;
-                       }
-
-                       if (((int8_t) (td->version[i] - md->version[i])) > 0) {
+                       } else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
                                rd = td;
-                               md->version[i] = td->version[i];
-                               writeops = 2;
+                               writeops = 0x02;
                        } else {
                                rd = md;
-                               td->version[i] = md->version[i];
-                               writeops = 1;
+                               writeops = 0x01;
                        }
-
-                       goto writecheck;
-
                } else {
                        if (td->pages[i] == -1) {
+                               create = 1;
                                writeops = 0x01;
-                               goto create;
+                       } else {
+                               rd = td;
                        }
-                       rd = td;
-                       goto writecheck;
                }
-       create:
-               /* Create the bad block table by scanning the device ? */
-               if (!(td->options & NAND_BBT_CREATE))
-                       continue;
 
-               /* Create the table in memory by scanning the chip(s) */
-               if (!(this->options & NAND_CREATE_EMPTY_BBT))
-                       create_bbt(mtd, buf, bd, chipsel);
-
-               td->version[i] = 1;
-               if (md)
-                       md->version[i] = 1;
-       writecheck:
-               /* read back first ? */
-               if (rd)
-                       read_abs_bbt(mtd, buf, rd, chipsel);
-               /* If they weren't versioned, read both. */
-               if (rd2)
-                       read_abs_bbt(mtd, buf, rd2, chipsel);
-
-               /* Write the bad block table to the device ? */
+               if (create) {
+                       /* Create the bad block table by scanning the device? */
+                       if (!(td->options & NAND_BBT_CREATE))
+                               continue;
+
+                       /* Create the table in memory by scanning the chip(s) */
+                       if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
+                               create_bbt(mtd, buf, bd, chipsel);
+
+                       td->version[i] = 1;
+                       if (md)
+                               md->version[i] = 1;
+               }
+
+               /* Read back first? */
+               if (rd) {
+                       res = read_abs_bbt(mtd, buf, rd, chipsel);
+                       if (mtd_is_eccerr(res)) {
+                               /* Mark table as invalid */
+                               rd->pages[i] = -1;
+                               rd->version[i] = 0;
+                               i--;
+                               continue;
+                       }
+               }
+               /* If they weren't versioned, read both */
+               if (rd2) {
+                       res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+                       if (mtd_is_eccerr(res2)) {
+                               /* Mark table as invalid */
+                               rd2->pages[i] = -1;
+                               rd2->version[i] = 0;
+                               i--;
+                               continue;
+                       }
+               }
+
+               /* Scrub the flash table(s)? */
+               if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
+                       writeops = 0x03;
+
+               /* Update version numbers before writing */
+               if (md) {
+                       td->version[i] = max(td->version[i], md->version[i]);
+                       md->version[i] = td->version[i];
+               }
+
+               /* Write the bad block table to the device? */
                if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
                        res = write_bbt(mtd, buf, td, md, chipsel);
                        if (res < 0)
                                return res;
                }
 
-               /* Write the mirror bad block table to the device ? */
+               /* Write the mirror bad block table to the device? */
                if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
                        res = write_bbt(mtd, buf, md, td, chipsel);
                        if (res < 0)
@@ -1032,20 +993,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
 /**
  * mark_bbt_regions - [GENERIC] mark the bad block table regions
- * @mtd:       MTD device structure
- * @td:                bad block table descriptor
+ * @mtd: MTD device structure
+ * @td: bad block table descriptor
  *
- * The bad block table regions are marked as "bad" to prevent
- * accidental erasures / writes. The regions are identified by
- * the mark 0x02.
-*/
+ * The bad block table regions are marked as "bad" to prevent accidental
+ * erasures / writes. The regions are identified by the mark 0x02.
+ */
 static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 {
        struct nand_chip *this = mtd->priv;
        int i, j, chips, block, nrblocks, update;
        uint8_t oldval, newval;
 
-       /* Do we have a bbt per chip ? */
+       /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP) {
                chips = this->numchips;
                nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
@@ -1082,9 +1042,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                                update = 1;
                        block += 2;
                }
-               /* If we want reserved blocks to be recorded to flash, and some
-                  new ones have been marked, then we need to update the stored
-                  bbts.  This should only happen once. */
+               /*
+                * If we want reserved blocks to be recorded to flash, and some
+                * new ones have been marked, then we need to update the stored
+                * bbts.  This should only happen once.
+                */
                if (update && td->reserved_block_code)
                        nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
        }
@@ -1092,8 +1054,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 
 /**
  * verify_bbt_descr - verify the bad block description
- * @mtd:       MTD device structure
- * @bd:                the table to verify
+ * @mtd: MTD device structure
+ * @bd: the table to verify
  *
  * This functions performs a few sanity checks on the bad block description
  * table.
@@ -1111,16 +1073,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
        pattern_len = bd->len;
        bits = bd->options & NAND_BBT_NRBITS_MSK;
 
-       BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) &&
-                       !(this->options & NAND_USE_FLASH_BBT));
+       BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
+                       !(this->bbt_options & NAND_BBT_USE_FLASH));
        BUG_ON(!bits);
 
        if (bd->options & NAND_BBT_VERSION)
                pattern_len++;
 
        if (bd->options & NAND_BBT_NO_OOB) {
-               BUG_ON(!(this->options & NAND_USE_FLASH_BBT));
-               BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB));
+               BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
+               BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
                BUG_ON(bd->offs);
                if (bd->options & NAND_BBT_VERSION)
                        BUG_ON(bd->veroffs != bd->len);
@@ -1140,18 +1102,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
 /**
  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
- * @mtd:       MTD device structure
- * @bd:                descriptor for the good/bad block search pattern
- *
- * The function checks, if a bad block table(s) is/are already
- * available. If not it scans the device for manufacturer
- * marked good / bad blocks and writes the bad block table(s) to
- * the selected place.
+ * @mtd: MTD device structure
+ * @bd: descriptor for the good/bad block search pattern
  *
- * The bad block table memory is allocated here. It must be freed
- * by calling the nand_free_bbt function.
+ * The function checks, if a bad block table(s) is/are already available. If
+ * not it scans the device for manufacturer marked good / bad blocks and writes
+ * the bad block table(s) to the selected place.
  *
-*/
+ * The bad block table memory is allocated here. It must be freed by calling
+ * the nand_free_bbt function.
+ */
 int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
        struct nand_chip *this = mtd->priv;
@@ -1161,19 +1121,21 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
        struct nand_bbt_descr *md = this->bbt_md;
 
        len = mtd->size >> (this->bbt_erase_shift + 2);
-       /* Allocate memory (2bit per block) and clear the memory bad block table */
+       /*
+        * Allocate memory (2bit per block) and clear the memory bad block
+        * table.
+        */
        this->bbt = kzalloc(len, GFP_KERNEL);
-       if (!this->bbt) {
-               printk(KERN_ERR "nand_scan_bbt: Out of memory\n");
+       if (!this->bbt)
                return -ENOMEM;
-       }
 
-       /* If no primary table decriptor is given, scan the device
-        * to build a memory based bad block table
+       /*
+        * If no primary table decriptor is given, scan the device to build a
+        * memory based bad block table.
         */
        if (!td) {
                if ((res = nand_memory_bbt(mtd, bd))) {
-                       printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+                       pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
                        kfree(this->bbt);
                        this->bbt = NULL;
                }
@@ -1187,22 +1149,20 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
        len += (len >> this->page_shift) * mtd->oobsize;
        buf = vmalloc(len);
        if (!buf) {
-               printk(KERN_ERR "nand_bbt: Out of memory\n");
                kfree(this->bbt);
                this->bbt = NULL;
                return -ENOMEM;
        }
 
-       /* Is the bbt at a given page ? */
+       /* Is the bbt at a given page? */
        if (td->options & NAND_BBT_ABSPAGE) {
-               res = read_abs_bbts(mtd, buf, td, md);
+               read_abs_bbts(mtd, buf, td, md);
        } else {
                /* Search the bad block table using a pattern in oob */
-               res = search_read_bbts(mtd, buf, td, md);
+               search_read_bbts(mtd, buf, td, md);
        }
 
-       if (res)
-               res = check_create(mtd, buf, bd);
+       res = check_create(mtd, buf, bd);
 
        /* Prevent the bbt regions from erasing / writing */
        mark_bbt_region(mtd, td);
@@ -1215,15 +1175,15 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
 /**
  * nand_update_bbt - [NAND Interface] update bad block table(s)
- * @mtd:       MTD device structure
- * @offs:      the offset of the newly marked block
+ * @mtd: MTD device structure
+ * @offs: the offset of the newly marked block
  *
- * The function updates the bad block table(s)
-*/
+ * The function updates the bad block table(s).
+ */
 int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 {
        struct nand_chip *this = mtd->priv;
-       int len, res = 0, writeops = 0;
+       int len, res = 0;
        int chip, chipsel;
        uint8_t *buf;
        struct nand_bbt_descr *td = this->bbt_td;
@@ -1236,14 +1196,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
        len = (1 << this->bbt_erase_shift);
        len += (len >> this->page_shift) * mtd->oobsize;
        buf = kmalloc(len, GFP_KERNEL);
-       if (!buf) {
-               printk(KERN_ERR "nand_update_bbt: Out of memory\n");
+       if (!buf)
                return -ENOMEM;
-       }
 
-       writeops = md != NULL ? 0x03 : 0x01;
-
-       /* Do we have a bbt per chip ? */
+       /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP) {
                chip = (int)(offs >> this->chip_shift);
                chipsel = chip;
@@ -1256,14 +1212,14 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
        if (md)
                md->version[chip]++;
 
-       /* Write the bad block table to the device ? */
-       if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
+       /* Write the bad block table to the device? */
+       if (td->options & NAND_BBT_WRITE) {
                res = write_bbt(mtd, buf, td, md, chipsel);
                if (res < 0)
                        goto out;
        }
-       /* Write the mirror bad block table to the device ? */
-       if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
+       /* Write the mirror bad block table to the device? */
+       if (md && (md->options & NAND_BBT_WRITE)) {
                res = write_bbt(mtd, buf, md, td, chipsel);
        }
 
@@ -1272,8 +1228,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
        return res;
 }
 
-/* Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks. */
+/*
+ * Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks.
+ */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
 static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
@@ -1285,8 +1243,7 @@ static struct nand_bbt_descr agand_flashbased = {
        .pattern = scan_agand_pattern
 };
 
-/* Generic flash bbt decriptors
-*/
+/* Generic flash bbt descriptors */
 static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
 static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
 
@@ -1296,7 +1253,7 @@ static struct nand_bbt_descr bbt_main_descr = {
        .offs = 8,
        .len = 4,
        .veroffs = 12,
-       .maxblocks = 4,
+       .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
        .pattern = bbt_pattern
 };
 
@@ -1306,55 +1263,51 @@ static struct nand_bbt_descr bbt_mirror_descr = {
        .offs = 8,
        .len = 4,
        .veroffs = 12,
-       .maxblocks = 4,
+       .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
        .pattern = mirror_pattern
 };
 
-static struct nand_bbt_descr bbt_main_no_bbt_descr = {
+static struct nand_bbt_descr bbt_main_no_oob_descr = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
                | NAND_BBT_NO_OOB,
        .len = 4,
        .veroffs = 4,
-       .maxblocks = 4,
+       .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
        .pattern = bbt_pattern
 };
 
-static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
+static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
                | NAND_BBT_NO_OOB,
        .len = 4,
        .veroffs = 4,
-       .maxblocks = 4,
+       .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
        .pattern = mirror_pattern
 };
 
-#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \
-               NAND_BBT_SCANBYTE1AND6)
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
 /**
- * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure
- * @this:      NAND chip to create descriptor for
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
+ * @this: NAND chip to create descriptor for
  *
  * This function allocates and initializes a nand_bbt_descr for BBM detection
- * based on the properties of "this". The new descriptor is stored in
+ * based on the properties of @this. The new descriptor is stored in
  * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
  * passed to this function.
- *
  */
-static int nand_create_default_bbt_descr(struct nand_chip *this)
+static int nand_create_badblock_pattern(struct nand_chip *this)
 {
        struct nand_bbt_descr *bd;
        if (this->badblock_pattern) {
-               printk(KERN_WARNING "BBT descr already allocated; not replacing.\n");
+               pr_warn("Bad block pattern already allocated; not replacing\n");
                return -EINVAL;
        }
        bd = kzalloc(sizeof(*bd), GFP_KERNEL);
-       if (!bd) {
-               printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n");
+       if (!bd)
                return -ENOMEM;
-       }
-       bd->options = this->options & BBT_SCAN_OPTIONS;
+       bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
        bd->offs = this->badblockpos;
        bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
        bd->pattern = scan_ff_pattern;
@@ -1365,22 +1318,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this)
 
 /**
  * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
- * @mtd:       MTD device structure
- *
- * This function selects the default bad block table
- * support for the device and calls the nand_scan_bbt function
+ * @mtd: MTD device structure
  *
-*/
+ * This function selects the default bad block table support for the device and
+ * calls the nand_scan_bbt function.
+ */
 int nand_default_bbt(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
 
-       /* Default for AG-AND. We must use a flash based
-        * bad block table as the devices have factory marked
-        * _good_ blocks. Erasing those blocks leads to loss
-        * of the good / bad information, so we _must_ store
-        * this information in a good / bad table during
-        * startup
+       /*
+        * Default for AG-AND. We must use a flash based bad block table as the
+        * devices have factory marked _good_ blocks. Erasing those blocks
+        * leads to loss of the good / bad information, so we _must_ store this
+        * information in a good / bad table during startup.
         */
        if (this->options & NAND_IS_AND) {
                /* Use the default pattern descriptors */
@@ -1388,17 +1339,17 @@ int nand_default_bbt(struct mtd_info *mtd)
                        this->bbt_td = &bbt_main_descr;
                        this->bbt_md = &bbt_mirror_descr;
                }
-               this->options |= NAND_USE_FLASH_BBT;
+               this->bbt_options |= NAND_BBT_USE_FLASH;
                return nand_scan_bbt(mtd, &agand_flashbased);
        }
 
-       /* Is a flash based bad block table requested ? */
-       if (this->options & NAND_USE_FLASH_BBT) {
+       /* Is a flash based bad block table requested? */
+       if (this->bbt_options & NAND_BBT_USE_FLASH) {
                /* Use the default pattern descriptors */
                if (!this->bbt_td) {
-                       if (this->options & NAND_USE_FLASH_BBT_NO_OOB) {
-                               this->bbt_td = &bbt_main_no_bbt_descr;
-                               this->bbt_md = &bbt_mirror_no_bbt_descr;
+                       if (this->bbt_options & NAND_BBT_NO_OOB) {
+                               this->bbt_td = &bbt_main_no_oob_descr;
+                               this->bbt_md = &bbt_mirror_no_oob_descr;
                        } else {
                                this->bbt_td = &bbt_main_descr;
                                this->bbt_md = &bbt_mirror_descr;
@@ -1410,18 +1361,17 @@ int nand_default_bbt(struct mtd_info *mtd)
        }
 
        if (!this->badblock_pattern)
-               nand_create_default_bbt_descr(this);
+               nand_create_badblock_pattern(this);
 
        return nand_scan_bbt(mtd, this->badblock_pattern);
 }
 
 /**
  * nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd:       MTD device structure
- * @offs:      offset in the device
- * @allowbbt:  allow access to bad block table region
- *
-*/
+ * @mtd: MTD device structure
+ * @offs: offset in the device
+ * @allowbbt: allow access to bad block table region
+ */
 int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 {
        struct nand_chip *this = mtd->priv;
index 39535497f8dfede06d6ca0e7ee009178fc7b8569..f856778b5e1a3209dbd962c7fc88aececb32b9bc 100644 (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
         * 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)
 
-       /*512 Megabit */
+       /* 512 Megabit */
        {"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 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",       0xF0, 0,  64, 0, LP_OPTIONS},
        {"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 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
         */
        {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000,
-        NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
-        BBT_AUTO_REFRESH
-       },
+        NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
 
        {NULL,}
 };
@@ -176,6 +175,9 @@ const struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_STMICRO, "ST Micro"},
        {NAND_MFR_HYNIX, "Hynix"},
        {NAND_MFR_MICRON, "Micron"},
-       {NAND_MFR_AMD, "AMD"},
+       {NAND_MFR_AMD, "AMD/Spansion"},
+       {NAND_MFR_MACRONIX, "Macronix"},
+       {NAND_MFR_EON, "Eon"},
        {0x0, "Unknown"}
 };
+
index fe8bdeb0ea32c4f4c0c9cd51fb5e54e1073c1ba1..d81972ca27baa9f851af9aa872da262386f31d2c 100644 (file)
@@ -121,7 +121,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
                WATCHDOG_RESET();
 
                if (!opts->scrub && bbtest) {
-                       int ret = meminfo->block_isbad(meminfo, erase.addr);
+                       int ret = mtd_block_isbad(meminfo, erase.addr);
                        if (ret > 0) {
                                if (!opts->quiet)
                                        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++;
 
-               result = meminfo->erase(meminfo, &erase);
+               result = mtd_erase(meminfo, &erase);
                if (result != 0) {
                        printf("\n%s: MTD Erase failure: %d\n",
                               mtd_device, result);
@@ -153,15 +153,16 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 
                /* format for JFFS2 ? */
                if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
-                       chip->ops.ooblen = 8;
-                       chip->ops.datbuf = NULL;
-                       chip->ops.oobbuf = (uint8_t *)&cleanmarker;
-                       chip->ops.ooboffs = 0;
-                       chip->ops.mode = MTD_OOB_AUTO;
+                       struct mtd_oob_ops ops;
+                       ops.ooblen = 8;
+                       ops.datbuf = NULL;
+                       ops.oobbuf = (uint8_t *)&cleanmarker;
+                       ops.ooboffs = 0;
+                       ops.mode = MTD_OPS_AUTO_OOB;
 
-                       result = meminfo->write_oob(meminfo,
+                       result = mtd_write_oob(meminfo,
                                                    erase.addr,
-                                                   &chip->ops);
+                                                   &ops);
                        if (result != 0) {
                                printf("\n%s: MTD writeoob failure: %d\n",
                                       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.ooblen = nand->oobsize;
-                       ops.mode = MTD_OOB_AUTO;
+                       ops.mode = MTD_OPS_AUTO_OOB;
                        ops.ooboffs = 0;
 
                        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.oobbuf = ops.datbuf + pagesize;
 
-                               rval = nand->write_oob(nand, offset, &ops);
+                               rval = mtd_write_oob(nand, offset, &ops);
                                if (rval != 0)
                                        break;
 
index 213d2c945a9a878d8bcd15ec5f16c219d240ba3d..94b90332d622acb518d3006857ca6e9ecba99dd7 100644 (file)
@@ -216,6 +216,7 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.mode = NAND_ECC_HW;
        nand->ecc.size = 256;
        nand->ecc.bytes = 3;
+       nand->ecc.strength = 1;
        nand->select_chip = ndfc_select_chip;
 
 #ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
index b76f4cbb5e6d43ab4217ddbdc15e6b735c7893f4..dc8e5137397d6035a024433b9a9c9e76e2d60737 100644 (file)
@@ -212,6 +212,7 @@ int board_nand_init(struct nand_chip *chip)
        chip->ecc.mode = NAND_ECC_HW;
        chip->ecc.bytes = 3;
        chip->ecc.size = 512;
+       chip->ecc.strength = 1;
        chip->ecc.layout = &nomadik_ecc_layout;
        chip->ecc.calculate = nomadik_ecc_calculate;
        chip->ecc.hwctl = nomadik_ecc_hwctl;
index bc1bcad3bad6d66576167dfb26add5651f959c7c..d5f3248157733dae95465b0ea8071b47a37135a5 100644 (file)
@@ -590,11 +590,12 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
+ * @oob_required: caller expects OOB data read to chip->oob_poi
  * @page:      page number to read
  *
  */
 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 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.correct = NULL;
        nand->ecc.calculate = NULL;
+       nand->ecc.strength = eccstrength;
 
        /* Setup the ecc configurations again */
        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->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 ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
                nand->options |= NAND_BUSWIDTH_16;
index e1a459b009a283d0b287d2131b77753f88725831..43d8213e04a10b7c4add28d1d951fc013cf75ac2 100644 (file)
@@ -173,6 +173,7 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.mode = NAND_ECC_HW;
        nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
        nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
+       nand->ecc.strength = 1;
 #else
        nand->ecc.mode = NAND_ECC_SOFT;
 #endif
index 4d94cc6f562819c98b0ca3801f31d5a39cdd6cb1..6afbec61ee2c506904e11421b1ce9176ed9a168f 100644 (file)
@@ -707,7 +707,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
  *             -EIO when command timeout
  */
 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);
 }
@@ -719,8 +719,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd,
  * @param chip nand chip info structure
  * @param buf  data buffer
  */
-static void nand_write_page_hwecc(struct mtd_info *mtd,
-       struct nand_chip *chip, const uint8_t *buf)
+static int nand_write_page_hwecc(struct mtd_info *mtd,
+       struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        int page;
        struct nand_drv *info;
@@ -731,6 +731,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,
                (readl(&info->reg->addr_reg2) << 16);
 
        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
  */
 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);
 }
@@ -758,8 +759,8 @@ static int nand_read_page_raw(struct mtd_info *mtd,
  * @param chip nand chip info structure
  * @param buf  data buffer
  */
-static void nand_write_page_raw(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf)
+static int nand_write_page_raw(struct mtd_info *mtd,
+               struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        int page;
        struct nand_drv *info;
@@ -769,6 +770,7 @@ static void nand_write_page_raw(struct mtd_info *mtd,
                (readl(&info->reg->addr_reg2) << 16);
 
        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 chip         nand chip info structure
  * @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,
-       int page, int sndcmd)
+       int page)
 {
-       if (sndcmd) {
-               chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
-               sndcmd = 0;
-       }
+       chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
        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.read_oob = nand_read_oob;
        nand->ecc.write_oob = nand_write_oob;
+       nand->ecc.strength = 1;
        nand->select_chip = nand_select_chip;
        nand->dev_ready  = nand_dev_ready;
        nand->priv = &nand_ctrl;
index 7e74be75f8195aaeeb4895db4bca6e0bf47b5403..622b8698083a067f60aaa3efd35d337213ecb09d 100644 (file)
@@ -224,7 +224,7 @@ enum {
 #define BCH_DEC_STATUS_MAX_CORR_CNT_MASK       (0x1f << 8)
 #define BCH_DEC_STATUS_PAGE_NUMBER_MASK                0xFF
 
-#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR)
+#define LP_OPTIONS     0
 
 struct nand_ctlr {
        u32     command;        /* offset 00h */
index 858e322743b5f6e08677a0488d204024b5cd3e7a..ddfe7e7c756dbff2cb385d88e5bbc27b0a496369 100644 (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 buf          destination address
  * @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;
 
        /* 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;
 
        /* 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);
 
-       if (ops->mode == MTD_OOB_AUTO)
+       if (ops->mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                oobsize = mtd->oobsize;
@@ -914,7 +914,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        thisooblen = oobsize - oobcolumn;
                        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);
                        else
                                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))
                                ret = onenand_recover_lsb(mtd, from, ret);
                        onenand_update_bufferram(mtd, from, !ret);
-                       if (ret == -EBADMSG)
+                       if (mtd_is_eccerr(ret))
                                ret = 0;
                }
 
@@ -950,7 +950,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        /* Now wait for load */
                        ret = this->wait(mtd, FL_READING);
                        onenand_update_bufferram(mtd, from, !ret);
-                       if (ret == -EBADMSG)
+                       if (mtd_is_eccerr(ret))
                                ret = 0;
                }
        }
@@ -987,7 +987,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
        struct mtd_ecc_stats stats;
        int read = 0, thislen, column, oobsize;
        size_t len = ops->ooblen;
-       mtd_oob_mode_t mode = ops->mode;
+       unsigned int mode = ops->mode;
        u_char *buf = ops->oobbuf;
        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 */
        ops->oobretlen = 0;
 
-       if (mode == MTD_OOB_AUTO)
+       if (mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                oobsize = mtd->oobsize;
@@ -1041,7 +1041,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                        break;
                }
 
-               if (mode == MTD_OOB_AUTO)
+               if (mode == MTD_OPS_AUTO_OOB)
                        onenand_transfer_auto_oob(mtd, buf, column, thislen);
                else
                        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;
 
        switch (ops->mode) {
-       case MTD_OOB_PLACE:
-       case MTD_OOB_AUTO:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_AUTO_OOB:
                break;
-       case MTD_OOB_RAW:
+       case MTD_OPS_RAW:
                /* Not implemented yet */
        default:
                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)
 
 /**
- * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
  * @param mtd           MTD device structure
  * @param oob_buf       oob buffer
  * @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->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 */
        if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
                printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
                return -EINVAL;
        }
 
-       if (ops->mode == MTD_OOB_AUTO)
+       if (ops->mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                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
                         *                          * to prevent byte access */
                        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);
                        else
                                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 to            offset to write to
  * @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;
        size_t len = ops->ooblen;
        const u_char *buf = ops->oobbuf;
-       mtd_oob_mode_t mode = ops->mode;
+       unsigned int mode = ops->mode;
 
        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 */
        ops->oobretlen = 0;
 
-       if (mode == MTD_OOB_AUTO)
+       if (mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                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
                 * to prevent byte access */
                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);
                else
                        memcpy(oobbuf + column, buf, thislen);
@@ -1661,10 +1655,10 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to,
        int ret;
 
        switch (ops->mode) {
-       case MTD_OOB_PLACE:
-       case MTD_OOB_AUTO:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_AUTO_OOB:
                break;
-       case MTD_OOB_RAW:
+       case MTD_OPS_RAW:
                /* Not implemented yet */
        default:
                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",
                        (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)) {
                /* Find the eraseregion of this address */
                i = flexonenand_region(mtd, addr);
@@ -1762,8 +1749,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                return -EINVAL;
        }
 
-       instr->fail_addr = 0xffffffff;
-
        /* Grab the lock and see if the device is available */
        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;
        u_char buf[2] = {0, 0};
        struct mtd_oob_ops ops = {
-               .mode = MTD_OOB_PLACE,
+               .mode = MTD_OPS_PLACE_OOB,
                .ooblen = 2,
                .oobbuf = buf,
                .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)
 {
-       struct onenand_chip *this = mtd->priv;
        int ret;
 
        ret = onenand_block_isbad(mtd, ofs);
@@ -1926,7 +1910,7 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
-       ret = this->block_markbad(mtd, ofs);
+       ret = mtd_block_markbad(mtd, ofs);
        return ret;
 }
 
@@ -2386,7 +2370,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
        int i, ret;
        int block;
        struct mtd_oob_ops ops = {
-               .mode = MTD_OOB_PLACE,
+               .mode = MTD_OPS_PLACE_OOB,
                .ooboffs = 0,
                .ooblen = mtd->oobsize,
                .datbuf = NULL,
@@ -2645,14 +2629,14 @@ int onenand_probe(struct mtd_info *mtd)
                mtd->size = this->chipsize;
 
        mtd->flags = MTD_CAP_NANDFLASH;
-       mtd->erase = onenand_erase;
-       mtd->read = onenand_read;
-       mtd->write = onenand_write;
-       mtd->read_oob = onenand_read_oob;
-       mtd->write_oob = onenand_write_oob;
-       mtd->sync = onenand_sync;
-       mtd->block_isbad = onenand_block_isbad;
-       mtd->block_markbad = onenand_block_markbad;
+       mtd->_erase = onenand_erase;
+       mtd->_read = onenand_read;
+       mtd->_write = onenand_write;
+       mtd->_read_oob = onenand_read_oob;
+       mtd->_write_oob = onenand_write_oob;
+       mtd->_sync = onenand_sync;
+       mtd->_block_isbad = onenand_block_isbad;
+       mtd->_block_markbad = onenand_block_markbad;
 
        return 0;
 }
index 9d5da54708ec9ed9db9c83eff0b9939adb6d90bd..0267c2c5c90a8b7f8b0bba69422638e625c22c0c 100644 (file)
@@ -87,7 +87,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
        startblock = 0;
        from = 0;
 
-       ops.mode = MTD_OOB_PLACE;
+       ops.mode = MTD_OPS_PLACE_OOB;
        ops.ooblen = readlen;
        ops.oobbuf = buf;
        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);
        /* Allocate memory (2bit per block) */
        bbm->bbt = malloc(len);
-       if (!bbm->bbt) {
-               printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
+       if (!bbm->bbt)
                return -ENOMEM;
-       }
        /* Clear the memory bad block table */
        memset(bbm->bbt, 0x00, len);
 
index a708162e43a826846584cf1440a0d783bbd4a53a..25888220df287e99a673a6a95c97de5af76c8b4b 100644 (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->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->min_io_size = ubi->mtd->writesize;
index d523c94b129df74a30ae32744847540320c83362..d2d3c9c5805d1b21fb5a3c79b183968572ee22e5 100644 (file)
@@ -460,7 +460,7 @@ retry:
                if (err == UBI_IO_BITFLIPS) {
                        scrub = 1;
                        err = 0;
-               } else if (err == -EBADMSG) {
+               } else if (mtd_is_eccerr(err)) {
                        if (vol->vol_type == UBI_DYNAMIC_VOLUME)
                                goto out_unlock;
                        scrub = 1;
index 8423894000bcc41597c47c80992bbe7134164fec..05de9aeb6eea6c25b7001a5b6c783383edf1ca7f 100644 (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;
 retry:
-       err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+       err = mtd_read(ubi->mtd, addr, len, &read, buf);
        if (err) {
                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;
-       err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
+       err = mtd_write(ubi->mtd, addr, len, &written, buf);
        if (err) {
                ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
                        " %zd bytes", err, len, pnum, offset, written);
@@ -318,7 +318,7 @@ retry:
        ei.callback = erase_callback;
        ei.priv     = (unsigned long)&wq;
 
-       err = ubi->mtd->erase(ubi->mtd, &ei);
+       err = mtd_erase(ubi->mtd, &ei);
        if (err) {
                if (retries++ < UBI_IO_RETRIES) {
                        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) {
                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)
                        ubi_err("error %d while checking if PEB %d is bad",
                                ret, pnum);
@@ -551,7 +551,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
        if (!ubi->bad_allowed)
                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)
                ubi_err("cannot mark PEB %d bad, error %d", pnum, 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;
 
        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) {
                ubi_err("error %d while reading %d bytes from PEB %d:%d, "
                        "read %zd bytes", err, len, pnum, offset, read);
index 423d479152f367fdb25d7fec024fe23421d1dd53..e553188797cd8a41a924cf05484b32fd060e734a 100644 (file)
@@ -349,7 +349,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
                return 0;
 
        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);
                vol->corrupted = 1;
        }
index a6410bfb6bce4f82211cbdd8ee54401dadedbc77..e8660d997037e995bd5cfa9a4f14b4d3b6f4b5d3 100644 (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);
                if (err) {
-                       if (err == -EBADMSG)
+                       if (mtd_is_eccerr(err))
                                err = 1;
                        break;
                }
index f679f06494b6c79f355976826695693aead1efd0..29d23200104a26e0a4ea552750e0890e6e2fe03d 100644 (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,
                                       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
                         * uncorrectable ECC error, but we have our own CRC and
index db49052b385ea0d9c46de954fc3d648869f3f526..6fcba047f968cc7b249cb6ada5eca1c89133696b 100644 (file)
@@ -70,22 +70,22 @@ int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
        u8 spareAsBytes[8]; /* OOB */
 
        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);
        else if (spare) {
                if (dev->param.use_nand_ecc) {
                        translate_spare2oob(spare, spareAsBytes);
-                       ops.mode = MTD_OOB_AUTO;
+                       ops.mode = MTD_OPS_AUTO_OOB;
                        ops.ooblen = 8; /* temp hack */
                } else {
-                       ops.mode = MTD_OOB_RAW;
+                       ops.mode = MTD_OPS_RAW;
                        ops.ooblen = YAFFS_BYTES_PER_SPARE;
                }
                ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
                ops.datbuf = (u8 *)data;
                ops.ooboffs = 0;
                ops.oobbuf = spareAsBytes;
-               retval = mtd->write_oob(mtd, addr, &ops);
+               retval = mtd_write_oob(mtd, addr, &ops);
        }
 
        if (retval == 0)
@@ -106,21 +106,21 @@ int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
        u8 spareAsBytes[8]; /* OOB */
 
        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);
        else if (spare) {
                if (dev->param.use_nand_ecc) {
-                       ops.mode = MTD_OOB_AUTO;
+                       ops.mode = MTD_OPS_AUTO_OOB;
                        ops.ooblen = 8; /* temp hack */
                } else {
-                       ops.mode = MTD_OOB_RAW;
+                       ops.mode = MTD_OPS_RAW;
                        ops.ooblen = YAFFS_BYTES_PER_SPARE;
                }
                ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
                ops.datbuf = data;
                ops.ooboffs = 0;
                ops.oobbuf = spareAsBytes;
-               retval = mtd->read_oob(mtd, addr, &ops);
+               retval = mtd_read_oob(mtd, addr, &ops);
                if (dev->param.use_nand_ecc)
                        translate_oob2spare(spare, spareAsBytes);
        }
@@ -151,7 +151,7 @@ int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
        /* Todo finish off the ei if required */
 
 
-       retval = mtd->erase(mtd, &ei);
+       retval = mtd_erase(mtd, &ei);
 
        if (retval == 0)
                return YAFFS_OK;
index 8135bcc0fe1152a20dd8aa55e08d7154a12e5621..234cb706dfb413a1d213879e006c3ecad23b93ac 100644 (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);
        }
 
-       ops.mode = MTD_OOB_AUTO;
+       ops.mode = MTD_OPS_AUTO_OOB;
        ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
        ops.len = dev->param.total_bytes_per_chunk;
        ops.ooboffs = 0;
        ops.datbuf = (u8 *) data;
        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)
                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))
-               retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
+               retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
                                   &dummy, data);
        else if (tags) {
-               ops.mode = MTD_OOB_AUTO;
+               ops.mode = MTD_OPS_AUTO_OOB;
                ops.ooblen = packed_tags_size;
                ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
                ops.ooboffs = 0;
                ops.datbuf = data;
                ops.oobbuf = local_spare;
-               retval = mtd->read_oob(mtd, addr, &ops);
+               retval = mtd_read_oob(mtd, addr, &ops);
        }
 
        if (dev->param.inband_tags) {
@@ -179,7 +179,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
                "nandmtd2_MarkNANDBlockBad %d", blockNo);
 
        retval =
-           mtd->block_markbad(mtd,
+           mtd_block_markbad(mtd,
                               blockNo * dev->param.chunks_per_block *
                               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);
        retval =
-           mtd->block_isbad(mtd,
+           mtd_block_isbad(mtd,
                             blockNo * dev->param.chunks_per_block *
                             dev->data_bytes_per_chunk);
 
index 8b13b107e28091ebc1c6230fa8f1695dc44aa6b0..69412e461e8aa8d83a47fb1a1aea44a5dde3bccd 100644 (file)
 #define CONFIG_SYS_HUSH_PARSER
 
 /* Video */
-#define CONFIG_FSL_DIU_FB
 
 #ifdef CONFIG_FSL_DIU_FB
 #define CONFIG_SYS_DIU_ADDR    (CONFIG_SYS_CCSRBAR + 0x10000)
 #endif
 
 #ifndef CONFIG_FSL_DIU_FB
-#define CONFIG_ATI
 #endif
 
 #ifdef CONFIG_ATI
index 8cbcdae1143fa28ef406ce7dc795c8c0b6f8f7b8..71292b1a86bc91629acd1c61bf9e4d83e97a65a3 100644 (file)
@@ -81,32 +81,53 @@ struct nand_bbt_descr {
 #define NAND_BBT_LASTBLOCK     0x00000010
 /* The bbt is at the given page, else we must scan for the bbt */
 #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 */
 #define NAND_BBT_PERCHIP       0x00000080
 /* bbt has a version counter at offset veroffs */
 #define NAND_BBT_VERSION       0x00000100
 /* Create a bbt if none exists */
 #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 */
-#define NAND_BBT_SCANALLPAGES  0x00000400
+#define NAND_BBT_SCANALLPAGES  0x00000800
 /* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY     0x00000800
+#define NAND_BBT_SCANEMPTY     0x00001000
 /* Write bbt if neccecary */
-#define NAND_BBT_WRITE         0x00001000
+#define NAND_BBT_WRITE         0x00002000
 /* 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 */
-#define NAND_BBT_SCAN2NDPAGE   0x00004000
+#define NAND_BBT_SCAN2NDPAGE   0x00008000
 /* Search good / bad pattern on the last page of the eraseblock */
-#define NAND_BBT_SCANLASTPAGE  0x00008000
-/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */
-#define NAND_BBT_SCANBYTE1AND6 0x00100000
-/* The nand_bbt_descr was created dynamicaly and must be freed */
-#define NAND_BBT_DYNAMICSTRUCT 0x00200000
-/* The bad block table does not OOB for marker */
-#define NAND_BBT_NO_OOB                0x00400000
+#define NAND_BBT_SCANLASTPAGE  0x00010000
+/*
+ * Use a flash based bad block table. By default, OOB identifier is saved in
+ * OOB area. This option is passed to the default bad block table function.
+ */
+#define NAND_BBT_USE_FLASH     0x00020000
+/*
+ * 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 */
 #define NAND_BBT_SCAN_MAXBLOCKS        4
index 141c96024c57c5246f967f8e045c2a6abab6c3f9..6f44abdc16102d345e97845f17bc624e5c37eb44 100644 (file)
@@ -9,7 +9,8 @@
 
 #include <linux/types.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_BLOCK_MAJOR 31
@@ -65,22 +66,6 @@ struct mtd_erase_region_info {
        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
  * @mode:      operation mode
@@ -92,7 +77,7 @@ typedef enum {
  * @ooblen:    number of oob bytes to write/read
  * @oobretlen: number of oob bytes written/read
  * @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
  * @oobbuf:    oob data buffer
  *
@@ -101,7 +86,7 @@ typedef enum {
  * OOB area.
  */
 struct mtd_oob_ops {
-       mtd_oob_mode_t  mode;
+       unsigned int    mode;
        size_t          len;
        size_t          retlen;
        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 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. */
        const char *name;
        int index;
 
-       /* ecc layout structure pointer - read only ! */
+       /* ECC layout structure pointer - read only! */
        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,
         * it means that the whole device has erasesize as given above.
         */
@@ -147,25 +144,17 @@ struct mtd_info {
        struct mtd_erase_region_info *eraseregions;
 
        /*
-        * 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.
+        * Do not call via these pointers, use corresponding mtd_*()
+        * wrappers instead.
         */
-       int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
-
-       /* 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,
+       int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
+       int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, void **virt, phys_addr_t *phys);
-
-       /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
-       void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
-
-
-       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);
+       void (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
+       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
           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
           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);
-       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);
-
+       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
-        * flash devices. The user data is one time programmable but the
-        * factory data is read only.
+        * If the driver is something smart, like UBI, it may need to maintain
+        * its own reference counting. The below functions are only for driver.
         */
-       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 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);
+       int (*_get_device) (struct mtd_info *mtd);
+       void (*_put_device) (struct mtd_info *mtd);
 
 /* XXX U-BOOT XXX */
 #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);
 #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 */
 #if 0
        struct notifier_block reboot_notifier;  /* default mode before reboot */
@@ -227,15 +215,59 @@ struct mtd_info {
 
        struct module *owner;
        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)
 {
        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);
 }
 
+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 */
 
 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 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
 
 #ifdef CONFIG_MTD_PARTITIONS
@@ -296,17 +332,34 @@ static inline void mtd_erase_callback(struct erase_info *instr)
 #define MTD_DEBUG_LEVEL3       (3)     /* Noisy   */
 
 #ifdef CONFIG_MTD_DEBUG
+#define pr_debug(args...)      MTDDEBUG(MTD_DEBUG_LEVEL0, args)
 #define MTDDEBUG(n, args...)                           \
        do {                                            \
                if (n <= CONFIG_MTD_DEBUG_VERBOSE)      \
                        printk(KERN_INFO args);         \
        } while(0)
 #else /* CONFIG_MTD_DEBUG */
+#define pr_debug(args...)
 #define MTDDEBUG(n, args...)                           \
        do {                                            \
                if (0)                                  \
                        printk(KERN_INFO args);         \
        } while(0)
 #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__ */
index 98bf255bb28526f5703f55fd9615e1ab9c595144..2055584374d6277629ee3ec16b8c9a812af65483 100644 (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
  * adjust this accordingly.
  */
-#define NAND_MAX_OOBSIZE       576
+#define NAND_MAX_OOBSIZE       640
 #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_ERASE2                0xd0
 #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_LOCK          0x2a
@@ -142,7 +144,7 @@ typedef enum {
 #define NAND_ECC_READ          0
 /* Reset Hardware ECC for write */
 #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
 
 /* Bit mask for flags passed to do_nand_read_ecc */
@@ -153,9 +155,7 @@ typedef enum {
  * Option constants for bizarre disfunctionality and real
  * features.
  */
-/* Chip can not auto increment pages */
-#define NAND_NO_AUTOINCR       0x00000001
-/* Buswitdh is 16 bit */
+/* Buswidth is 16 bit */
 #define NAND_BUSWIDTH_16       0x00000002
 /* Device supports partial programming without padding */
 #define NAND_NO_PADDING                0x00000004
@@ -179,12 +179,6 @@ typedef enum {
  * This happens with the Renesas AG-AND chips, possibly others.
  */
 #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 */
 #define NAND_NO_SUBPAGE_WRITE  0x00000200
 
@@ -202,34 +196,21 @@ typedef enum {
        (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
 
 /* 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_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
 #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
 #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
 
 /* 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. */
-#define NAND_SKIP_BBTSCAN      0x00020000
+#define NAND_SKIP_BBTSCAN      0x00010000
 /*
  * This option is defined if the board driver allocates its own buffers
  * (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 */
-#define NAND_SCAN_SILENT_NODEV 0x00080000
-/*
- * 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
+#define NAND_SCAN_SILENT_NODEV 0x00040000
 
 /* Options set by nand scan */
 /* bbt has already been read */
@@ -244,6 +225,21 @@ typedef enum {
 /* Keep gcc happy */
 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 {
        /* rev info and features block */
        /* 'O' 'N' 'F' 'I'  */
@@ -326,27 +322,32 @@ struct nand_hw_control {
 };
 
 /**
- * struct nand_ecc_ctrl - Control structure for ecc
- * @mode:      ecc mode
- * @steps:     number of ecc steps per page
- * @size:      data bytes per ecc step
- * @bytes:     ecc bytes per step
- * @total:     total number of ecc bytes per page
- * @prepad:    padding information for syndrome based ecc generators
- * @postpad:   padding information for syndrome based ecc generators
+ * struct nand_ecc_ctrl - Control structure for ECC
+ * @mode:      ECC mode
+ * @steps:     number of ECC steps per page
+ * @size:      data bytes per ECC step
+ * @bytes:     ECC bytes per step
+ * @strength:  max number of correctible bits per ECC step
+ * @total:     total number of ECC bytes per page
+ * @prepad:    padding information for syndrome based ECC generators
+ * @postpad:   padding information for syndrome based ECC generators
  * @layout:    ECC layout control struct pointer
- * @priv:      pointer to private ecc control data
- * @hwctl:     function to control hardware ecc generator. Must only
+ * @priv:      pointer to private ECC control data
+ * @hwctl:     function to control hardware ECC generator. Must only
  *             be provided if an hardware ECC is available
- * @calculate: function for ecc calculation or readback from ecc hardware
- * @correct:   function for ecc correction, matching to ecc generator (sw/hw)
+ * @calculate: function for ECC calculation or readback from ECC hardware
+ * @correct:   function for ECC correction, matching to ECC generator (sw/hw)
  * @read_page_raw:     function to read 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
- *             requirements.
- * @read_subpage:      function to read parts of the page covered by ECC.
- * @write_page:        function to write a page according to the ecc generator
+ * @read_page: function to read a page according to the ECC generator
+ *             requirements; returns maximum number of bitflips corrected in
+ *             any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
+ * @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.
+ * @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
  * @write_oob: function to write chip OOB data
  */
@@ -356,6 +357,7 @@ struct nand_ecc_ctrl {
        int size;
        int bytes;
        int total;
+       int strength;
        int prepad;
        int postpad;
        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,
                        uint8_t *calc_ecc);
        int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint8_t *buf, int page);
-       void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf);
+                       uint8_t *buf, int oob_required, int page);
+       int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf, int oob_required);
        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,
                        uint32_t offs, uint32_t len, uint8_t *buf);
-       void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf);
-       int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
-                       int sndcmd);
+       int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf, int oob_required);
+       int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+                       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 page);
 };
 
 /**
  * struct nand_buffers - buffer structure for read/write
- * @ecccalc:   buffer for calculated ecc
- * @ecccode:   buffer for ecc read from flash
+ * @ecccalc:   buffer for calculated ECC
+ * @ecccode:   buffer for ECC read from flash
  * @databuf:   buffer for data - dynamically sized
  *
  * 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.
  *                     @id_data contains the 8 bytes values of NAND_CMD_READID.
  *                     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
  *                     ready/busy is available and the ready/busy information
  *                     is read from the chip status register.
@@ -426,17 +431,17 @@ struct nand_buffers {
  *                     commands to the chip.
  * @waitfunc:          [REPLACEABLE] hardwarespecific function for wait on
  *                     ready.
- * @ecc:               [BOARDSPECIFIC] ecc control ctructure
+ * @ecc:               [BOARDSPECIFIC] ECC control structure
  * @buffers:           buffer structure for read/write
  * @hwcontrol:         platform-specific hardware control structure
- * @ops:               oob operation operands
  * @erase_cmd:         [INTERN] erase command write function, selectable due
  *                     to AND support.
  * @scan_bbt:          [REPLACEABLE] function to scan bad block table
  * @chip_delay:                [BOARDSPECIFIC] chip dependent delay for transferring
  *                     data from array to read regs (tR).
  * @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
  *                     address bits).
  * @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
  *                     be set to inform nand_scan about special functionality.
  *                     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
  *                     area.
- * @badblockbits:      [INTERN] number of bits to left-shift the bad block
- *                     number
+ * @badblockbits:      [INTERN] minimum number of set bits in a good block's
+ *                     bad block marker position; i.e., BBM == 11110111b is
+ *                     not bad when badblockbits == 7
  * @cellinfo:          [INTERN] MLC/multichip data from chip ident
  * @numchips:          [INTERN] number of physical chips
  * @chipsize:          [INTERN] the size of one chip for multichip arrays
@@ -460,7 +469,9 @@ struct nand_buffers {
  *                     non 0 if ONFI supported.
  * @onfi_params:       [INTERN] holds the ONFI page parameter when ONFI is
  *                     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_td:            [REPLACEABLE] bad block table descriptor for flash
  *                     lookup.
@@ -468,9 +479,9 @@ struct nand_buffers {
  * @badblock_pattern:  [REPLACEABLE] bad block scan pattern used for initial
  *                     bad block scan.
  * @controller:                [REPLACEABLE] a pointer to a hardware controller
- *                     structure which is shared among multiple independend
+ *                     structure which is shared among multiple independent
  *                     devices.
- * @priv:              [OPTIONAL] pointer to private chip date
+ * @priv:              [OPTIONAL] pointer to private chip data
  * @errstat:           [OPTIONAL] hardware specific function to perform
  *                     additional error status checks (determine if errors are
  *                     correctable).
@@ -501,10 +512,16 @@ struct nand_chip {
        int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
                        int status, int page);
        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;
        unsigned int options;
+       unsigned int bbt_options;
 
        int page_shift;
        int phys_erase_shift;
@@ -534,8 +551,6 @@ struct nand_chip {
        struct nand_buffers *buffers;
        struct nand_hw_control hwcontrol;
 
-       struct mtd_oob_ops ops;
-
        uint8_t *bbt;
        struct nand_bbt_descr *bbt_td;
        struct nand_bbt_descr *bbt_md;
@@ -557,6 +572,8 @@ struct nand_chip {
 #define NAND_MFR_HYNIX         0xad
 #define NAND_MFR_MICRON                0x2c
 #define NAND_MFR_AMD           0x01
+#define NAND_MFR_MACRONIX      0xc2
+#define NAND_MFR_EON           0x92
 
 /**
  * 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
  * @chip_delay:                R/B delay value in us
  * @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
- * @priv:              hardware controller specific settings
  */
 struct platform_nand_chip {
        int nr_chips;
@@ -627,8 +644,8 @@ struct platform_nand_chip {
        struct nand_ecclayout *ecclayout;
        int chip_delay;
        unsigned int options;
+       unsigned int bbt_options;
        const char **part_probe_types;
-       void *priv;
 };
 
 /* Keep gcc happy */
@@ -650,6 +667,7 @@ struct platform_nand_ctrl {
        int (*dev_ready)(struct mtd_info *mtd);
        void (*select_chip)(struct mtd_info *mtd, int chip);
        void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
+       unsigned char (*read_byte)(struct mtd_info *mtd);
        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);
 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 */
index e9b134d1428f43786bce85d8f7dc4a6fc72d1907..8e44855712c33be990b02ff0db8f70f67110d08d 100644 (file)
@@ -85,6 +85,9 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
 #ifndef __HAVE_ARCH_MEMCHR
 extern void * memchr(const void *,int,__kernel_size_t);
 #endif
+#ifndef __HAVE_ARCH_MEMCHR_INV
+void *memchr_inv(const void *, int, size_t);
+#endif
 
 #ifdef __cplusplus
 }
similarity index 65%
rename from include/linux/mtd/mtd-abi.h
rename to include/mtd/mtd-abi.h
index 8bdd23112b4f2cfd5c40079e8301c7ba2ba0966e..d51c1abd186328d9f862aba4febeabcc8fdf4eb1 100644 (file)
@@ -24,6 +24,25 @@ struct mtd_oob_buf {
        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_RAM                        1
 #define MTD_ROM                        2
@@ -82,24 +101,42 @@ struct otp_info {
        uint32_t locked;
 };
 
+/* Get basic MTD characteristics info (better to use sysfs) */
 #define MEMGETINFO             _IOR('M', 1, struct mtd_info_user)
+/* Erase segment of MTD */
 #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)
+/* Read out-of-band data from MTD */
 #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)
+/* Unlock a chip (for MTD that supports it) */
 #define MEMUNLOCK              _IOW('M', 6, struct erase_info_user)
+/* Get the number of different erase regions */
 #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)
+/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
 #define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo)
 #define MEMGETOOBSEL           _IOR('M', 10, struct nand_oobinfo)
+/* Check if an eraseblock is bad */
 #define MEMGETBADBLOCK         _IOW('M', 11, loff_t)
+/* Mark an eraseblock as bad */
 #define MEMSETBADBLOCK         _IOW('M', 12, loff_t)
+/* Set OTP (One-Time Programmable) mode (factory vs. user) */
 #define OTPSELECT              _IOR('M', 13, int)
+/* Get number of OTP (One-Time Programmable) regions */
 #define OTPGETREGIONCOUNT      _IOW('M', 14, int)
+/* Get all OTP (One-Time Programmable) info about MTD */
 #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)
+/* Get ECC layout (deprecated) */
 #define ECCGETLAYOUT           _IOR('M', 17, struct nand_ecclayout)
+/* Get statistics about corrected/uncorrected errors */
 #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)
 
 /*
@@ -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 {
        MTD_MODE_NORMAL = MTD_OTP_OFF,
index 4f965235b6e035afc5fd1b53f4b1a93d3e454e02..26190e4137da9ac05c896506f909d230f5f4537d 100644 (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)
 {
-       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)
 {
-       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)
 {
-       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)
@@ -78,7 +78,7 @@ static inline int nand_erase(nand_info_t *info, loff_t off, size_t size)
        instr.len = size;
        instr.callback = 0;
 
-       return info->erase(info, &instr);
+       return mtd_erase(info, &instr);
 }
 
 
index 09dfae03c247554deb48c29ce98693ffd9c25f9d..3a82efab6194ce394ebc57e225a17062f7e17757 100644 (file)
@@ -617,3 +617,62 @@ void *memchr(const void *s, int c, size_t n)
 }
 
 #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
+