]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/mtd/nand/mxs_nand.c
Merge remote-tracking branch 'u-boot/master' into u-boot-arm-merged
[people/ms/u-boot.git] / drivers / mtd / nand / mxs_nand.c
index ce2a3268732c33b64334544f54096f50eae0e7a4..e38e15125407bb0f2361ac04e96edae893294c7d 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#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>
@@ -50,6 +50,7 @@ struct mxs_nand_info {
        int             cur_chip;
 
        uint32_t        cmd_queue_len;
+       uint32_t        data_buf_size;
 
        uint8_t         *cmd_buf;
        uint8_t         *data_buf;
@@ -73,6 +74,36 @@ struct mxs_nand_info {
 
 struct nand_ecclayout fake_ecc_layout;
 
+/*
+ * Cache management functions
+ */
+#ifndef        CONFIG_SYS_DCACHE_OFF
+static void mxs_nand_flush_data_buf(struct mxs_nand_info *info)
+{
+       uint32_t addr = (uint32_t)info->data_buf;
+
+       flush_dcache_range(addr, addr + info->data_buf_size);
+}
+
+static void mxs_nand_inval_data_buf(struct mxs_nand_info *info)
+{
+       uint32_t addr = (uint32_t)info->data_buf;
+
+       invalidate_dcache_range(addr, addr + info->data_buf_size);
+}
+
+static void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info)
+{
+       uint32_t addr = (uint32_t)info->cmd_buf;
+
+       flush_dcache_range(addr, addr + MXS_NAND_COMMAND_BUFFER_SIZE);
+}
+#else
+static inline void mxs_nand_flush_data_buf(struct mxs_nand_info *info) {}
+static inline void mxs_nand_inval_data_buf(struct mxs_nand_info *info) {}
+static inline void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) {}
+#endif
+
 static struct mxs_dma_desc *mxs_nand_get_dma_desc(struct mxs_nand_info *info)
 {
        struct mxs_dma_desc *desc;
@@ -202,11 +233,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);
@@ -286,6 +317,9 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
 
        mxs_dma_desc_append(channel, d);
 
+       /* Flush caches */
+       mxs_nand_flush_cmd_buf(nand_info);
+
        /* Execute the DMA chain. */
        ret = mxs_dma_go(channel);
        if (ret)
@@ -304,8 +338,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);
@@ -435,6 +469,9 @@ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length)
                goto rtn;
        }
 
+       /* Invalidate caches */
+       mxs_nand_inval_data_buf(nand_info);
+
        memcpy(buf, nand_info->data_buf, length);
 
 rtn:
@@ -484,6 +521,9 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 
        mxs_dma_desc_append(channel, d);
 
+       /* Flush caches */
+       mxs_nand_flush_data_buf(nand_info);
+
        /* Execute the DMA chain. */
        ret = mxs_dma_go(channel);
        if (ret)
@@ -600,6 +640,9 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
                goto rtn;
        }
 
+       /* Invalidate caches */
+       mxs_nand_inval_data_buf(nand_info);
+
        /* Read DMA completed, now do the mark swapping. */
        mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf);
 
@@ -687,6 +730,9 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
 
        mxs_dma_desc_append(channel, d);
 
+       /* Flush caches */
+       mxs_nand_flush_data_buf(nand_info);
+
        /* Execute the DMA chain. */
        ret = mxs_dma_go(channel);
        if (ret) {
@@ -922,11 +968,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)
@@ -978,18 +1024,19 @@ int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info)
        uint8_t *buf;
        const int size = NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE;
 
+       nand_info->data_buf_size = roundup(size, MXS_DMA_ALIGNMENT);
+
        /* DMA buffers */
-       buf = memalign(MXS_DMA_ALIGNMENT, size);
+       buf = memalign(MXS_DMA_ALIGNMENT, nand_info->data_buf_size);
        if (!buf) {
                printf("MXS NAND: Error allocating DMA buffers\n");
                return -ENOMEM;
        }
 
-       memset(buf, 0, size);
+       memset(buf, 0, nand_info->data_buf_size);
 
        nand_info->data_buf = buf;
        nand_info->oob_buf = buf + NAND_MAX_PAGESIZE;
-
        /* Command buffers */
        nand_info->cmd_buf = memalign(MXS_DMA_ALIGNMENT,
                                MXS_NAND_COMMAND_BUFFER_SIZE);
@@ -1009,9 +1056,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);
@@ -1026,10 +1075,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
@@ -1042,6 +1096,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: