]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/mtd/onenand/onenand_base.c
[MTD] [OneNAND] Use pre-alloced oob buffer instead of local buffer
[net-next-2.6.git] / drivers / mtd / onenand / onenand_base.c
index 7d194cfdb873ce22a82e47572d7ddcbe40ef278a..b281b116aaeb55dab9c8c4e210cba43231392a17 100644 (file)
@@ -169,6 +169,18 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
        return ((bsa << ONENAND_BSA_SHIFT) | bsc);
 }
 
+/**
+ * onenand_get_density - [DEFAULT] Get OneNAND density
+ * @param dev_id       OneNAND device ID
+ *
+ * Get OneNAND density from device ID
+ */
+static inline int onenand_get_density(int dev_id)
+{
+       int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       return (density & ONENAND_DEVICE_DENSITY_MASK);
+}
+
 /**
  * onenand_command - [DEFAULT] Send command to OneNAND device
  * @param mtd          MTD device structure
@@ -182,8 +194,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
 static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
 {
        struct onenand_chip *this = mtd->priv;
-       int value, readcmd = 0, block_cmd = 0;
-       int block, page;
+       int value, block, page;
 
        /* Address translation */
        switch (cmd) {
@@ -198,7 +209,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
        case ONENAND_CMD_ERASE:
        case ONENAND_CMD_BUFFERRAM:
        case ONENAND_CMD_OTP_ACCESS:
-               block_cmd = 1;
                block = (int) (addr >> this->erase_shift);
                page = -1;
                break;
@@ -240,11 +250,9 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                value = onenand_block_address(this, block);
                this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
 
-               if (block_cmd) {
-                       /* Select DataRAM for DDP */
-                       value = onenand_bufferram_address(this, block);
-                       this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
-               }
+               /* Select DataRAM for DDP */
+               value = onenand_bufferram_address(this, block);
+               this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
        }
 
        if (page != -1) {
@@ -256,7 +264,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                case ONENAND_CMD_READ:
                case ONENAND_CMD_READOOB:
                        dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
-                       readcmd = 1;
                        break;
 
                default:
@@ -273,12 +280,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                /* Write 'BSA, BSC' of DataRAM */
                value = onenand_buffer_address(dataram, sectors, count);
                this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
-
-               if (readcmd) {
-                       /* Select DataRAM for DDP */
-                       value = onenand_bufferram_address(this, block);
-                       this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
-               }
        }
 
        /* Interrupt clear */
@@ -327,18 +328,20 @@ static int onenand_wait(struct mtd_info *mtd, int state)
                printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
                if (ctrl & ONENAND_CTRL_LOCK)
                        printk(KERN_ERR "onenand_wait: it's locked error.\n");
-               return ctrl;
+               return -EIO;
        }
 
        if (interrupt & ONENAND_INT_READ) {
                int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
                if (ecc) {
-                       printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
                        if (ecc & ONENAND_ECC_2BIT_ALL) {
+                               printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
                                mtd->ecc_stats.failed++;
-                               return ecc;
-                       } else if (ecc & ONENAND_ECC_1BIT_ALL)
+                               return -EBADMSG;
+                       } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+                               printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc);
                                mtd->ecc_stats.corrected++;
+                       }
                }
        } else if (state == FL_READING) {
                printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
@@ -357,7 +360,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
  */
 static irqreturn_t onenand_interrupt(int irq, void *data)
 {
-       struct onenand_chip *this = (struct onenand_chip *) data;
+       struct onenand_chip *this = data;
 
        /* To handle shared interrupt */
        if (!this->complete.done)
@@ -763,37 +766,86 @@ static void onenand_release_device(struct mtd_info *mtd)
 }
 
 /**
- * onenand_read - [MTD Interface] Read data from flash
+ * 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 ops:         oob operation description structure
  *
- * Read with ecc
-*/
-static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf)
+ * OneNAND read main and/or out-of-band data
+ */
+static int onenand_read_ops_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, column;
-       int thislen;
+       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;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+       DEBUG(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;
+
+       oobcolumn = from & (mtd->oobsize - 1);
 
        /* Do not allow reads past end of device */
        if ((from + len) > mtd->size) {
-               printk(KERN_ERR "onenand_read: 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;
 
        /* Read-while-load method */
@@ -804,6 +856,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                        this->command(mtd, ONENAND_CMD_READ, from, writesize);
                        ret = this->wait(mtd, FL_READING);
                        onenand_update_bufferram(mtd, from, !ret);
+                       if (ret == -EBADMSG)
+                               ret = 0;
                }
        }
 
@@ -832,6 +886,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                }
                /* 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;
+               }
+
                /* See if we are done */
                read += thislen;
                if (read == len)
