WS cleanup: remove SPACE(s) followed by TAB
[platform/kernel/u-boot.git] / drivers / mtd / onenand / onenand_base.c
index 1d0f196..46aeef2 100644 (file)
  */
 
 #include <common.h>
-#include <linux/mtd/compat.h>
+#include <log.h>
+#include <watchdog.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
 #include <linux/mtd/mtd.h>
+#include "linux/mtd/flashchip.h"
 #include <linux/mtd/onenand.h>
 
 #include <asm/io.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <malloc.h>
 
 /* It should access 16-bit instead of 8-bit */
@@ -91,7 +96,13 @@ static struct nand_ecclayout onenand_oob_32 = {
        .oobfree        = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
 };
 
-static const unsigned char ffchars[] = {
+/*
+ * Warning! This array is used with the memcpy_16() function, thus
+ * it must be aligned to 2 bytes. GCC can make this array unaligned
+ * as the array is made of unsigned char, which memcpy16() doesn't
+ * like and will cause unaligned access.
+ */
+static const unsigned char __aligned(2) ffchars[] = {
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -460,15 +471,18 @@ static int onenand_read_ecc(struct onenand_chip *this)
 static int onenand_wait(struct mtd_info *mtd, int state)
 {
        struct onenand_chip *this = mtd->priv;
-       unsigned int flags = ONENAND_INT_MASTER;
        unsigned int interrupt = 0;
        unsigned int ctrl;
 
-       while (1) {
+       /* Wait at most 20ms ... */
+       u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
+       u32 time_start = get_timer(0);
+       do {
+               WATCHDOG_RESET();
+               if (get_timer(time_start) > timeo)
+                       return -EIO;
                interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
-               if (interrupt & flags)
-                       break;
-       }
+       } while ((interrupt & ONENAND_INT_MASTER) == 0);
 
        ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
 
@@ -632,10 +646,6 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
        int blockpage, found = 0;
        unsigned int i;
 
-#ifdef CONFIG_S3C64XX
-       return 0;
-#endif
-
        if (ONENAND_IS_2PLANE(this))
                blockpage = onenand_get_2x_blockpage(mtd, addr);
        else
@@ -747,7 +757,7 @@ static void onenand_release_device(struct mtd_info *mtd)
 }
 
 /**
- * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
+ * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer
  * @param mtd          MTD device structure
  * @param buf          destination address
  * @param column       oob offset to read from
@@ -765,7 +775,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
        uint8_t *oob_buf = this->oob_buf;
 
        free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length;
+            i++, free++) {
                if (readcol >= lastgap)
                        readcol += free->offset - lastgap;
                if (readend >= lastgap)
@@ -774,7 +785,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
        }
        this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
        free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && 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);
@@ -811,7 +823,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
                return status;
 
        /* check if we failed due to uncorrectable error */
-       if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
+       if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
                return status;
 
        /* check if address lies in MLC region */
@@ -849,9 +861,10 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        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);
+       pr_debug("onenand_read_ops_nolock: from = 0x%08x, len = %i\n",
+                (unsigned int) from, (int) len);
 
-       if (ops->mode == MTD_OOB_AUTO)
+       if (ops->mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                oobsize = mtd->oobsize;
@@ -918,7 +931,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        thisooblen = oobsize - oobcolumn;
                        thisooblen = min_t(int, thisooblen, ooblen - oobread);
 
-                       if (ops->mode == MTD_OOB_AUTO)
+                       if (ops->mode == MTD_OPS_AUTO_OOB)
                                onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
                        else
                                this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
@@ -933,7 +946,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        if (unlikely(ret))
                                ret = onenand_recover_lsb(mtd, from, ret);
                        onenand_update_bufferram(mtd, from, !ret);
-                       if (ret == -EBADMSG)
+                       if (mtd_is_eccerr(ret))
                                ret = 0;
                }
 
@@ -954,7 +967,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        /* Now wait for load */
                        ret = this->wait(mtd, FL_READING);
                        onenand_update_bufferram(mtd, from, !ret);
-                       if (ret == -EBADMSG)
+                       if (mtd_is_eccerr(ret))
                                ret = 0;
                }
        }
@@ -973,7 +986,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
-       return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+       /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
+       return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
 }
 
 /**
@@ -991,18 +1005,19 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
        struct mtd_ecc_stats stats;
        int read = 0, thislen, column, oobsize;
        size_t len = ops->ooblen;
-       mtd_oob_mode_t mode = ops->mode;
+       unsigned int mode = ops->mode;
        u_char *buf = ops->oobbuf;
        int ret = 0, readcmd;
 
        from += ops->ooboffs;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+       pr_debug("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)
+       if (mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                oobsize = mtd->oobsize;
@@ -1045,7 +1060,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                        break;
                }
 
-               if (mode == MTD_OOB_AUTO)
+               if (mode == MTD_OPS_AUTO_OOB)
                        onenand_transfer_auto_oob(mtd, buf, column, thislen);
                else
                        this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
@@ -1119,10 +1134,10 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from,
        int ret;
 
        switch (ops->mode) {
-       case MTD_OOB_PLACE:
-       case MTD_OOB_AUTO:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_AUTO_OOB:
                break;
-       case MTD_OOB_RAW:
+       case MTD_OPS_RAW:
                /* Not implemented yet */
        default:
                return -EINVAL;
