Fix OneNAND read_oob/write_oob functions compatability
authorKyungmin Park <kmpark@infradead.org>
Mon, 18 Aug 2008 23:42:53 +0000 (08:42 +0900)
committerScott Wood <scottwood@freescale.com>
Thu, 21 Aug 2008 18:50:20 +0000 (13:50 -0500)
Also sync with kernel OneNAND codes

Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
common/cmd_onenand.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_bbt.c
include/linux/mtd/bbm.h
include/linux/mtd/onenand.h
include/linux/mtd/onenand_regs.h
include/onenand_uboot.h

index 5e2062b5a2f1f8fd332e80611b7cdb5d8ee1a033..8d87b787f0facbfc0b646cf2f0c9bdb93c304b95 100644 (file)
@@ -85,15 +85,25 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
                        ulong addr = simple_strtoul(argv[2], NULL, 16);
                        ulong ofs = simple_strtoul(argv[3], NULL, 16);
                        size_t len = simple_strtoul(argv[4], NULL, 16);
-                       size_t retlen = 0;
                        int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
+                       struct mtd_oob_ops ops;
+
+                       ops.mode = MTD_OOB_PLACE;
+
+                       if (oob) {
+                               ops.len = 0;
+                               ops.datbuf = NULL;
+                               ops.ooblen = len;
+                               ops.oobbuf = (u_char *) addr;
+                       } else {
+                               ops.len = len;
+                               ops.datbuf = (u_char *) addr;
+                               ops.ooblen = 0;
+                               ops.oobbuf = NULL;
+                       }
+                       ops.retlen = ops.oobretlen = 0;
 
-                       if (oob)
-                               onenand_read_oob(&onenand_mtd, ofs, len,
-                                                &retlen, (u_char *) addr);
-                       else
-                               onenand_read(&onenand_mtd, ofs, len, &retlen,
-                                            (u_char *) addr);
+                       onenand_mtd.read_oob(&onenand_mtd, ofs, &ops);
                        printf("Done\n");
 
                        return 0;
@@ -117,9 +127,12 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
                        ulong block = simple_strtoul(argv[3], NULL, 10);
                        ulong page = simple_strtoul(argv[4], NULL, 10);
                        size_t len = simple_strtol(argv[5], NULL, 10);
-                       size_t retlen = 0;
                        ulong ofs;
                        int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
+                       struct mtd_oob_ops ops;
+
+                       ops.mode = MTD_OOB_PLACE;
+
 
                        ofs = block << onenand_chip.erase_shift;
                        if (page)
@@ -127,17 +140,21 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 
                        if (!len) {
                                if (oob)
-                                       len = 64;
+                                       ops.ooblen = 64;
                                else
-                                       len = 512;
+                                       ops.len = 512;
+                       }
+
+                       if (oob) {
+                               ops.datbuf = NULL;
+                               ops.oobbuf = (u_char *) addr;
+                       } else {
+                               ops.datbuf = (u_char *) addr;
+                               ops.oobbuf = NULL;
                        }
+                       ops.retlen = ops.oobretlen = 0;
 
-                       if (oob)
-                               onenand_read_oob(&onenand_mtd, ofs, len,
-                                                &retlen, (u_char *) addr);
-                       else
-                               onenand_read(&onenand_mtd, ofs, len, &retlen,
-                                            (u_char *) addr);
+                       onenand_read_oob(&onenand_mtd, ofs, &ops);
                        return 0;
                }
 
index 9ce68e1a47c90905763b3cad235f7135d416ab70..c22a8a8029652166f203327c64c7efaccc2bae17 100644 (file)
@@ -4,6 +4,11 @@
  *  Copyright (C) 2005-2007 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
  *
+ *  Credits:
+ *      Adrian Hunter <ext-adrian.hunter@nokia.com>:
+ *      auto-placement support, read-while load support, various fixes
+ *      Copyright (C) Nokia Corporation, 2007
+ *
  * 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
  * published by the Free Software Foundation.
@@ -526,83 +531,273 @@ static void onenand_release_device(struct mtd_info *mtd)
 }
 
 /**
- * onenand_read_ecc - [MTD Interface] Read data with ECC
+ * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd          MTD device structure
+ * @param buf          destination address
+ * @param column       oob offset to read from
+ * @param thislen      oob length to read
+ */
+static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
+                                       int column, int thislen)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct nand_oobfree *free;
+       int readcol = column;
+       int readend = column + thislen;
+       int lastgap = 0;
+       unsigned int i;
+       uint8_t *oob_buf = this->oob_buf;
+
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               if (readcol >= lastgap)
+                       readcol += free->offset - lastgap;
+               if (readend >= lastgap)
+                       readend += free->offset - lastgap;
+               lastgap = free->offset + free->length;
+       }
+       this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               int free_end = free->offset + free->length;
+               if (free->offset < readend && free_end > readcol) {
+                       int st = max_t(int,free->offset,readcol);
+                       int ed = min_t(int,free_end,readend);
+                       int n = ed - st;
+                       memcpy(buf, oob_buf + st, n);
+                       buf += n;
+               } else if (column == 0)
+                       break;
+       }
+       return 0;
+}
+
+/**
+ * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
  * @param mtd          MTD device structure
  * @param from         offset to read from
- * @param len          number of bytes to read
- * @param retlen       pointer to variable to store the number of read bytes
- * @param buf          the databuffer to put data
- * @param oob_buf      filesystem supplied oob data buffer
- * @param oobsel       oob selection structure
+ * @param ops          oob operation description structure
  *
- * OneNAND read with ECC
+ * OneNAND read main and/or out-of-band data
  */