@@ -847,91 +916,52 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                /* Now wait for load */
                ret = this->wait(mtd, FL_READING);
                onenand_update_bufferram(mtd, from, !ret);
+               if (ret == -EBADMSG)
+                       ret = 0;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
        /*
         * Return success, if no ECC failures, else -EBADMSG
         * fs driver will take care of that, because
         * retlen == desired len and result == -EBADMSG
         */
-       *retlen = read;
-
-       if (mtd->ecc_stats.failed - stats.failed)
-               return -EBADMSG;
+       ops->retlen = read;
+       ops->oobretlen = oobread;
 
        if (ret)
                return ret;
 
-       return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
-}
-
-/**
- * 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;
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
 
-       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;
+       return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
 /**
- * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
+ * onenand_read_oob_nolock - [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 mode         operation mode
+ * @param ops:         oob operation description structure
  *
  * OneNAND read out-of-band data from the spare area
  */
-static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
+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;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+       from += ops->ooboffs;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
        /* Initialize return length value */
-       *retlen = 0;
+       ops->oobretlen = 0;
 
        if (mode == MTD_OOB_AUTO)
                oobsize = this->ecclayout->oobavail;
@@ -941,7 +971,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
        column = from & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n");
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
                return -EINVAL;
        }
 
@@ -949,12 +979,11 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
        if (unlikely(from >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (from >> this->page_shift)) * oobsize)) {
-               printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n");
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
                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) {
                cond_resched();
@@ -967,18 +996,16 @@ static int onenand_do_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 */
+               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);
 
-               if (ret) {
-                       printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
-                       break;
-               }
-
                read += thislen;
 
                if (read == len)
@@ -994,22 +1021,59 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
                }
        }
 
-       /* Deselect and wake up anyone waiting on the device */
+       ops->oobretlen = read;
+
+       if (ret)
+               return ret;
+
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return 0;
+}
+
+/**
+ * onenand_read - [MTD Interface] Read data from flash
+ * @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
+ *
+ * Read with ecc
+*/
+static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+       size_t *retlen, u_char *buf)
+{
+       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 = read;
+       *retlen = ops.retlen;
        return ret;
 }
 
 /**
- * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
+ * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
  * @param mtd:         MTD device structure
  * @param from:                offset to read from
  * @param ops:         oob operation description structure
+
+ * Read main and/or out-of-band
  */
 static 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:
@@ -1019,8 +1083,15 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
        default:
                return -EINVAL;
        }
-       return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen,
-                                  &ops->oobretlen, ops->oobbuf, ops->mode);
+
+       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;
 }
 
 /**
@@ -1048,12 +1119,10 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
        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);
-               /* Initial bad block case */
-               if (ctrl & ONENAND_CTRL_LOAD)
-                       return ONENAND_BBT_READ_ERROR;
-               return ONENAND_BBT_READ_FATAL_ERROR;
+               return ONENAND_BBT_READ_ERROR;
        }
 
        if (interrupt & ONENAND_INT_READ) {
@@ -1144,12 +1213,11 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
  * @param mtd          MTD device structure
  * @param buf          the databuffer to verify
  * @param to           offset to read from
- *
  */
 static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
 {
        struct onenand_chip *this = mtd->priv;
-       char oobbuf[64];
+       u_char *oob_buf = this->oob_buf;
        int status, i;
 
        this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
@@ -1158,9 +1226,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
        if (status)
                return status;
 
-       this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
+       this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
        for (i = 0; i < mtd->oobsize; i++)
-               if (buf[i] != 0xFF && buf[i] != oobbuf[i])
+               if (buf[i] != 0xFF && buf[i] != oob_buf[i])
                        return -EBADMSG;
 
        return 0;
@@ -1172,7 +1240,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
  * @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)
 {
@@ -1218,50 +1285,101 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
 #define NOTALIGNED(x)  ((x & (this->subpagesize - 1)) != 0)
 
 /**
- * onenand_write - [MTD Interface] write buffer to FLASH
+ * 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 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 ops          oob operation description structure
  *
- * Write with ECC
+ * Write main and/or oob with ECC
  */
-static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
-       size_t *retlen, const u_char *buf)
+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;
-       int column, subpage;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+       DEBUG(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)) {
-               printk(KERN_ERR "onenand_write: 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))) {
-                printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
+                printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
                 return -EINVAL;
         }
 
-       column = to & (mtd->writesize - 1);
+       if (ops->mode == MTD_OOB_AUTO)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
+       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 - column, len - written);
                u_char *wbuf = (u_char *) buf;
 
+               thislen = min_t(int, mtd->writesize - column, len - written);
+               thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
+
                cond_resched();
 
                this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
@@ -1275,7 +1393,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
                }
 
                this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
