]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mtd/nand/mxs_nand.c
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / mtd / nand / mxs_nand.c
index 4b1297a2fdc140bf46b9ece19c5f611b5578b98b..036c113ad3e93ad6ffaa8a637d6e042fe2758a94 100644 (file)
  * Copyright (C) 2010 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
+#include <common.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/types.h>
-#include <common.h>
 #include <malloc.h>
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
+#include <asm/imx-common/regs-bch.h>
+#include <asm/imx-common/regs-gpmi.h>
 #include <asm/arch/sys_proto.h>
-#include <asm/arch/dma.h>
+#include <asm/imx-common/dma.h>
 
 #define        MXS_NAND_DMA_DESCRIPTOR_COUNT           4
 
 #define        MXS_NAND_CHUNK_DATA_CHUNK_SIZE          512
+#if defined(CONFIG_MX6)
+#define        MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT    2
+#else
+#define        MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT    0
+#endif
 #define        MXS_NAND_METADATA_SIZE                  10
 
 #define        MXS_NAND_COMMAND_BUFFER_SIZE            32
@@ -160,6 +155,9 @@ static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
 
                if (page_oob_size == 218)
                        return 16;
+
+               if (page_oob_size == 224)
+                       return 16;
        }
 
        return 0;
@@ -233,11 +231,11 @@ static uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd)
  */
 static int mxs_nand_wait_for_bch_complete(void)
 {
-       struct mx28_bch_regs *bch_regs = (struct mx28_bch_regs *)MXS_BCH_BASE;
+       struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
        int timeout = MXS_NAND_BCH_TIMEOUT;
        int ret;
 
-       ret = mx28_wait_mask_set(&bch_regs->hw_bch_ctrl_reg,
+       ret = mxs_wait_mask_set(&bch_regs->hw_bch_ctrl_reg,
                BCH_CTRL_COMPLETE_IRQ, timeout);
 
        writel(BCH_CTRL_COMPLETE_IRQ, &bch_regs->hw_bch_ctrl_clr);
@@ -338,8 +336,8 @@ static int mxs_nand_device_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
        struct mxs_nand_info *nand_info = chip->priv;
-       struct mx28_gpmi_regs *gpmi_regs =
-               (struct mx28_gpmi_regs *)MXS_GPMI_BASE;
+       struct mxs_gpmi_regs *gpmi_regs =
+               (struct mxs_gpmi_regs *)MXS_GPMI_BASE;
        uint32_t tmp;
 
        tmp = readl(&gpmi_regs->hw_gpmi_stat);
@@ -546,7 +544,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
  * Read a page from NAND.
  */
 static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
-                                       uint8_t *buf, int page)
+                                       uint8_t *buf, int oob_required,
+                                       int page)
 {
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
@@ -691,8 +690,9 @@ rtn:
 /*
  * Write a page to NAND.
  */
-static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
-                               struct nand_chip *nand, const uint8_t *buf)
+static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
+                               struct nand_chip *nand, const uint8_t *buf,
+                               int oob_required)
 {
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
@@ -748,6 +748,7 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
 
 rtn:
        mxs_nand_return_dma_descs(nand_info);
+       return 0;
 }
 
 /*
@@ -763,7 +764,7 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from,
        struct mxs_nand_info *nand_info = chip->priv;
        int ret;
 
-       if (ops->mode == MTD_OOB_RAW)
+       if (ops->mode == MTD_OPS_RAW)
                nand_info->raw_oob_mode = 1;
        else
                nand_info->raw_oob_mode = 0;
@@ -788,7 +789,7 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to,
        struct mxs_nand_info *nand_info = chip->priv;
        int ret;
 
-       if (ops->mode == MTD_OOB_RAW)
+       if (ops->mode == MTD_OPS_RAW)
                nand_info->raw_oob_mode = 1;
        else
                nand_info->raw_oob_mode = 0;
@@ -866,7 +867,7 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
  * what to do.
  */
 static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