-static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                           size_t * retlen, u_char * buf,
-                           u_char * oob_buf, struct nand_oobinfo *oobsel)
+static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
+               struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
-       int read = 0, column;
-       int thislen;
-       int ret = 0;
+       struct mtd_ecc_stats stats;
+       size_t len = ops->len;
+       size_t ooblen = ops->ooblen;
+       u_char *buf = ops->datbuf;
+       u_char *oobbuf = ops->oobbuf;
+       int read = 0, column, thislen;
+       int oobread = 0, oobcolumn, thisooblen, oobsize;
+       int ret = 0, boundary = 0;
+       int writesize = this->writesize;
+
+       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)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_read_ecc: "
-                 "from = 0x%08x, len = %i\n",
-                 (unsigned int)from, (int)len);
+       oobcolumn = from & (mtd->oobsize - 1);
 
        /* Do not allow reads past end of device */
        if ((from + len) > mtd->size) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_read_ecc: "
-                         "Attempt read beyond end of device\n");
-               *retlen = 0;
+               printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
+               ops->retlen = 0;
+               ops->oobretlen = 0;
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_READING);
+       stats = mtd->ecc_stats;
 
-       while (read < len) {
-               thislen = min_t(int, mtd->writesize, len - read);
-
-               column = from & (mtd->writesize - 1);
-               if (column + thislen > mtd->writesize)
-                       thislen = mtd->writesize - column;
+       /* Read-while-load method */
 
+       /* Do first load to bufferRAM */
+       if (read < len) {
                if (!onenand_check_bufferram(mtd, from)) {
-                       this->command(mtd, ONENAND_CMD_READ, from,
-                                     mtd->writesize);
+                       this->command(mtd, ONENAND_CMD_READ, from, writesize);
                        ret = this->wait(mtd, FL_READING);
-                       /* First copy data and check return value for ECC handling */
-                       onenand_update_bufferram(mtd, from, 1);
+                       onenand_update_bufferram(mtd, from, !ret);
+                       if (ret == -EBADMSG)
+                               ret = 0;
                }
+       }
 
-               this->read_bufferram(mtd, ONENAND_DATARAM, buf, column,
-                                    thislen);
+       thislen = min_t(int, writesize, len - read);
+       column = from & (writesize - 1);
+       if (column + thislen > writesize)
+               thislen = writesize - column;
 
-               read += thislen;
-               if (read == len)
-                       break;
+       while (!ret) {
+               /* If there is more to load then start next load */
+               from += thislen;
+               if (read + thislen < len) {
+                       this->command(mtd, ONENAND_CMD_READ, from, writesize);
+                       /*
+                        * Chip boundary handling in DDP
+                        * Now we issued chip 1 read and pointed chip 1
+                        * bufferam so we have to point chip 0 bufferam.
+                        */
+                       if (ONENAND_IS_DDP(this) &&
+                                       unlikely(from == (this->chipsize >> 1))) {
+                               this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
+                               boundary = 1;
+                       } else
+                               boundary = 0;
+                       ONENAND_SET_PREV_BUFFERRAM(this);
+               }
 
-               if (ret) {
-                       MTDDEBUG (MTD_DEBUG_LEVEL0,
-                                 "onenand_read_ecc: read failed = %d\n", ret);
-                       break;
+               /* While load is going, read from last bufferRAM */
+               this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+
+               /* Read oob area if needed */
+               if (oobbuf) {
+                       thisooblen = oobsize - oobcolumn;
+                       thisooblen = min_t(int, thisooblen, ooblen - oobread);
+
+                       if (ops->mode == MTD_OOB_AUTO)
+                               onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
+                       else
+                               this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
+                       oobread += thisooblen;
+                       oobbuf += thisooblen;
+                       oobcolumn = 0;
                }
 
-               from += thislen;
+               /* See if we are done */
+               read += thislen;
+               if (read == len)
+                       break;
+               /* Set up for next read from bufferRAM */
+               if (unlikely(boundary))
+                       this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
+               ONENAND_SET_NEXT_BUFFERRAM(this);
                buf += thislen;
-       }
+               thislen = min_t(int, writesize, len - read);
+               column = 0;
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
+               /* Now wait for load */
+               ret = this->wait(mtd, FL_READING);
+               onenand_update_bufferram(mtd, from, !ret);
+               if (ret == -EBADMSG)
+                       ret = 0;
+       }
 
        /*
         * Return success, if no ECC failures, else -EBADMSG
         * fs driver will take care of that, because
         * retlen == desired len and result == -EBADMSG
         */
-       *retlen = read;
-       return ret;
+       ops->retlen = read;
+       ops->oobretlen = oobread;
+
+       if (ret)
+               return ret;
+
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+}
+
+/**
+ * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param ops          oob operation description structure
+ *
+ * OneNAND read out-of-band data from the spare area
+ */
+static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
+               struct mtd_oob_ops *ops)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct mtd_ecc_stats stats;
+       int read = 0, thislen, column, oobsize;
+       size_t len = ops->ooblen;
+       mtd_oob_mode_t mode = ops->mode;
+       u_char *buf = ops->oobbuf;
+       int ret = 0;
+
+       from += ops->ooboffs;
+
+       MTDDEBUG(MTD_DEBUG_LEVEL3,
+               "onenand_read_oob_nolock: from = 0x%08x, len = %i\n",
+               (unsigned int) from, (int) len);
+
+       /* Initialize return length value */
+       ops->oobretlen = 0;
+
+       if (mode == MTD_OOB_AUTO)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
+
+       column = from & (mtd->oobsize - 1);
+
+       if (unlikely(column >= oobsize)) {
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
+               return -EINVAL;
+       }
+
+       /* Do not allow reads past end of device */
+       if (unlikely(from >= mtd->size ||
+               column + len > ((mtd->size >> this->page_shift) -
+                               (from >> this->page_shift)) * oobsize)) {
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
+               return -EINVAL;
+       }
+
+       stats = mtd->ecc_stats;
+
+       while (read < len) {
+               thislen = oobsize - column;
+               thislen = min_t(int, thislen, len);
+
+               this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+
+               onenand_update_bufferram(mtd, from, 0);
+
+               ret = this->wait(mtd, FL_READING);
+               if (ret && ret != -EBADMSG) {
+                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
+                       break;
+               }
+
+               if (mode == MTD_OOB_AUTO)
+                       onenand_transfer_auto_oob(mtd, buf, column, thislen);
+               else
+                       this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+
+               read += thislen;
+
+               if (read == len)
+                       break;
+
+               buf += thislen;
+
+               /* Read more? */
+               if (read < len) {
+                       /* Page size */
+                       from += mtd->writesize;
+                       column = 0;
+               }
+       }
+
+       ops->oobretlen = read;
+
+       if (ret)
+               return ret;
+
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return 0;
 }
 
 /**
@@ -618,38 +813,126 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                 size_t * retlen, u_char * buf)
 {
-       return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = buf,
+               .oobbuf = NULL,
+       };
+       int ret;
+
+       onenand_get_device(mtd, FL_READING);
+       ret = onenand_read_ops_nolock(mtd, from, &ops);
+       onenand_release_device(mtd);
+
+       *retlen = ops.retlen;
+       return ret;
 }
 
 /**
  * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
  * @param mtd          MTD device structure
  * @param from         offset to read from
- * @param len          number of bytes to read
- * @param retlen       pointer to variable to store the number of read bytes
- * @param buf          the databuffer to put data
+ * @param ops          oob operations description structure
  *
- * OneNAND read out-of-band data from the spare area
+ * OneNAND main and/or out-of-band
  */