-               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+               if (oob) {
+                       oobbuf = this->oob_buf;
+
+                       /* 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);
 
@@ -1289,14 +1425,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
                }
 
                if (ret) {
-                       printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
                        break;
                }
 
                /* Only check verify write turn on */
-               ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
+               ret = onenand_verify(mtd, buf, to, thislen);
                if (ret) {
-                       printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
                        break;
                }
 
@@ -1310,57 +1446,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
                buf += thislen;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
-       *retlen = written;
+       ops->retlen = written;
 
        return ret;
 }
 
-/**
- * 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_do_write_oob - [Internal] OneNAND write out-of-band
+ * 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
@@ -1370,18 +1463,23 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
  *
  * OneNAND write out-of-band
  */
-static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-                               size_t *retlen, const u_char *buf, mtd_oob_mode_t mode)
+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, 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;
+
+       to += ops->ooboffs;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+       DEBUG(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;
 
        if (mode == MTD_OOB_AUTO)
                oobsize = this->ecclayout->oobavail;
@@ -1391,13 +1489,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
        column = to & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n");
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
                return -EINVAL;
        }
 
        /* For compatibility with NAND: Do not allow write past end of page */
        if (unlikely(column + len > oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: "
+               printk(KERN_ERR "onenand_write_oob_nolock: "
                      "Attempt to write past end of page\n");
                return -EINVAL;
        }
@@ -1406,13 +1504,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
        if (unlikely(to >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (to >> this->page_shift)) * oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n");
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
-
        oobbuf = this->oob_buf;
 
        /* Loop until all data write */
@@ -1442,13 +1537,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
 
                ret = this->wait(mtd, FL_WRITING);
                if (ret) {
-                       printk(KERN_ERR "onenand_write_oob: write failed %d\n", 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: verify failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
                        break;
                }
 
@@ -1461,11 +1556,37 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
                column = 0;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
+       ops->oobretlen = written;
+
+       return ret;
+}
+
+/**
+ * onenand_write - [MTD Interface] write buffer to FLASH
+ * @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
+ */
+static 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;
 
-       *retlen = written;
+       onenand_get_device(mtd, FL_WRITING);
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
+       onenand_release_device(mtd);
 
+       *retlen = ops.retlen;
        return ret;
 }
 
@@ -1478,6 +1599,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
 static 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:
@@ -1487,21 +1610,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
        default:
                return -EINVAL;
        }
-       return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen,
-                                   &ops->oobretlen, ops->oobbuf, ops->mode);
+
+       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;
 }
 
 /**
- * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
  * @param mtd          MTD device structure
  * @param ofs          offset from device start
- * @param getchip      0, if the chip is already selected
  * @param 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.
  */
-static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
@@ -1562,7 +1691,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                cond_resched();
 
                /* Check if we have a bad block, we do not erase bad blocks */
-               if (onenand_block_checkbad(mtd, addr, 0, 0)) {
+               if (onenand_block_isbad_nolock(mtd, addr, 0)) {
                        printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr);
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
@@ -1590,13 +1719,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
 erase_exit:
 
        ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-       /* Do call back function */
-       if (!ret)
-               mtd_erase_callback(instr);
 
        /* Deselect and wake up anyone waiting on the device */
        onenand_release_device(mtd);
 
+       /* Do call back function */
+       if (!ret)
+               mtd_erase_callback(instr);
+
        return ret;
 }
 
@@ -1626,11 +1756,16 @@ static void onenand_sync(struct mtd_info *mtd)
  */
 static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
 {
+       int ret;
+
        /* Check for invalid offset */
        if (ofs > mtd->size)
                return -EINVAL;
 
-       return onenand_block_checkbad(mtd, ofs, 1, 0);
+       onenand_get_device(mtd, FL_READING);
+       ret = onenand_block_isbad_nolock(mtd, ofs, 0);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1646,7 +1781,12 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
        u_char buf[2] = {0, 0};
-       size_t retlen;
+       struct mtd_oob_ops ops = {
+               .mode = MTD_OOB_PLACE,
+               .ooblen = 2,
+               .oobbuf = buf,
+               .ooboffs = 0,
+       };
        int block;
 
        /* Get block number */
@@ -1656,7 +1796,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
         /* We write two bytes, so we dont have to mess with 16 bit access */
         ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
-        return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE);
+        return onenand_write_oob_nolock(mtd, ofs, &ops);
 }
 
 /**
@@ -1679,7 +1819,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
-       return this->block_markbad(mtd, ofs);
+       onenand_get_device(mtd, FL_WRITING);
+       ret = this->block_markbad(mtd, ofs);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1770,7 +1913,12 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
  */
 static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-       return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+       int ret;
+
+       onenand_get_device(mtd, FL_LOCKING);
+       ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1783,7 +1931,12 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
  */
 static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-       return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+       int ret;
