WS cleanup: remove SPACE(s) followed by TAB
[platform/kernel/u-boot.git] / drivers / mtd / onenand / onenand_base.c
index 979e4af..46aeef2 100644 (file)
  */
 
 #include <common.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);
 
@@ -847,7 +861,8 @@ 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_OPS_AUTO_OOB)
                oobsize = this->ecclayout->oobavail;
@@ -996,7 +1011,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
 
        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;
@@ -1147,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);
@@ -1200,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;
@@ -1403,7 +1423,8 @@ 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;
@@ -1524,7 +1545,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
 
        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;
@@ -1716,7 +1738,7 @@ 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);
 
        if (FLEXONENAND(this)) {
@@ -1732,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 {
@@ -1741,16 +1762,14 @@ 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;
        }
 
@@ -1779,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;
 
@@ -1835,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);
@@ -1905,6 +1924,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
  */
 int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
+       struct onenand_chip *this = mtd->priv;
        int ret;
 
        ret = onenand_block_isbad(mtd, ofs);
@@ -1915,7 +1935,10 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
-       ret = mtd_block_markbad(mtd, ofs);
+       onenand_get_device(mtd, FL_WRITING);
+       ret = this->block_markbad(mtd, ofs);
+       onenand_release_device(mtd);
+
        return ret;
 }
 
@@ -2283,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)
@@ -2529,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);
@@ -2633,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->writebufsize = mtd->writesize;
 
        return 0;
 }