-int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-                    size_t * retlen, u_char * buf)
+int onenand_read_oob(struct mtd_info *mtd, loff_t from,
+                       struct mtd_oob_ops *ops)
+{
+       int ret;
+
+       switch (ops->mode) {
+       case MTD_OOB_PLACE:
+       case MTD_OOB_AUTO:
+               break;
+       case MTD_OOB_RAW:
+               /* Not implemented yet */
+       default:
+               return -EINVAL;
+       }
+
+       onenand_get_device(mtd, FL_READING);
+       if (ops->datbuf)
+               ret = onenand_read_ops_nolock(mtd, from, ops);
+       else
+               ret = onenand_read_oob_nolock(mtd, from, ops);
+       onenand_release_device(mtd);
+
+       return ret;
+}
+
+/**
+ * onenand_bbt_wait - [DEFAULT] wait until the command is done
+ * @param mtd          MTD device structure
+ * @param state                state to select the max. timeout value
+ *
+ * Wait for command done.
+ */
+static int onenand_bbt_wait(struct mtd_info *mtd, int state)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned int flags = ONENAND_INT_MASTER;
+       unsigned int interrupt;
+       unsigned int ctrl;
+
+       while (1) {
+               interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+               if (interrupt & flags)
+                       break;
+       }
+
+       /* To get correct interrupt status in timeout case */
+       interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+       ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+       /* Initial bad block case: 0x2400 or 0x0400 */
+       if (ctrl & ONENAND_CTRL_ERROR) {
+               printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
+               return ONENAND_BBT_READ_ERROR;
+       }
+
+       if (interrupt & ONENAND_INT_READ) {
+               int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+               if (ecc & ONENAND_ECC_2BIT_ALL)
+                       return ONENAND_BBT_READ_ERROR;
+       } else {
+               printk(KERN_ERR "onenand_bbt_wait: read timeout!"
+                               "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+               return ONENAND_BBT_READ_FATAL_ERROR;
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param ops          oob operation description structure
+ *
+ * OneNAND read out-of-band data from the spare area for bbt scan
+ */
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+               struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
        int read = 0, thislen, column;
        int ret = 0;
+       size_t len = ops->ooblen;
+       u_char *buf = ops->oobbuf;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_read_oob: "
-                 "from = 0x%08x, len = %i\n",
-                 (unsigned int)from, (int)len);
+       MTDDEBUG(MTD_DEBUG_LEVEL3,
+               "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n",
+               (unsigned int) from, len);
 
-       /* Initialize return length value */
-       *retlen = 0;
+       /* Initialize return value */
+       ops->oobretlen = 0;
 
        /* Do not allow reads past end of device */
        if (unlikely((from + len) > mtd->size)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_read_oob: "
-                         "Attempt read beyond end of device\n");
-               return -EINVAL;
+               printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
+               return ONENAND_BBT_READ_FATAL_ERROR;
        }
 
        /* Grab the lock and see if the device is available */