@@ -1148,15 +1163,18 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from,
 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) {
+       /* Wait at most 20ms ... */
+       u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
+       u32 time_start = get_timer(0);
+       do {
+               WATCHDOG_RESET();
+               if (get_timer(time_start) > timeo)
+                       return ONENAND_BBT_READ_FATAL_ERROR;
                interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
-               if (interrupt & flags)
-                       break;
-       }
+       } while ((interrupt & ONENAND_INT_MASTER) == 0);
 
        /* To get correct interrupt status in timeout case */
        interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
@@ -1201,7 +1219,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
        size_t len = ops->ooblen;
        u_char *buf = ops->oobbuf;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
+       pr_debug("onenand_bbt_read_oob: from = 0x%08x, len = %zi\n",
+                (unsigned int) from, len);
 
        readcmd = ONENAND_IS_4KB_PAGE(this) ?
                ONENAND_CMD_READ : ONENAND_CMD_READOOB;
@@ -1341,7 +1360,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
 #define NOTALIGNED(x)  ((x & (this->subpagesize - 1)) != 0)
 
 /**
- * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
  * @param mtd           MTD device structure
  * @param oob_buf       oob buffer
  * @param buf           source address
@@ -1359,7 +1378,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
        unsigned int i;
 
        free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length;
+            i++, free++) {
                if (writecol >= lastgap)
                        writecol += free->offset - lastgap;
                if (writeend >= lastgap)
@@ -1367,7 +1387,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
                lastgap = free->offset + free->length;
        }
        free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && 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);
@@ -1402,25 +1423,20 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
        u_char *oobbuf;
        int ret = 0;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+       pr_debug("onenand_write_ops_nolock: to = 0x%08x, len = %i\n",
+                (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
        ops->retlen = 0;
        ops->oobretlen = 0;
 
-       /* Do not allow writes past end of device */
-       if (unlikely((to + len) > mtd->size)) {
-               printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
-               return -EINVAL;
-       }
-
        /* Reject writes, which are not page aligned */
        if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
                printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
                return -EINVAL;
        }
 
-       if (ops->mode == MTD_OOB_AUTO)
+       if (ops->mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                oobsize = mtd->oobsize;
@@ -1454,7 +1470,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
                        /* We send data to spare ram with oobsize
                         *                          * to prevent byte access */
                        memset(oobbuf, 0xff, mtd->oobsize);
-                       if (ops->mode == MTD_OOB_AUTO)
+                       if (ops->mode == MTD_OPS_AUTO_OOB)
                                onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
                        else
                                memcpy(oobbuf + oobcolumn, oob, thisooblen);
@@ -1506,7 +1522,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
 }
 
 /**
- * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
+ * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
  * @param mtd           MTD device structure
  * @param to            offset to write to
  * @param len           number of bytes to write
@@ -1525,16 +1541,17 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
        u_char *oobbuf;
        size_t len = ops->ooblen;
        const u_char *buf = ops->oobbuf;
-       mtd_oob_mode_t mode = ops->mode;
+       unsigned int mode = ops->mode;
 
        to += ops->ooboffs;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+       pr_debug("onenand_write_oob_nolock: to = 0x%08x, len = %i\n",
+                (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
        ops->oobretlen = 0;
 
-       if (mode == MTD_OOB_AUTO)
+       if (mode == MTD_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
        else
                oobsize = mtd->oobsize;
@@ -1575,7 +1592,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
                /* We send data to spare ram with oobsize
                 * to prevent byte access */
                memset(oobbuf, 0xff, mtd->oobsize);
-               if (mode == MTD_OOB_AUTO)
+               if (mode == MTD_OPS_AUTO_OOB)
                        onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
                else
                        memcpy(oobbuf + column, buf, thislen);
@@ -1665,10 +1682,10 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to,
        int ret;
 
        switch (ops->mode) {
-       case MTD_OOB_PLACE:
-       case MTD_OOB_AUTO:
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_AUTO_OOB:
                break;
-       case MTD_OOB_RAW:
+       case MTD_OPS_RAW:
                /* Not implemented yet */
        default:
                return -EINVAL;
@@ -1721,16 +1738,9 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
        struct mtd_erase_region_info *region = NULL;
        unsigned int region_end = 0;
 
-       MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
+       pr_debug("onenand_erase: start = 0x%08x, len = %i\n",
                        (unsigned int) addr, len);
 
-       /* Do not allow erase past end of device */
-       if (unlikely((len + addr) > mtd->size)) {
-               MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
-                                       "Erase past end of device\n");
-               return -EINVAL;
-       }
-
        if (FLEXONENAND(this)) {
                /* Find the eraseregion of this address */
                i = flexonenand_region(mtd, addr);
@@ -1744,8 +1754,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                 * Erase region's start offset is always block start address.
                 */
                if (unlikely((addr - region->offset) & (block_size - 1))) {
-                       MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
-                               " Unaligned address\n");
+                       pr_debug("onenand_erase:" " Unaligned address\n");
                        return -EINVAL;
                }
        } else {
@@ -1753,21 +1762,17 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
 
                /* Start address must align on block boundary */
                if (unlikely(addr & (block_size - 1))) {
-                       MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
-                                               "Unaligned address\n");
+                       pr_debug("onenand_erase:" "Unaligned address\n");
                        return -EINVAL;
                }
        }
 
        /* Length must align on block boundary */
        if (unlikely(len & (block_size - 1))) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0,