+
+       onenand_get_device(mtd, FL_LOCKING);
+       ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1845,7 +1998,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
                        loff_t ofs = this->chipsize >> 1;
                        size_t len = mtd->erasesize;
 
-                       onenand_unlock(mtd, ofs, len);
+                       onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
                }
 
                onenand_check_lock_status(this);
@@ -1853,7 +2006,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
                return 0;
        }
 
-       onenand_unlock(mtd, 0x0, this->chipsize);
+       onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK);
 
        return 0;
 }
@@ -1878,13 +2031,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = buf,
+               .oobbuf = NULL,
+       };
        int ret;
 
        /* Enter OTP access mode */
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = mtd->read(mtd, from, len, retlen, buf);
+       ret = onenand_read_ops_nolock(mtd, from, &ops);
 
        /* Exit OTP access mode */
        this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1896,19 +2055,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
 /**
  * do_otp_write - [DEFAULT] Write OTP block area
  * @param mtd          MTD device structure
- * @param from         The offset to write
+ * @param to           The offset to write
  * @param len          number of bytes to write
  * @param retlen       pointer to variable to store the number of write bytes
  * @param buf          the databuffer to put/get data
  *
  * Write OTP block area.
  */
-static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
+static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
        unsigned char *pbuf = buf;
        int ret;
+       struct mtd_oob_ops ops;
 
        /* Force buffer page aligned */
        if (len < mtd->writesize) {
@@ -1922,7 +2082,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = mtd->write(mtd, from, len, retlen, pbuf);
+       ops.len = len;
+       ops.ooblen = 0;
+       ops.datbuf = pbuf;
+       ops.oobbuf = NULL;
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
+       *retlen = ops.retlen;
 
        /* Exit OTP access mode */
        this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1945,13 +2110,21 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_oob_ops ops = {
+               .mode = MTD_OOB_PLACE,
+               .ooblen = len,
+               .oobbuf = buf,
+               .ooboffs = 0,
+       };
        int ret;
 
        /* Enter OTP access mode */
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE);
+       ret = onenand_write_oob_nolock(mtd, from, &ops);
+
+       *retlen = ops.oobretlen;
 
        /* Exit OTP access mode */
        this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1983,7 +2156,7 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
 
        *retlen = 0;
 
-       density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       density = onenand_get_density(this->device_id);
        if (density < ONENAND_DEVICE_DENSITY_512Mb)
                otp_pages = 20;
        else
@@ -1998,13 +2171,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
        if (((mtd->writesize * otp_pages) - (from + len)) < 0)
                return 0;
 
+       onenand_get_device(mtd, FL_OTPING);
        while (len > 0 && otp_pages > 0) {
                if (!action) {  /* OTP Info functions */
                        struct otp_info *otpinfo;
 
                        len -= sizeof(struct otp_info);
-                       if (len <= 0)
-                               return -ENOSPC;
+                       if (len <= 0) {
+                               ret = -ENOSPC;
+                               break;
+                       }
 
                        otpinfo = (struct otp_info *) buf;
                        otpinfo->start = from;
@@ -2024,13 +2200,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
                        len -= size;
                        *retlen += size;
 
-                       if (ret < 0)
-                               return ret;
+                       if (ret)
+                               break;
                }
                otp_pages--;
        }
+       onenand_release_device(mtd);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -2130,7 +2307,8 @@ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
 static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
                        size_t len)
 {
-       unsigned char oob_buf[64];
+       struct onenand_chip *this = mtd->priv;
+       u_char *oob_buf = this->oob_buf;
        size_t retlen;
        int ret;
 
@@ -2170,7 +2348,7 @@ static void onenand_check_features(struct mtd_info *mtd)
        unsigned int density, process;
 
        /* Lock scheme depends on density and process */
-       density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       density = onenand_get_density(this->device_id);
        process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
 
        /* Lock scheme */
@@ -2219,14 +2397,14 @@ static void onenand_print_device_info(int device, int version)
         vcc = device & ONENAND_DEVICE_VCC_MASK;
         demuxed = device & ONENAND_DEVICE_IS_DEMUX;
         ddp = device & ONENAND_DEVICE_IS_DDP;
-        density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
+        density = onenand_get_density(device);
         printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
                 demuxed ? "" : "Muxed ",
                 ddp ? "(DDP)" : "",
                 (16 << density),
                 vcc ? "2.65/3.3" : "1.8",
                 device);
-       printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
+       printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
 }
 
 static const struct onenand_manufacturers onenand_manuf_ids[] = {
@@ -2311,7 +2489,7 @@ static int onenand_probe(struct mtd_info *mtd)
        this->device_id = dev_id;
        this->version_id = ver_id;
 
-       density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       density = onenand_get_density(dev_id);
        this->chipsize = (16 << density) << 20;
        /* Set density mask. it is used for DDP */
        if (ONENAND_IS_DDP(this))