@@ -658,6 +941,7 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
        column = from & (mtd->oobsize - 1);
 
        while (read < len) {
+
                thislen = mtd->oobsize - column;
                thislen = min_t(int, thislen, len);
 
@@ -665,27 +949,21 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
 
                onenand_update_bufferram(mtd, from, 0);
 
-               ret = this->wait(mtd, FL_READING);
-               /* First copy data and check return value for ECC handling */
-
-               this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column,
-                                    thislen);
+               ret = onenand_bbt_wait(mtd, FL_READING);
+               if (ret)
+                       break;
 
+               this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
                read += thislen;
                if (read == len)
                        break;
 
-               if (ret) {
-                       MTDDEBUG (MTD_DEBUG_LEVEL0,
-                                 "onenand_read_oob: read failed = %d\n", ret);
-                       break;
-               }
-
                buf += thislen;
+
                /* Read more? */
                if (read < len) {
-                       /* Page size */
-                       from += mtd->writesize;
+                       /* Update Page size */
+                       from += this->writesize;
                        column = 0;
                }
        }
@@ -693,224 +971,425 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
        /* Deselect and wake up anyone waiting on the device */
        onenand_release_device(mtd);
 
-       *retlen = read;
+       ops->oobretlen = read;
        return ret;
 }
 
+
 #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
 /**
- * onenand_verify_page - [GENERIC] verify the chip contents after a write
- * @param mtd          MTD device structure
- * @param buf          the databuffer to verify
- *
- * Check DataRAM area directly
+ * onenand_verify_oob - [GENERIC] verify the oob contents after a write
+ * @param mtd           MTD device structure
+ * @param buf           the databuffer to verify
+ * @param to            offset to read from
  */
-static int onenand_verify_page(struct mtd_info *mtd, u_char * buf,
-                              loff_t addr)
+static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
 {
        struct onenand_chip *this = mtd->priv;
-       void __iomem *dataram0, *dataram1;
+       u_char *oob_buf = this->oob_buf;
+       int status, i;
+
+       this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
+       onenand_update_bufferram(mtd, to, 0);
+       status = this->wait(mtd, FL_READING);
+       if (status)
+               return status;
+
+       this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
+       for (i = 0; i < mtd->oobsize; i++)
+               if (buf[i] != 0xFF && buf[i] != oob_buf[i])
+                       return -EBADMSG;
+
+       return 0;
+}
+
+/**
+ * onenand_verify - [GENERIC] verify the chip contents after a write
+ * @param mtd          MTD device structure
+ * @param buf          the databuffer to verify
+ * @param addr         offset to read from
+ * @param len          number of bytes to read and compare
+ */
+static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
+{
+       struct onenand_chip *this = mtd->priv;
+       void __iomem *dataram;
        int ret = 0;
+       int thislen, column;
 
-       this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
+       while (len != 0) {
+               thislen = min_t(int, this->writesize, len);
+               column = addr & (this->writesize - 1);
+               if (column + thislen > this->writesize)
+                       thislen = this->writesize - column;
 
-       ret = this->wait(mtd, FL_READING);
-       if (ret)
-               return ret;
+               this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
 
-       onenand_update_bufferram(mtd, addr, 1);
+               onenand_update_bufferram(mtd, addr, 0);
 
-       /* Check, if the two dataram areas are same */
-       dataram0 = this->base + ONENAND_DATARAM;
-       dataram1 = dataram0 + mtd->writesize;
+               ret = this->wait(mtd, FL_READING);
+               if (ret)
+                       return ret;
 
-       if (memcmp(dataram0, dataram1, mtd->writesize))
-               return -EBADMSG;
+               onenand_update_bufferram(mtd, addr, 1);
+
+               dataram = this->base + ONENAND_DATARAM;
+               dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
+
+               if (memcmp(buf, dataram + column, thislen))
+                       return -EBADMSG;
+
+               len -= thislen;
+               buf += thislen;
+               addr += thislen;
+       }
 
        return 0;
 }
 #else