-                        "onenand_erase: Length not block aligned\n");
+               pr_debug("onenand_erase: Length not block aligned\n");
                return -EINVAL;
        }
 
-       instr->fail_addr = 0xffffffff;
-
        /* Grab the lock and see if the device is available */
        onenand_get_device(mtd, FL_ERASING);
 
@@ -1793,12 +1798,12 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                /* Check, if it is write protected */
                if (ret) {
                        if (ret == -EPERM)
-                               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
-                                         "Device is write protected!!!\n");
+                               pr_debug("onenand_erase: "
+                                        "Device is write protected!!!\n");
                        else
-                               MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
-                                         "Failed erase, block %d\n",
-                                       onenand_block(this, addr));
+                               pr_debug("onenand_erase: "
+                                        "Failed erase, block %d\n",
+                                        onenand_block(this, addr));
                        instr->state = MTD_ERASE_FAILED;
                        instr->fail_addr = addr;
 
@@ -1849,7 +1854,7 @@ erase_exit:
  */
 void onenand_sync(struct mtd_info *mtd)
 {
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
+       pr_debug("onenand_sync: called\n");
 
        /* Grab the lock and see if the device is available */
        onenand_get_device(mtd, FL_SYNCING);
@@ -1893,7 +1898,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct bbm_info *bbm = this->bbm;
        u_char buf[2] = {0, 0};
        struct mtd_oob_ops ops = {
-               .mode = MTD_OOB_PLACE,
+               .mode = MTD_OPS_PLACE_OOB,
                .ooblen = 2,
                .oobbuf = buf,
                .ooboffs = 0,
@@ -1930,7 +1935,10 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
+       onenand_get_device(mtd, FL_WRITING);
        ret = this->block_markbad(mtd, ofs);
+       onenand_release_device(mtd);
+
        return ret;
 }
 
@@ -2298,8 +2306,8 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)
 
 /**
  * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
- *                       boundary[], diesize[], mtd->size, mtd->erasesize,
- *                       mtd->eraseregions
+ *                       boundary[], diesize[], mtd->size, mtd->erasesize,
+ *                       mtd->eraseregions
  * @param mtd          - MTD device structure
  */
 static void flexonenand_get_size(struct mtd_info *mtd)
@@ -2390,7 +2398,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
        int i, ret;
        int block;
        struct mtd_oob_ops ops = {
-               .mode = MTD_OOB_PLACE,
+               .mode = MTD_OPS_PLACE_OOB,
                .ooboffs = 0,
                .ooblen = mtd->oobsize,
                .datbuf = NULL,
@@ -2544,7 +2552,8 @@ static int onenand_chip_probe(struct mtd_info *mtd)
        this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
 
        /* Wait reset */
-       this->wait(mtd, FL_RESETING);
+       if (this->wait(mtd, FL_RESETING))
+               return -ENXIO;
 
        /* Restore system configuration 1 */
        this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
@@ -2648,15 +2657,15 @@ int onenand_probe(struct mtd_info *mtd)
        else
                mtd->size = this->chipsize;
 
+       mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH;
-       mtd->erase = onenand_erase;
-       mtd->read = onenand_read;
-       mtd->write = onenand_write;
-       mtd->read_oob = onenand_read_oob;
-       mtd->write_oob = onenand_write_oob;
-       mtd->sync = onenand_sync;
-       mtd->block_isbad = onenand_block_isbad;
-       mtd->block_markbad = onenand_block_markbad;
+       mtd->_erase = onenand_erase;
+       mtd->_read_oob = onenand_read_oob;
+       mtd->_write_oob = onenand_write_oob;
+       mtd->_sync = onenand_sync;
+       mtd->_block_isbad = onenand_block_isbad;
+       mtd->_block_markbad = onenand_block_markbad;
+       mtd->writebufsize = mtd->writesize;
 
        return 0;
 }
@@ -2769,7 +2778,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
         * the out of band area
         */
        this->ecclayout->oobavail = 0;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
+
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE &&
            this->ecclayout->oobfree[i].length; i++)
                this->ecclayout->oobavail +=
                        this->ecclayout->oobfree[i].length;