-                               int page, int cmd)
+                               int page)
 {
        struct mxs_nand_info *nand_info = nand->priv;
 
@@ -968,11 +969,11 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd->priv;
        struct mxs_nand_info *nand_info = nand->priv;
-       struct mx28_bch_regs *bch_regs = (struct mx28_bch_regs *)MXS_BCH_BASE;
+       struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
        uint32_t tmp;
 
        /* Configure BCH and set NFC geometry */
-       mx28_reset_block(&bch_regs->hw_bch_ctrl_reg);
+       mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
 
        /* Configure layout 0 */
        tmp = (mxs_nand_ecc_chunk_cnt(mtd->writesize) - 1)
@@ -980,14 +981,16 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
        tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
        tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
                << BCH_FLASHLAYOUT0_ECC0_OFFSET;
-       tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
+       tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE
+               >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
        writel(tmp, &bch_regs->hw_bch_flash0layout0);
 
        tmp = (mtd->writesize + mtd->oobsize)
                << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
        tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
                << BCH_FLASHLAYOUT1_ECCN_OFFSET;
-       tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
+       tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE
+               >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
        writel(tmp, &bch_regs->hw_bch_flash0layout1);
 
        /* Set *all* chip selects to use layout 0 */
@@ -997,19 +1000,19 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
        writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);
 
        /* Hook some operations at the MTD level. */
-       if (mtd->read_oob != mxs_nand_hook_read_oob) {
-               nand_info->hooked_read_oob = mtd->read_oob;
-               mtd->read_oob = mxs_nand_hook_read_oob;
+       if (mtd->_read_oob != mxs_nand_hook_read_oob) {
+               nand_info->hooked_read_oob = mtd->_read_oob;
+               mtd->_read_oob = mxs_nand_hook_read_oob;
        }
 
-       if (mtd->write_oob != mxs_nand_hook_write_oob) {
-               nand_info->hooked_write_oob = mtd->write_oob;
-               mtd->write_oob = mxs_nand_hook_write_oob;
+       if (mtd->_write_oob != mxs_nand_hook_write_oob) {
+               nand_info->hooked_write_oob = mtd->_write_oob;
+               mtd->_write_oob = mxs_nand_hook_write_oob;
        }
 
-       if (mtd->block_markbad != mxs_nand_hook_block_markbad) {
-               nand_info->hooked_block_markbad = mtd->block_markbad;
-               mtd->block_markbad = mxs_nand_hook_block_markbad;
+       if (mtd->_block_markbad != mxs_nand_hook_block_markbad) {
+               nand_info->hooked_block_markbad = mtd->_block_markbad;
+               mtd->_block_markbad = mxs_nand_hook_block_markbad;
        }
 
        /* We use the reference implementation for bad block management. */
@@ -1056,9 +1059,11 @@ int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info)
  */
 int mxs_nand_init(struct mxs_nand_info *info)
 {
-       struct mx28_gpmi_regs *gpmi_regs =
-               (struct mx28_gpmi_regs *)MXS_GPMI_BASE;
-       int i = 0;
+       struct mxs_gpmi_regs *gpmi_regs =
+               (struct mxs_gpmi_regs *)MXS_GPMI_BASE;
+       struct mxs_bch_regs *bch_regs =
+               (struct mxs_bch_regs *)MXS_BCH_BASE;
+       int i = 0, j;
 
        info->desc = malloc(sizeof(struct mxs_dma_desc *) *
                                MXS_NAND_DMA_DESCRIPTOR_COUNT);
@@ -1073,10 +1078,15 @@ int mxs_nand_init(struct mxs_nand_info *info)
        }
 
        /* Init the DMA controller. */
-       mxs_dma_init();
+       for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
+               j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) {
+               if (mxs_dma_init_channel(j))
+                       goto err3;
+       }
 
        /* Reset the GPMI block. */
-       mx28_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg);
+       mxs_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg);
+       mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
 
        /*
         * Choose NAND mode, set IRQ polarity, disable write protection and
@@ -1089,6 +1099,9 @@ int mxs_nand_init(struct mxs_nand_info *info)
 
        return 0;
 
+err3:
+       for (--j; j >= 0; j--)
+               mxs_dma_release(j);
 err2:
        free(info->desc);
 err1:
@@ -1153,6 +1166,7 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.mode          = NAND_ECC_HW;
        nand->ecc.bytes         = 9;
        nand->ecc.size          = 512;
+       nand->ecc.strength      = 8;
 
        return 0;