-#define onenand_verify_page(...)       (0)
+#define onenand_verify(...)             (0)
+#define onenand_verify_oob(...)         (0)
 #endif
 
 #define NOTALIGNED(x)  ((x & (mtd->writesize - 1)) != 0)
 
 /**
- * onenand_write_ecc - [MTD Interface] OneNAND write with ECC
- * @param mtd          MTD device structure
- * @param to           offset to write to
- * @param len          number of bytes to write
- * @param retlen       pointer to variable to store the number of written bytes
- * @param buf          the data to write
- * @param eccbuf       filesystem supplied oob data buffer
- * @param oobsel       oob selection structure
+ * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd           MTD device structure
+ * @param oob_buf       oob buffer
+ * @param buf           source address
+ * @param column        oob offset to write to
+ * @param thislen       oob length to write
+ */
+static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
+               const u_char *buf, int column, int thislen)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct nand_oobfree *free;
+       int writecol = column;
+       int writeend = column + thislen;
+       int lastgap = 0;
+       unsigned int i;
+
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               if (writecol >= lastgap)
+                       writecol += free->offset - lastgap;
+               if (writeend >= lastgap)
+                       writeend += free->offset - lastgap;
+               lastgap = free->offset + free->length;
+       }
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               int free_end = free->offset + free->length;
+               if (free->offset < writeend && free_end > writecol) {
+                       int st = max_t(int,free->offset,writecol);
+                       int ed = min_t(int,free_end,writeend);
+                       int n = ed - st;
+                       memcpy(oob_buf + st, buf, n);
+                       buf += n;
+               } else if (column == 0)
+                       break;
+       }
+       return 0;
+}
+
+/**
+ * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
+ * @param mtd           MTD device structure
+ * @param to            offset to write to
+ * @param ops           oob operation description structure
  *
- * OneNAND write with ECC
+ * Write main and/or oob with ECC
  */
-static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-                            size_t * retlen, const u_char * buf,
-                            u_char * eccbuf, struct nand_oobinfo *oobsel)
+static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
+               struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
-       int written = 0;
+       int written = 0, column, thislen, subpage;
+       int oobwritten = 0, oobcolumn, thisooblen, oobsize;
+       size_t len = ops->len;
+       size_t ooblen = ops->ooblen;
+       const u_char *buf = ops->datbuf;
+       const u_char *oob = ops->oobbuf;
+       u_char *oobbuf;
        int ret = 0;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_write_ecc: "
-                 "to = 0x%08x, len = %i\n",
-                 (unsigned int)to, (int)len);
+       MTDDEBUG(MTD_DEBUG_LEVEL3,
+               "onenand_write_ops_nolock: to = 0x%08x, len = %i\n",
+               (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
-       *retlen = 0;
+       ops->retlen = 0;
+       ops->oobretlen = 0;
 
        /* Do not allow writes past end of device */
        if (unlikely((to + len) > mtd->size)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_ecc: "
-                         "Attempt write to past end of device\n");
+               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)) || unlikely(NOTALIGNED(len))) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_ecc: "
-                         "Attempt to write not page aligned data\n");
+       if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
+               printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
+       if (ops->mode == MTD_OOB_AUTO)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
+
+       oobcolumn = to & (mtd->oobsize - 1);
+
+       column = to & (mtd->writesize - 1);
 
        /* Loop until all data write */
        while (written < len) {
-               int thislen = min_t(int, mtd->writesize, len - written);
+               u_char *wbuf = (u_char *) buf;
 
-               this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize);
+               thislen = min_t(int, mtd->writesize - column, len - written);
+               thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
 
-               this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);
-               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0,
-                                     mtd->oobsize);
+               this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
 
-               this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
+               /* Partial page write */
+               subpage = thislen < mtd->writesize;
+               if (subpage) {
+                       memset(this->page_buf, 0xff, mtd->writesize);
+                       memcpy(this->page_buf + column, buf, thislen);
+                       wbuf = this->page_buf;
+               }
+
+               this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
+
+               if (oob) {
+                       oobbuf = this->oob_buf;
 
-               onenand_update_bufferram(mtd, to, 1);
+                       /* We send data to spare ram with oobsize
+                        *                          * to prevent byte access */
+                       memset(oobbuf, 0xff, mtd->oobsize);
+                       if (ops->mode == MTD_OOB_AUTO)
+                               onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
+                       else
+                               memcpy(oobbuf + oobcolumn, oob, thisooblen);
+
+                       oobwritten += thisooblen;
+                       oob += thisooblen;
+                       oobcolumn = 0;
+               } else
+                       oobbuf = (u_char *) ffchars;
+
+               this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
+
+               this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
 
                ret = this->wait(mtd, FL_WRITING);
+
+               /* In partial page write we don't update bufferram */
+               onenand_update_bufferram(mtd, to, !ret && !subpage);
+               if (ONENAND_IS_2PLANE(this)) {
+                       ONENAND_SET_BUFFERRAM1(this);
+                       onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
+               }
+
                if (ret) {
-                       MTDDEBUG (MTD_DEBUG_LEVEL0,
-                                 "onenand_write_ecc: write filaed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
                        break;
                }
 
-               written += thislen;
-
                /* Only check verify write turn on */
-               ret = onenand_verify_page(mtd, (u_char *) buf, to);
+               ret = onenand_verify(mtd, buf, to, thislen);
                if (ret) {
-                       MTDDEBUG (MTD_DEBUG_LEVEL0,
-                                 "onenand_write_ecc: verify failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
                        break;
                }
 
+               written += thislen;
+
                if (written == len)
                        break;
 
+               column = 0;
                to += thislen;
                buf += thislen;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
-       *retlen = written;
+       ops->retlen = written;
 
        return ret;
 }
 
 /**
- * onenand_write - [MTD Interface] compability function for onenand_write_ecc
- * @param mtd          MTD device structure
- * @param to           offset to write to
- * @param len          number of bytes to write
- * @param retlen       pointer to variable to store the number of written bytes
- * @param buf          the data to write
- *
- * This function simply calls onenand_write_ecc
- * with oob buffer and oobsel = NULL
- */
-int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
-                 size_t * retlen, const u_char * buf)
-{
-       return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);
-}
-
-/**
- * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
- * @param mtd          MTD device structure
- * @param to           offset to write to
- * @param len          number of bytes to write
- * @param retlen       pointer to variable to store the number of written bytes
- * @param buf          the data to write
+ * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
+ * @param mtd           MTD device structure
+ * @param to            offset to write to
+ * @param len           number of bytes to write
+ * @param retlen        pointer to variable to store the number of written bytes
+ * @param buf           the data to write
+ * @param mode          operation mode
  *
  * OneNAND write out-of-band
  */
-int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-                     size_t * retlen, const u_char * buf)
+static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
+               struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
-       int column, status;
+       int column, ret = 0, oobsize;
        int written = 0;
+       u_char *oobbuf;
+       size_t len = ops->ooblen;
+       const u_char *buf = ops->oobbuf;
+       mtd_oob_mode_t mode = ops->mode;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_write_oob: "
-                 "to = 0x%08x, len = %i\n",
-                 (unsigned int)to, (int)len);
+       to += ops->ooboffs;
+
+       MTDDEBUG(MTD_DEBUG_LEVEL3,
+               "onenand_write_oob_nolock: to = 0x%08x, len = %i\n",
+               (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
-       *retlen = 0;
+       ops->oobretlen = 0;
 
-       /* Do not allow writes past end of device */
-       if (unlikely((to + len) > mtd->size)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_oob: "
-                         "Attempt write to past end of device\n");
+       if (mode == MTD_OOB_AUTO)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
+
+       column = to & (mtd->oobsize - 1);
+
+       if (unlikely(column >= oobsize)) {
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
+       /* For compatibility with NAND: Do not allow write past end of page */
+       if (unlikely(column + len > oobsize)) {
+               printk(KERN_ERR "onenand_write_oob_nolock: "
+                               "Attempt to write past end of page\n");
+               return -EINVAL;
+       }
+
+       /* Do not allow reads past end of device */
+       if (unlikely(to >= mtd->size ||
+                               column + len > ((mtd->size >> this->page_shift) -
+                                       (to >> this->page_shift)) * oobsize)) {
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
+               return -EINVAL;
+       }
+
+       oobbuf = this->oob_buf;
 
        /* Loop until all data write */
        while (written < len) {
-               int thislen = min_t(int, mtd->oobsize, len - written);
-
-               column = to & (mtd->oobsize - 1);
+               int thislen = min_t(int, oobsize, len - written);
 
                this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
 
-               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0,
-                                     mtd->oobsize);
-               this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column,
-                                     thislen);
+               /* We send data to spare ram with oobsize
+                * to prevent byte access */
+               memset(oobbuf, 0xff, mtd->oobsize);
+               if (mode == MTD_OOB_AUTO)
+                       onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
+               else
+                       memcpy(oobbuf + column, buf, thislen);
+               this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
 
                this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
 
                onenand_update_bufferram(mtd, to, 0);
+               if (ONENAND_IS_2PLANE(this)) {
+                       ONENAND_SET_BUFFERRAM1(this);
+                       onenand_update_bufferram(mtd, to + this->writesize, 0);
+               }
 
-               status = this->wait(mtd, FL_WRITING);
-               if (status)
+               ret = this->wait(mtd, FL_WRITING);
+               if (ret) {
+                       printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
                        break;
+               }
+
+               ret = onenand_verify_oob(mtd, oobbuf, to);
+               if (ret) {
+                       printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
+                       break;
+               }
 
                written += thislen;
                if (written == len)
                        break;
 
-               to += thislen;
+               to += mtd->writesize;
                buf += thislen;
+               column = 0;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
+       ops->oobretlen = written;
+
+       return ret;
+}
+
+/**
+ * onenand_write - [MTD Interface] compability function for onenand_write_ecc
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param len          number of bytes to write
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param buf          the data to write
+ *
+ * Write with ECC
+ */
+int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+                 size_t * retlen, const u_char * buf)
+{
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = (u_char *) buf,
+               .oobbuf = NULL,
+       };
+       int ret;
+
+       onenand_get_device(mtd, FL_WRITING);
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
        onenand_release_device(mtd);
 
-       *retlen = written;
+       *retlen = ops.retlen;
+       return ret;
+}
+
+/**
+ * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param ops          oob operation description structure
+ *
+ * OneNAND write main and/or out-of-band
+ */
+int onenand_write_oob(struct mtd_info *mtd, loff_t to,
+                       struct mtd_oob_ops *ops)
+{
+       int ret;
+
+       switch (ops->mode) {
+       case MTD_OOB_PLACE:
+       case MTD_OOB_AUTO:
+               break;
+       case MTD_OOB_RAW:
+               /* Not implemented yet */
+       default:
+               return -EINVAL;
+       }
+
+       onenand_get_device(mtd, FL_WRITING);
+       if (ops->datbuf)
+               ret = onenand_write_ops_nolock(mtd, to, ops);
+       else
+               ret = onenand_write_oob_nolock(mtd, to, ops);
+       onenand_release_device(mtd);
+
+       return ret;
 
-       return 0;
 }
 
 /**
@@ -947,29 +1426,30 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
        int len;
        int ret = 0;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
-                 (unsigned int)instr->addr, (unsigned int)instr->len);
+       MTDDEBUG (MTD_DEBUG_LEVEL3,
+                "onenand_erase: start = 0x%08x, len = %i\n",
+                (unsigned int)instr->addr, (unsigned int)ins tr->len);
 
        block_size = (1 << this->erase_shift);
 
        /* Start address must align on block boundary */
        if (unlikely(instr->addr & (block_size - 1))) {
                MTDDEBUG (MTD_DEBUG_LEVEL0,
-                         "onenand_erase: Unaligned address\n");
+                        "onenand_erase: Unaligned address\n");
                return -EINVAL;
        }
 
        /* Length must align on block boundary */
        if (unlikely(instr->len & (block_size - 1))) {
                MTDDEBUG (MTD_DEBUG_LEVEL0,
-                         "onenand_erase: Length not block aligned\n");
+                        "onenand_erase: Length not block aligned\n");
                return -EINVAL;
        }
 
        /* Do not allow erase past end of device */
        if (unlikely((instr->len + instr->addr) > mtd->size)) {
                MTDDEBUG (MTD_DEBUG_LEVEL0,
-                         "onenand_erase: Erase past end of device\n");
+                        "onenand_erase: Erase past end of device\n");
                return -EINVAL;
        }
 
@@ -1277,6 +1757,8 @@ static int onenand_probe(struct mtd_info *mtd)
        this->page_shift = ffs(mtd->writesize) - 1;
        this->ppb_shift = (this->erase_shift - this->page_shift);
        this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
+       /* It's real page size */
+       this->writesize = mtd->writesize;
 
        /* REVIST: Multichip handling */
 
@@ -1346,6 +1828,28 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
                this->read_bufferram = onenand_sync_read_bufferram;
        }
 
+       /* Allocate buffers, if necessary */
+       if (!this->page_buf) {
+               this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
+               if (!this->page_buf) {
+                       printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
+                       return -ENOMEM;
+               }
+               this->options |= ONENAND_PAGEBUF_ALLOC;
+       }
+       if (!this->oob_buf) {
+               this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
+               if (!this->oob_buf) {
+                       printk(KERN_ERR "onenand_scan: Can't allocate oob_buf\n");
+                       if (this->options & ONENAND_PAGEBUF_ALLOC) {
+                               this->options &= ~ONENAND_PAGEBUF_ALLOC;
+                               kfree(this->page_buf);
+                       }
+                       return -ENOMEM;
+               }
+               this->options |= ONENAND_OOBBUF_ALLOC;
+       }
+
        onenand_unlock(mtd, 0, mtd->size);
 
        return onenand_default_bbt(mtd);
index d13d2777e200e5c2b58dd77ec4b3882dc5260eb5..dde11ae45f76b7a8a89701a141a0f6c0d279c22e 100644 (file)
@@ -68,6 +68,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
        int startblock;
        loff_t from;
        size_t readlen, ooblen;
+       struct mtd_oob_ops ops;
 
        printk(KERN_INFO "Scanning device for bad blocks\n");
 
@@ -85,25 +86,26 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
        startblock = 0;
        from = 0;
 
+       ops.mode = MTD_OOB_PLACE;
+       ops.ooblen = readlen;
+       ops.oobbuf = buf;
+       ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+
        for (i = startblock; i < numblocks;) {
                int ret;
 
                for (j = 0; j < len; j++) {
-                       size_t retlen;
-
                        /* No need to read pages fully,
                         * just read required OOB bytes */
-                       ret = onenand_read_oob(mtd,
+                       ret = onenand_bbt_read_oob(mtd,
                                             from + j * mtd->writesize +
-                                            bd->offs, readlen, &retlen,
-                                            &buf[0]);
+                                            bd->offs, &ops);
 
-                       if (ret && ret != -EAGAIN) {
-                               printk("ret = %d\n", ret);
-                               return ret;
-                       }
+                       /* If it is a initial bad block, just ignore it */
+                        if (ret == ONENAND_BBT_READ_FATAL_ERROR)
+                                return -EIO;
 
-                       if (check_short_pattern
+                       if (ret || check_short_pattern
                            (&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
                                bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
                                printk(KERN_WARNING
index bffb25b2575524d59dabe9c6f5193cd9b5a2762e..abf8f1a7e8680a9db5750a7b7ddb1480b972f058 100644 (file)
@@ -97,6 +97,13 @@ struct nand_bbt_descr {
  */
 #define ONENAND_BADBLOCK_POS   0
 
+/*
+ * Bad block scanning errors
+ */
+#define ONENAND_BBT_READ_ERROR          1
+#define ONENAND_BBT_READ_ECC_ERROR      2
+#define ONENAND_BBT_READ_FATAL_ERROR    4
+
 /**
  * struct bbt_info - [GENERIC] Bad Block Table data structure
  * @param bbt_erase_shift      [INTERN] number of address bits in a bbt entry
index 8a0fd0de97efb4b2a42c83fd5c0a7d06970e6f34..420eb140a3c7e2f2fdd67ec0f464ca2e082ae088 100644 (file)
@@ -75,6 +75,7 @@ struct onenand_chip {
        unsigned int page_shift;
        unsigned int ppb_shift; /* Pages per block shift */
        unsigned int page_mask;
+       unsigned int writesize;
 
        unsigned int bufferram_index;
        struct onenand_bufferram bufferram[MAX_BUFFERRAM];
@@ -93,25 +94,39 @@ struct onenand_chip {
        int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
        int (*scan_bbt)(struct mtd_info *mtd);
 
-       spinlock_t chip_lock;
-       wait_queue_head_t wq;
        int state;
+       unsigned char *page_buf;
+       unsigned char *oob_buf;
 
        struct nand_oobinfo *autooob;
+       struct nand_ecclayout *ecclayout;
 
        void *bbm;
 
        void *priv;
 };
 
+/*
+ * Helper macros
+ */
 #define ONENAND_CURRENT_BUFFERRAM(this)                (this->bufferram_index)
 #define ONENAND_NEXT_BUFFERRAM(this)           (this->bufferram_index ^ 1)
 #define ONENAND_SET_NEXT_BUFFERRAM(this)       (this->bufferram_index ^= 1)
+#define ONENAND_SET_PREV_BUFFERRAM(this)       (this->bufferram_index ^= 1)
+#define ONENAND_SET_BUFFERRAM0(this)           (this->bufferram_index = 0)
+#define ONENAND_SET_BUFFERRAM1(this)           (this->bufferram_index = 1)
+
+#define ONENAND_IS_DDP(this)                                           \
+       (this->device_id & ONENAND_DEVICE_IS_DDP)
+
+#define ONENAND_IS_2PLANE(this)                        (0)
 
 /*
  * Options bits
  */
 #define ONENAND_CONT_LOCK              (0x0001)
+#define ONENAND_PAGEBUF_ALLOC          (0x1000)
+#define ONENAND_OOBBUF_ALLOC           (0x2000)
 
 /*
  * OneNAND Flash Manufacturer ID Codes
@@ -129,4 +144,7 @@ struct onenand_manufacturers {
        char *name;
 };
 
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+                       struct mtd_oob_ops *ops);
+
 #endif                         /* __LINUX_MTD_ONENAND_H */
index c8a9f3e90446f80eae13d0f2f06be9dc8de657d6..6a8aa28b1b520c341a5bfa3b5134b6c10d0611a7 100644 (file)
@@ -83,6 +83,8 @@
  * Start Address 1 F100h (R/W)
  */
 #define ONENAND_DDP_SHIFT              (15)
+#define ONENAND_DDP_CHIP0              (0)
+#define ONENAND_DDP_CHIP1              (1 << ONENAND_DDP_SHIFT)
 
 /*
  * Start Address 8 F107h (R/W)
index 4260ee7eb442cac79d66f958401ae9ae775fa062..6605e4f218d2c99e3a38414dbd1093bd454efc6f 100644 (file)
 
 #include <linux/types.h>
 
-struct kvec {
-       void *iov_base;
-       size_t iov_len;
-};
-
-typedef int spinlock_t;
-typedef int wait_queue_head_t;
-
 struct mtd_info;
 struct erase_info;
 
+extern struct mtd_info onenand_mtd;
+
 /* Functions */
 extern void onenand_init(void);
 extern int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                        size_t * retlen, u_char * buf);
-extern int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-                           size_t * retlen, u_char * buf);
+extern int onenand_read_oob(struct mtd_info *mtd, loff_t from,
+                           struct mtd_oob_ops *ops);
 extern int onenand_write(struct mtd_info *mtd, loff_t from, size_t len,
                         size_t * retlen, const u_char * buf);
 extern int onenand_erase(struct mtd_info *mtd, struct erase_info *instr);