summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTerry Lv <r65388@freescale.com>2010-09-05 18:27:46 +0800
committerTerry Lv <r65388@freescale.com>2010-09-19 23:25:21 +0800
commit6537dffd192344d8c786a037bce9f41db5448fc9 (patch)
tree0500e0c88f7b0c9c6675d14fad3563267b419936 /drivers
parent1e981afa607f3e04691fa8f05dc7c37070702845 (diff)
downloadu-boot-imx-6537dffd192344d8c786a037bce9f41db5448fc9.zip
u-boot-imx-6537dffd192344d8c786a037bce9f41db5448fc9.tar.gz
u-boot-imx-6537dffd192344d8c786a037bce9f41db5448fc9.tar.bz2
ENGR00127167: Add gpmi nfc and apbh dma support for mx50.
Add gpmi nfc and apbh dma support for mx50. Signed-off-by: Terry Lv <r65388@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/apbh_dma.c825
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/gpmi_nfc_bch.h664
-rw-r--r--drivers/mtd/nand/gpmi_nfc_gpmi.h1118
-rw-r--r--drivers/mtd/nand/gpmi_nfc_hal.c1621
-rw-r--r--drivers/mtd/nand/gpmi_nfc_mil.c1187
-rw-r--r--drivers/serial/serial_mxc.c40
8 files changed, 5422 insertions, 35 deletions
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 36d99f9..2c023c8 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -27,6 +27,7 @@ LIB := $(obj)libdma.a
COBJS-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
COBJS-$(CONFIG_FSL_DMA) += fsl_dma.o
+COBJS-$(CONFIG_APBH_DMA) += apbh_dma.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/dma/apbh_dma.c b/drivers/dma/apbh_dma.c
new file mode 100644
index 0000000..296125a
--- /dev/null
+++ b/drivers/dma/apbh_dma.c
@@ -0,0 +1,825 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#include <asm/apbh_dma.h>
+
+#include <linux/err.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <common.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_ARCH_MMU
+#include <asm/arch/mmu.h>
+#endif
+
+#ifndef BM_APBH_CTRL0_APB_BURST_EN
+#define BM_APBH_CTRL0_APB_BURST_EN BM_APBH_CTRL0_APB_BURST4_EN
+#endif
+
+#if 0
+static inline s32 mxs_dma_apbh_reset_block(void *hwreg, int is_enable)
+{
+ int timeout;
+
+ /* the process of software reset of IP block is done
+ in several steps:
+
+ - clear SFTRST and wait for block is enabled;
+ - clear clock gating (CLKGATE bit);
+ - set the SFTRST again and wait for block is in reset;
+ - clear SFTRST and wait for reset completion.
+ */
+ /* clear SFTRST */
+ REG_CLR_ADDR(hwreg, BM_APBH_CTRL0_SFTRST);
+
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((REG_RD_ADDR(hwreg) & BM_APBH_CTRL0_SFTRST) == 0)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when enabling\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ /* clear CLKGATE */
+ REG_CLR_ADDR(hwreg, BM_APBH_CTRL0_CLKGATE);
+
+ if (is_enable) {
+ /* now again set SFTRST */
+ REG_SET_ADDR(hwreg, BM_APBH_CTRL0_SFTRST);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* poll until CLKGATE set */
+ if (REG_RD_ADDR(hwreg) & BM_APBH_CTRL0_CLKGATE)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when resetting\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ REG_CLR_ADDR(hwreg, BM_APBH_CTRL0_SFTRST);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((REG_RD_ADDR(hwreg) & BM_APBH_CTRL0_SFTRST) == 0)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when enabling "
+ "after reset\n", __func__, hwreg);
+ return -ETIME;
+ }
+
+ /* clear CLKGATE */
+ REG_CLR_ADDR(hwreg, BM_APBH_CTRL0_CLKGATE);
+ }
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((REG_RD_ADDR(hwreg) & BM_APBH_CTRL0_CLKGATE) == 0)
+ break;
+
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when unclockgating\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ return 0;
+}
+#endif
+
+static int mxs_dma_apbh_enable(struct mxs_dma_chan *pchan, unsigned int chan)
+{
+ unsigned int sem;
+ struct mxs_dma_device *pdev = pchan->dma;
+ struct mxs_dma_desc *pdesc;
+
+ pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node);
+ if (pdesc == NULL)
+ return -EFAULT;
+
+ sem = readl(pdev->base + HW_APBH_CHn_SEMA(chan));
+ sem = (sem & BM_APBH_CHn_SEMA_PHORE) >> BP_APBH_CHn_SEMA_PHORE;
+ if (pchan->flags & MXS_DMA_FLAGS_BUSY) {
+ if (pdesc->cmd.cmd.bits.chain == 0)
+ return 0;
+ if (sem < 2) {
+ if (!sem)
+ return 0;
+ pdesc = list_entry(pdesc->node.next,
+ struct mxs_dma_desc, node);
+#ifdef CONFIG_ARCH_MMU
+ writel(iomem_to_phys(mxs_dma_cmd_address(pdesc)),
+ pdev->base + HW_APBH_CHn_NXTCMDAR(chan));
+#else
+ writel(mxs_dma_cmd_address(pdesc),
+ pdev->base + HW_APBH_CHn_NXTCMDAR(chan));
+#endif
+ }
+ sem = pchan->pending_num;
+ pchan->pending_num = 0;
+ writel(BF_APBH_CHn_SEMA_INCREMENT_SEMA(sem),
+ pdev->base + HW_APBH_CHn_SEMA(chan));
+ pchan->active_num += sem;
+ return 0;
+ }
+
+ pchan->active_num += pchan->pending_num;
+ pchan->pending_num = 0;
+#ifdef CONFIG_ARCH_MMU
+ writel(iomem_to_phys(mxs_dma_cmd_address(pdesc)),
+ pdev->base + HW_APBH_CHn_NXTCMDAR(chan));
+#else
+ writel(mxs_dma_cmd_address(pdesc),
+ pdev->base + HW_APBH_CHn_NXTCMDAR(chan));
+#endif
+ writel(pchan->active_num, pdev->base + HW_APBH_CHn_SEMA(chan));
+ REG_CLR(pdev->base, HW_APBH_CTRL0, 1 << chan);
+ return 0;
+}
+
+static void mxs_dma_apbh_disable(struct mxs_dma_chan *pchan, unsigned int chan)
+{
+ struct mxs_dma_device *pdev = pchan->dma;
+
+ REG_SET(pdev->base, HW_APBH_CTRL0,
+ 1 << (chan + BP_APBH_CTRL0_CLKGATE_CHANNEL));
+}
+
+static void mxs_dma_apbh_reset(struct mxs_dma_device *pdev, unsigned int chan)
+{
+ REG_SET(pdev->base, HW_APBH_CHANNEL_CTRL,
+ 1 << (chan + BP_APBH_CHANNEL_CTRL_RESET_CHANNEL));
+}
+
+static void mxs_dma_apbh_freeze(struct mxs_dma_device *pdev, unsigned int chan)
+{
+ REG_SET(pdev->base, HW_APBH_CHANNEL_CTRL, 1 << chan);
+}
+
+static void
+mxs_dma_apbh_unfreeze(struct mxs_dma_device *pdev, unsigned int chan)
+{
+ REG_CLR(pdev->base, HW_APBH_CHANNEL_CTRL, 1 << chan);
+}
+
+static void mxs_dma_apbh_info(struct mxs_dma_device *pdev,
+ unsigned int chan, struct mxs_dma_info *info)
+{
+ unsigned int reg;
+
+ reg = REG_RD(pdev->base, HW_APBH_CTRL2);
+ info->status = reg >> chan;
+ info->buf_addr = readl(pdev->base + HW_APBH_CHn_BAR(chan));
+}
+
+static int
+mxs_dma_apbh_read_semaphore(struct mxs_dma_device *pdev, unsigned int chan)
+{
+ unsigned int reg;
+
+ reg = readl(pdev->base + HW_APBH_CHn_SEMA(chan));
+ return (reg & BM_APBH_CHn_SEMA_PHORE) >> BP_APBH_CHn_SEMA_PHORE;
+}
+
+static void
+mxs_dma_apbh_enable_irq(struct mxs_dma_device *pdev,
+ unsigned int chan, int enable)
+{
+ if (enable)
+ REG_SET(pdev->base, HW_APBH_CTRL1, 1 << (chan + 16));
+ else
+ REG_CLR(pdev->base, HW_APBH_CTRL1, 1 << (chan + 16));
+
+}
+
+static int
+mxs_dma_apbh_irq_is_pending(struct mxs_dma_device *pdev, unsigned int chan)
+{
+ unsigned int reg;
+
+ reg = REG_RD(pdev->base, HW_APBH_CTRL1);
+ reg |= REG_RD(pdev->base, HW_APBH_CTRL2);
+
+ return reg & (1 << chan);
+}
+
+static void mxs_dma_apbh_ack_irq(struct mxs_dma_device *pdev,
+ unsigned int chan)
+{
+ REG_CLR(pdev->base, HW_APBH_CTRL1, 1 << chan);
+ REG_CLR(pdev->base, HW_APBH_CTRL2, 1 << chan);
+}
+
+static struct mxs_dma_device mxs_dma_apbh = {
+ .name = "mxs-dma-apbh",
+};
+
+static int mxs_dma_apbh_probe(void)
+{
+ int i = 1000000;
+ u32 base = CONFIG_MXS_DMA_REG_BASE;
+
+ mxs_dma_apbh.base = (void *)base;
+
+ /*
+ mxs_dma_apbh_reset_block((void *)(base + HW_APBH_CTRL0), 1);
+ */
+ REG_CLR(base, HW_APBH_CTRL0,
+ BM_APBH_CTRL0_SFTRST);
+ for (; i > 0; --i) {
+ if (!(REG_RD(base, HW_APBH_CTRL0) &
+ BM_APBH_CTRL0_SFTRST))
+ break;
+ udelay(2);
+ }
+ if (i <= 0)
+ return -ETIME;
+ REG_CLR(base, HW_APBH_CTRL0, BM_APBH_CTRL0_CLKGATE);
+
+#ifdef CONFIG_APBH_DMA_BURST8
+ REG_SET(base, HW_APBH_CTRL0,
+ BM_APBH_CTRL0_AHB_BURST8_EN);
+#else
+ REG_CLR(base, HW_APBH_CTRL0,
+ BM_APBH_CTRL0_AHB_BURST8_EN);
+#endif
+
+#ifdef CONFIG_APBH_DMA_BURST
+ REG_SET(base, HW_APBH_CTRL0,
+ BM_APBH_CTRL0_APB_BURST_EN);
+#else
+ REG_CLR(base, HW_APBH_CTRL0,
+ BM_APBH_CTRL0_APB_BURST_EN);
+#endif
+
+ mxs_dma_apbh.chan_base = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
+ mxs_dma_apbh.chan_num = MXS_MAX_DMA_CHANNELS;
+
+ return mxs_dma_device_register(&mxs_dma_apbh);
+}
+
+/* DMA engine */
+
+/*
+ * The list of DMA drivers that manage various DMA channels. A DMA device
+ * driver registers to manage DMA channels by calling mxs_dma_device_register().
+ */
+static LIST_HEAD(mxs_dma_devices);
+
+/*
+ * The array of struct mxs_dma_chan that represent every DMA channel in the
+ * system. The index of the structure in the array indicates the specific DMA
+ * hardware it represents (see mach-mx28/include/mach/dma.h).
+ */
+
+static struct mxs_dma_chan mxs_dma_channels[MXS_MAX_DMA_CHANNELS];
+
+int mxs_dma_request(int channel)
+{
+ int ret = 0;
+ struct mxs_dma_chan *pchan;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+
+ pchan = mxs_dma_channels + channel;
+ if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) {
+ ret = -ENODEV;
+ goto out;
+ }
+ if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pchan->flags |= MXS_DMA_FLAGS_ALLOCATED;
+ pchan->active_num = 0;
+ pchan->pending_num = 0;
+ INIT_LIST_HEAD(&pchan->active);
+ INIT_LIST_HEAD(&pchan->done);
+out:
+ return ret;
+}
+
+void mxs_dma_release(int channel)
+{
+ struct mxs_dma_chan *pchan;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+
+ pchan = mxs_dma_channels + channel;
+
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+
+ if (pchan->flags & MXS_DMA_FLAGS_BUSY)
+ return;
+
+ pchan->dev = 0;
+ pchan->active_num = 0;
+ pchan->pending_num = 0;
+ pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED;
+}
+
+int mxs_dma_enable(int channel)
+{
+ int ret = 0;
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return -EINVAL;
+
+ pdma = pchan->dma;
+ if (pchan->pending_num)
+ ret = mxs_dma_apbh_enable(pchan, channel - pdma->chan_base);
+ pchan->flags |= MXS_DMA_FLAGS_BUSY;
+ return ret;
+}
+
+void mxs_dma_disable(int channel)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+ if (!(pchan->flags & MXS_DMA_FLAGS_BUSY))
+ return;
+ pdma = pchan->dma;
+ mxs_dma_apbh_disable(pchan, channel - pdma->chan_base);
+ pchan->flags &= ~MXS_DMA_FLAGS_BUSY;
+ pchan->active_num = 0;
+ pchan->pending_num = 0;
+ list_splice_init(&pchan->active, &pchan->done);
+}
+
+int mxs_dma_get_info(int channel, struct mxs_dma_info *info)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if (!info)
+ return -EINVAL;
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return -EFAULT;
+ pdma = pchan->dma;
+ mxs_dma_apbh_info(pdma, channel - pdma->chan_base, info);
+
+ return 0;
+}
+
+int mxs_dma_cooked(int channel, struct list_head *head)
+{
+ int sem;
+ struct mxs_dma_chan *pchan;
+ struct list_head *p, *q;
+ struct mxs_dma_desc *pdesc;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return -EINVAL;
+
+ sem = mxs_dma_read_semaphore(channel);
+ if (sem < 0)
+ return sem;
+ if (sem == pchan->active_num)
+ return 0;
+ list_for_each_safe(p, q, &pchan->active) {
+ if ((pchan->active_num) <= sem)
+ break;
+ pdesc = list_entry(p, struct mxs_dma_desc, node);
+ pdesc->flags &= ~MXS_DMA_DESC_READY;
+ if (head)
+ list_move_tail(p, head);
+ else
+ list_move_tail(p, &pchan->done);
+ if (pdesc->flags & MXS_DMA_DESC_LAST)
+ pchan->active_num--;
+ }
+ if (sem == 0)
+ pchan->flags &= ~MXS_DMA_FLAGS_BUSY;
+
+ return 0;
+}
+
+void mxs_dma_reset(int channel)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+ pdma = pchan->dma;
+ mxs_dma_apbh_reset(pdma, channel - pdma->chan_base);
+}
+
+void mxs_dma_freeze(int channel)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+ pdma = pchan->dma;
+ mxs_dma_apbh_freeze(pdma, channel - pdma->chan_base);
+}
+
+void mxs_dma_unfreeze(int channel)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+ pdma = pchan->dma;
+ mxs_dma_apbh_unfreeze(pdma, channel - pdma->chan_base);
+}
+
+int mxs_dma_read_semaphore(int channel)
+{
+ int ret = -EINVAL;
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return ret;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return ret;
+ pdma = pchan->dma;
+ ret = mxs_dma_apbh_read_semaphore(pdma, channel - pdma->chan_base);
+
+ return ret;
+}
+
+void mxs_dma_enable_irq(int channel, int en)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+ pdma = pchan->dma;
+ mxs_dma_apbh_enable_irq(pdma, channel - pdma->chan_base, en);
+}
+
+int mxs_dma_irq_is_pending(int channel)
+{
+ int ret = 0;
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return ret;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return ret;
+ pdma = pchan->dma;
+ ret = mxs_dma_apbh_irq_is_pending(pdma, channel - pdma->chan_base);
+
+ return ret;
+}
+
+void mxs_dma_ack_irq(int channel)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return;
+ pdma = pchan->dma;
+ mxs_dma_apbh_ack_irq(pdma, channel - pdma->chan_base);
+}
+
+/* mxs dma utility function */
+struct mxs_dma_desc *mxs_dma_alloc_desc(void)
+{
+ struct mxs_dma_desc *pdesc;
+#ifdef CONFIG_ARCH_MMU
+ u32 address;
+#endif
+
+#ifdef CONFIG_ARCH_MMU
+ address = (u32)iomem_to_phys((ulong)memalign(MXS_DMA_ALIGNMENT,
+ sizeof(struct mxs_dma_desc)));
+ if (!address)
+ return NULL;
+ pdesc = (struct mxs_dma_desc *)ioremap_nocache(address,
+ MXS_DMA_ALIGNMENT);
+ memset(pdesc, 0, sizeof(*pdesc));
+ pdesc->address = address;
+#else
+ pdesc = (struct mxs_dma_desc *)memalign(MXS_DMA_ALIGNMENT,
+ sizeof(struct mxs_dma_desc));
+ if (pdesc == NULL)
+ return NULL;
+ memset(pdesc, 0, sizeof(*pdesc));
+ pdesc->address = pdesc;
+#endif
+
+ return pdesc;
+};
+
+void mxs_dma_free_desc(struct mxs_dma_desc *pdesc)
+{
+ if (pdesc == NULL)
+ return;
+
+ free(pdesc);
+}
+
+int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc)
+{
+ int ret = 0;
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_desc *last;
+ struct mxs_dma_device *pdma;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return -EINVAL;
+ pdma = pchan->dma;
+#ifdef CONFIG_ARCH_MMU
+ pdesc->cmd.next = iomem_to_phys(mxs_dma_cmd_address(pdesc));
+#else
+ pdesc->cmd.next = mxs_dma_cmd_address(pdesc);
+#endif
+ pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST;
+ if (!list_empty(&pchan->active)) {
+
+ last = list_entry(pchan->active.prev,
+ struct mxs_dma_desc, node);
+
+ pdesc->flags &= ~MXS_DMA_DESC_FIRST;
+ last->flags &= ~MXS_DMA_DESC_LAST;
+
+#ifdef CONFIG_ARCH_MMU
+ last->cmd.next = iomem_to_phys(mxs_dma_cmd_address(pdesc));
+#else
+ last->cmd.next = mxs_dma_cmd_address(pdesc);
+#endif
+ last->cmd.cmd.bits.chain = 1;
+ }
+ pdesc->flags |= MXS_DMA_DESC_READY;
+ if (pdesc->flags & MXS_DMA_DESC_FIRST)
+ pchan->pending_num++;
+ list_add_tail(&pdesc->node, &pchan->active);
+
+ return ret;
+}
+
+int mxs_dma_desc_add_list(int channel, struct list_head *head)
+{
+ int ret = 0, size = 0;
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+ struct list_head *p;
+ struct mxs_dma_desc *prev = NULL, *pcur;
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return -EINVAL;
+
+ if (list_empty(head))
+ return 0;
+
+ pdma = pchan->dma;
+ list_for_each(p, head) {
+ pcur = list_entry(p, struct mxs_dma_desc, node);
+ if (!(pcur->cmd.cmd.bits.dec_sem || pcur->cmd.cmd.bits.chain))
+ return -EINVAL;
+ if (prev)
+#ifdef CONFIG_ARCH_MMU
+ prev->cmd.next =
+ iomem_to_phys(mxs_dma_cmd_address(pcur));
+#else
+ prev->cmd.next = mxs_dma_cmd_address(pcur);
+#endif
+ else
+ pcur->flags |= MXS_DMA_DESC_FIRST;
+ pcur->flags |= MXS_DMA_DESC_READY;
+ prev = pcur;
+ size++;
+ }
+ pcur = list_first_entry(head, struct mxs_dma_desc, node);
+#ifdef CONFIG_ARCH_MMU
+ prev->cmd.next = iomem_to_phys(mxs_dma_cmd_address(pcur));
+#else
+ prev->cmd.next = mxs_dma_cmd_address(pcur);
+#endif
+ prev->flags |= MXS_DMA_DESC_LAST;
+
+ if (!list_empty(&pchan->active)) {
+ pcur = list_entry(pchan->active.next,
+ struct mxs_dma_desc, node);
+ if (pcur->cmd.cmd.bits.dec_sem != prev->cmd.cmd.bits.dec_sem) {
+ ret = -EFAULT;
+ goto out ;
+ }
+#ifdef CONFIG_ARCH_MMU
+ prev->cmd.next = iomem_to_phys(mxs_dma_cmd_address(pcur));
+#else
+ prev->cmd.next = mxs_dma_cmd_address(pcur);
+#endif
+ prev = list_entry(pchan->active.prev,
+ struct mxs_dma_desc, node);
+ pcur = list_first_entry(head, struct mxs_dma_desc, node);
+ pcur->flags &= ~MXS_DMA_DESC_FIRST;
+ prev->flags &= ~MXS_DMA_DESC_LAST;
+#ifdef CONFIG_ARCH_MMU
+ prev->cmd.next = iomem_to_phys(mxs_dma_cmd_address(pcur));
+#else
+ prev->cmd.next = mxs_dma_cmd_address(pcur);
+#endif
+ }
+ list_splice(head, &pchan->active);
+ pchan->pending_num += size;
+ if (!(pcur->cmd.cmd.bits.dec_sem) && (pcur->flags & MXS_DMA_DESC_FIRST))
+ pchan->pending_num += 1;
+ else
+ pchan->pending_num += size;
+
+out:
+ return ret;
+}
+
+int mxs_dma_get_cooked(int channel, struct list_head *head)
+{
+ struct mxs_dma_chan *pchan;
+
+ if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+ pchan = mxs_dma_channels + channel;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return -EINVAL;
+
+ if (head == NULL)
+ return 0;
+
+ list_splice(&pchan->done, head);
+
+ return 0;
+}
+
+int mxs_dma_device_register(struct mxs_dma_device *pdev)
+{
+ int i;
+ struct mxs_dma_chan *pchan;
+
+ if (pdev == NULL || !pdev->chan_num)
+ return -EINVAL;
+
+ if ((pdev->chan_base >= MXS_MAX_DMA_CHANNELS) ||
+ ((pdev->chan_base + pdev->chan_num) > MXS_MAX_DMA_CHANNELS))
+ return -EINVAL;
+
+ pchan = mxs_dma_channels + pdev->chan_base;
+ for (i = 0; i < pdev->chan_num; i++, pchan++) {
+ pchan->dma = pdev;
+ pchan->flags = MXS_DMA_FLAGS_VALID;
+ }
+ list_add(&pdev->node, &mxs_dma_devices);
+
+ return 0;
+}
+
+/* DMA Operation */
+int mxs_dma_init(void)
+{
+ s32 dma_channel = 0, err = 0;
+
+ mxs_dma_apbh_probe();
+
+ for (dma_channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
+ dma_channel <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7;
+ ++dma_channel) {
+ err = mxs_dma_request(dma_channel);
+
+ if (err) {
+ printf("Can't acquire DMA channel %u\n", dma_channel);
+
+ /* Free all the channels we've already acquired. */
+ while (--dma_channel >= 0)
+ mxs_dma_release(dma_channel);
+ return err;
+ }
+
+ mxs_dma_reset(dma_channel);
+ mxs_dma_ack_irq(dma_channel);
+ }
+
+ return 0;
+}
+
+int mxs_dma_wait_complete(u32 uSecTimeout, unsigned int chan)
+{
+ struct mxs_dma_chan *pchan;
+ struct mxs_dma_device *pdma;
+
+ if ((chan < 0) || (chan >= MXS_MAX_DMA_CHANNELS))
+ return 1;
+
+ pchan = mxs_dma_channels + chan;
+ if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
+ return 1;
+ pdma = pchan->dma;
+
+ while ((!(REG_RD(pdma->base, HW_APBH_CTRL1) & (1 << chan))) &&
+ --uSecTimeout)
+ ;
+
+ if (uSecTimeout <= 0) {
+ /* Abort dma by resetting channel */
+ mxs_dma_apbh_reset(pdma, chan - pdma->chan_base);
+ return 1;
+ }
+
+ return 0;
+}
+
+int mxs_dma_go(int chan)
+{
+ u32 timeout = 10000;
+ int error;
+
+ LIST_HEAD(tmp_desc_list);
+
+ /* Get ready... */
+ mxs_dma_enable_irq(chan, 1);
+
+ /* Go! */
+ mxs_dma_enable(chan);
+
+ /* Wait for it to finish. */
+ error = (mxs_dma_wait_complete(timeout, chan)) ? -ETIMEDOUT : 0;
+
+ /* Clear out the descriptors we just ran. */
+ mxs_dma_cooked(chan, &tmp_desc_list);
+
+ /* Shut the DMA channel down. */
+ /* Clear irq */
+ mxs_dma_ack_irq(chan);
+ mxs_dma_reset(chan);
+ mxs_dma_enable_irq(chan, 0);
+ mxs_dma_disable(chan);
+
+ /* Return. */
+ return error;
+}
+
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 408f57c..92d5b06 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -48,6 +48,7 @@ COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o
COBJS-$(CONFIG_MX31_NAND) += mx31_nand.o
COBJS-$(CONFIG_MXC_NAND) += mxc_nand.o nand_device_info.o
+COBJS-$(CONFIG_NAND_GPMI) += gpmi_nfc_hal.o gpmi_nfc_mil.o nand_device_info.o
endif
COBJS := $(COBJS-y)
diff --git a/drivers/mtd/nand/gpmi_nfc_bch.h b/drivers/mtd/nand/gpmi_nfc_bch.h
new file mode 100644
index 0000000..2807088
--- /dev/null
+++ b/drivers/mtd/nand/gpmi_nfc_bch.h
@@ -0,0 +1,664 @@
+/*
+ * Freescale BCH Register Definitions
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.3
+ * Template revision: 1.3
+ */
+
+#ifndef __GPMI_NFC_BCH_REGS_H
+#define __GPMI_NFC_BCH_REGS_H
+
+
+#define HW_BCH_CTRL (0x00000000)
+#define HW_BCH_CTRL_SET (0x00000004)
+#define HW_BCH_CTRL_CLR (0x00000008)
+#define HW_BCH_CTRL_TOG (0x0000000c)
+
+#define BM_BCH_CTRL_SFTRST 0x80000000
+#define BV_BCH_CTRL_SFTRST__RUN 0x0
+#define BV_BCH_CTRL_SFTRST__RESET 0x1
+#define BM_BCH_CTRL_CLKGATE 0x40000000
+#define BV_BCH_CTRL_CLKGATE__RUN 0x0
+#define BV_BCH_CTRL_CLKGATE__NO_CLKS 0x1
+#define BP_BCH_CTRL_RSVD5 23
+#define BM_BCH_CTRL_RSVD5 0x3F800000
+#define BF_BCH_CTRL_RSVD5(v) \
+ (((v) << 23) & BM_BCH_CTRL_RSVD5)
+#define BM_BCH_CTRL_DEBUGSYNDROME 0x00400000
+#define BP_BCH_CTRL_RSVD4 20
+#define BM_BCH_CTRL_RSVD4 0x00300000
+#define BF_BCH_CTRL_RSVD4(v) \
+ (((v) << 20) & BM_BCH_CTRL_RSVD4)
+#define BP_BCH_CTRL_M2M_LAYOUT 18
+#define BM_BCH_CTRL_M2M_LAYOUT 0x000C0000
+#define BF_BCH_CTRL_M2M_LAYOUT(v) \
+ (((v) << 18) & BM_BCH_CTRL_M2M_LAYOUT)
+#define BM_BCH_CTRL_M2M_ENCODE 0x00020000
+#define BM_BCH_CTRL_M2M_ENABLE 0x00010000
+#define BP_BCH_CTRL_RSVD3 11
+#define BM_BCH_CTRL_RSVD3 0x0000F800
+#define BF_BCH_CTRL_RSVD3(v) \
+ (((v) << 11) & BM_BCH_CTRL_RSVD3)
+#define BM_BCH_CTRL_DEBUG_STALL_IRQ_EN 0x00000400
+#define BM_BCH_CTRL_RSVD2 0x00000200
+#define BM_BCH_CTRL_COMPLETE_IRQ_EN 0x00000100
+#define BP_BCH_CTRL_RSVD1 4
+#define BM_BCH_CTRL_RSVD1 0x000000F0
+#define BF_BCH_CTRL_RSVD1(v) \
+ (((v) << 4) & BM_BCH_CTRL_RSVD1)
+#define BM_BCH_CTRL_BM_ERROR_IRQ 0x00000008
+#define BM_BCH_CTRL_DEBUG_STALL_IRQ 0x00000004
+#define BM_BCH_CTRL_RSVD0 0x00000002
+#define BM_BCH_CTRL_COMPLETE_IRQ 0x00000001
+
+#define HW_BCH_STATUS0 (0x00000010)
+
+#define BP_BCH_STATUS0_HANDLE 20
+#define BM_BCH_STATUS0_HANDLE 0xFFF00000
+#define BF_BCH_STATUS0_HANDLE(v) \
+ (((v) << 20) & BM_BCH_STATUS0_HANDLE)
+#define BP_BCH_STATUS0_COMPLETED_CE 16
+#define BM_BCH_STATUS0_COMPLETED_CE 0x000F0000
+#define BF_BCH_STATUS0_COMPLETED_CE(v) \
+ (((v) << 16) & BM_BCH_STATUS0_COMPLETED_CE)
+#define BP_BCH_STATUS0_STATUS_BLK0 8
+#define BM_BCH_STATUS0_STATUS_BLK0 0x0000FF00
+#define BF_BCH_STATUS0_STATUS_BLK0(v) \
+ (((v) << 8) & BM_BCH_STATUS0_STATUS_BLK0)
+#define BV_BCH_STATUS0_STATUS_BLK0__ZERO 0x00
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR1 0x01
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR2 0x02
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR3 0x03
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR4 0x04
+#define BV_BCH_STATUS0_STATUS_BLK0__UNCORRECTABLE 0xFE
+#define BV_BCH_STATUS0_STATUS_BLK0__ERASED 0xFF
+#define BP_BCH_STATUS0_RSVD1 5
+#define BM_BCH_STATUS0_RSVD1 0x000000E0
+#define BF_BCH_STATUS0_RSVD1(v) \
+ (((v) << 5) & BM_BCH_STATUS0_RSVD1)
+#define BM_BCH_STATUS0_ALLONES 0x00000010
+#define BM_BCH_STATUS0_CORRECTED 0x00000008
+#define BM_BCH_STATUS0_UNCORRECTABLE 0x00000004
+#define BP_BCH_STATUS0_RSVD0 0
+#define BM_BCH_STATUS0_RSVD0 0x00000003
+#define BF_BCH_STATUS0_RSVD0(v) \
+ (((v) << 0) & BM_BCH_STATUS0_RSVD0)
+
+#define HW_BCH_MODE (0x00000020)
+
+#define BP_BCH_MODE_RSVD 8
+#define BM_BCH_MODE_RSVD 0xFFFFFF00
+#define BF_BCH_MODE_RSVD(v) \
+ (((v) << 8) & BM_BCH_MODE_RSVD)
+#define BP_BCH_MODE_ERASE_THRESHOLD 0
+#define BM_BCH_MODE_ERASE_THRESHOLD 0x000000FF
+#define BF_BCH_MODE_ERASE_THRESHOLD(v) \
+ (((v) << 0) & BM_BCH_MODE_ERASE_THRESHOLD)
+
+#define HW_BCH_ENCODEPTR (0x00000030)
+
+#define BP_BCH_ENCODEPTR_ADDR 0
+#define BM_BCH_ENCODEPTR_ADDR 0xFFFFFFFF
+#define BF_BCH_ENCODEPTR_ADDR(v) (v)
+
+#define HW_BCH_DATAPTR (0x00000040)
+
+#define BP_BCH_DATAPTR_ADDR 0
+#define BM_BCH_DATAPTR_ADDR 0xFFFFFFFF
+#define BF_BCH_DATAPTR_ADDR(v) (v)
+
+#define HW_BCH_METAPTR (0x00000050)
+
+#define BP_BCH_METAPTR_ADDR 0
+#define BM_BCH_METAPTR_ADDR 0xFFFFFFFF
+#define BF_BCH_METAPTR_ADDR(v) (v)
+
+#define HW_BCH_LAYOUTSELECT (0x00000070)
+
+#define BP_BCH_LAYOUTSELECT_CS15_SELECT 30
+#define BM_BCH_LAYOUTSELECT_CS15_SELECT 0xC0000000
+#define BF_BCH_LAYOUTSELECT_CS15_SELECT(v) \
+ (((v) << 30) & BM_BCH_LAYOUTSELECT_CS15_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS14_SELECT 28
+#define BM_BCH_LAYOUTSELECT_CS14_SELECT 0x30000000
+#define BF_BCH_LAYOUTSELECT_CS14_SELECT(v) \
+ (((v) << 28) & BM_BCH_LAYOUTSELECT_CS14_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS13_SELECT 26
+#define BM_BCH_LAYOUTSELECT_CS13_SELECT 0x0C000000
+#define BF_BCH_LAYOUTSELECT_CS13_SELECT(v) \
+ (((v) << 26) & BM_BCH_LAYOUTSELECT_CS13_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS12_SELECT 24
+#define BM_BCH_LAYOUTSELECT_CS12_SELECT 0x03000000
+#define BF_BCH_LAYOUTSELECT_CS12_SELECT(v) \
+ (((v) << 24) & BM_BCH_LAYOUTSELECT_CS12_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS11_SELECT 22
+#define BM_BCH_LAYOUTSELECT_CS11_SELECT 0x00C00000
+#define BF_BCH_LAYOUTSELECT_CS11_SELECT(v) \
+ (((v) << 22) & BM_BCH_LAYOUTSELECT_CS11_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS10_SELECT 20
+#define BM_BCH_LAYOUTSELECT_CS10_SELECT 0x00300000
+#define BF_BCH_LAYOUTSELECT_CS10_SELECT(v) \
+ (((v) << 20) & BM_BCH_LAYOUTSELECT_CS10_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS9_SELECT 18
+#define BM_BCH_LAYOUTSELECT_CS9_SELECT 0x000C0000
+#define BF_BCH_LAYOUTSELECT_CS9_SELECT(v) \
+ (((v) << 18) & BM_BCH_LAYOUTSELECT_CS9_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS8_SELECT 16
+#define BM_BCH_LAYOUTSELECT_CS8_SELECT 0x00030000
+#define BF_BCH_LAYOUTSELECT_CS8_SELECT(v) \
+ (((v) << 16) & BM_BCH_LAYOUTSELECT_CS8_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS7_SELECT 14
+#define BM_BCH_LAYOUTSELECT_CS7_SELECT 0x0000C000
+#define BF_BCH_LAYOUTSELECT_CS7_SELECT(v) \
+ (((v) << 14) & BM_BCH_LAYOUTSELECT_CS7_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS6_SELECT 12
+#define BM_BCH_LAYOUTSELECT_CS6_SELECT 0x00003000
+#define BF_BCH_LAYOUTSELECT_CS6_SELECT(v) \
+ (((v) << 12) & BM_BCH_LAYOUTSELECT_CS6_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS5_SELECT 10
+#define BM_BCH_LAYOUTSELECT_CS5_SELECT 0x00000C00
+#define BF_BCH_LAYOUTSELECT_CS5_SELECT(v) \
+ (((v) << 10) & BM_BCH_LAYOUTSELECT_CS5_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS4_SELECT 8
+#define BM_BCH_LAYOUTSELECT_CS4_SELECT 0x00000300
+#define BF_BCH_LAYOUTSELECT_CS4_SELECT(v) \
+ (((v) << 8) & BM_BCH_LAYOUTSELECT_CS4_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS3_SELECT 6
+#define BM_BCH_LAYOUTSELECT_CS3_SELECT 0x000000C0
+#define BF_BCH_LAYOUTSELECT_CS3_SELECT(v) \
+ (((v) << 6) & BM_BCH_LAYOUTSELECT_CS3_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS2_SELECT 4
+#define BM_BCH_LAYOUTSELECT_CS2_SELECT 0x00000030
+#define BF_BCH_LAYOUTSELECT_CS2_SELECT(v) \
+ (((v) << 4) & BM_BCH_LAYOUTSELECT_CS2_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS1_SELECT 2
+#define BM_BCH_LAYOUTSELECT_CS1_SELECT 0x0000000C
+#define BF_BCH_LAYOUTSELECT_CS1_SELECT(v) \
+ (((v) << 2) & BM_BCH_LAYOUTSELECT_CS1_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS0_SELECT 0
+#define BM_BCH_LAYOUTSELECT_CS0_SELECT 0x00000003
+#define BF_BCH_LAYOUTSELECT_CS0_SELECT(v) \
+ (((v) << 0) & BM_BCH_LAYOUTSELECT_CS0_SELECT)
+
+#define HW_BCH_FLASH0LAYOUT0 (0x00000080)
+
+#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH0LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH0LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH0LAYOUT0_META_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH0LAYOUT0_ECC0 11
+#define BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F800
+#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \
+ (((v) << 11) & BM_BCH_FLASH0LAYOUT0_ECC0)
+#else
+#define BP_BCH_FLASH0LAYOUT0_ECC0 12
+#define BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH0LAYOUT0_ECC0)
+#endif
+#define BV_BCH_FLASH0LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC20 0xA
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC22 0xB
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC24 0xC
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC26 0xD
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC28 0xE
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC30 0xF
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC32 0x10
+#define BM_BCH_FLASH0LAYOUT0_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+
+#define HW_BCH_FLASH0LAYOUT1 (0x00000090)
+
+#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH0LAYOUT1_ECCN 11
+#define BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F800
+#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \
+ (((v) << 11) & BM_BCH_FLASH0LAYOUT1_ECCN)
+#else
+#define BP_BCH_FLASH0LAYOUT1_ECCN 12
+#define BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH0LAYOUT1_ECCN)
+#endif
+#define BV_BCH_FLASH0LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC20 0xA
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC22 0xB
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC24 0xC
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC26 0xD
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC28 0xE
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC30 0xF
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC32 0x10
+#define BM_BCH_FLASH0LAYOUT1_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+
+#define HW_BCH_FLASH1LAYOUT0 (0x000000a0)
+
+#define BP_BCH_FLASH1LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH1LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH1LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH1LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH1LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH1LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH1LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH1LAYOUT0_META_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH1LAYOUT0_ECC0 11
+#define BM_BCH_FLASH1LAYOUT0_ECC0 0x0000F800
+#define BF_BCH_FLASH1LAYOUT0_ECC0(v) \
+ (((v) << 11) & BM_BCH_FLASH1LAYOUT0_ECC0)
+#else
+#define BP_BCH_FLASH1LAYOUT0_ECC0 12
+#define BM_BCH_FLASH1LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH1LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH1LAYOUT0_ECC0)
+#endif
+#define BV_BCH_FLASH1LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC20 0xA
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC22 0xB
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC24 0xC
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC26 0xD
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC28 0xE
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC30 0xF
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC32 0x10
+#define BM_BCH_FLASH1LAYOUT0_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH1LAYOUT0_DATA0_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH1LAYOUT0_DATA0_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH1LAYOUT0_DATA0_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH1LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH1LAYOUT0_DATA0_SIZE)
+
+#define HW_BCH_FLASH1LAYOUT1 (0x000000b0)
+
+#define BP_BCH_FLASH1LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH1LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH1LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH1LAYOUT1_PAGE_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH1LAYOUT1_ECCN 11
+#define BM_BCH_FLASH1LAYOUT1_ECCN 0x0000F800
+#define BF_BCH_FLASH1LAYOUT1_ECCN(v) \
+ (((v) << 11) & BM_BCH_FLASH1LAYOUT1_ECCN)
+#else
+#define BP_BCH_FLASH1LAYOUT1_ECCN 12
+#define BM_BCH_FLASH1LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH1LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH1LAYOUT1_ECCN)
+#endif
+#define BV_BCH_FLASH1LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC20 0xA
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC22 0xB
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC24 0xC
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC26 0xD
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC28 0xE
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC30 0xF
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC32 0x10
+#define BM_BCH_FLASH1LAYOUT1_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH1LAYOUT1_DATAN_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH1LAYOUT1_DATAN_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH1LAYOUT1_DATAN_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH1LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH1LAYOUT1_DATAN_SIZE)
+
+#define HW_BCH_FLASH2LAYOUT0 (0x000000c0)
+
+#define BP_BCH_FLASH2LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH2LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH2LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH2LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH2LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH2LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH2LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH2LAYOUT0_META_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH2LAYOUT0_ECC0 11
+#define BM_BCH_FLASH2LAYOUT0_ECC0 0x0000F800
+#define BF_BCH_FLASH2LAYOUT0_ECC0(v) \
+ (((v) << 11) & BM_BCH_FLASH2LAYOUT0_ECC0)
+#else
+#define BP_BCH_FLASH2LAYOUT0_ECC0 12
+#define BM_BCH_FLASH2LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH2LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH2LAYOUT0_ECC0)
+#endif
+#define BV_BCH_FLASH2LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC20 0xA
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC22 0xB
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC24 0xC
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC26 0xD
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC28 0xE
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC30 0xF
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC32 0x10
+#define BM_BCH_FLASH2LAYOUT0_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH2LAYOUT0_DATA0_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH2LAYOUT0_DATA0_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH2LAYOUT0_DATA0_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH2LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH2LAYOUT0_DATA0_SIZE)
+
+#define HW_BCH_FLASH2LAYOUT1 (0x000000d0)
+
+#define BP_BCH_FLASH2LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH2LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH2LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH2LAYOUT1_PAGE_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH2LAYOUT1_ECCN 11
+#define BM_BCH_FLASH2LAYOUT1_ECCN 0x0000F800
+#define BF_BCH_FLASH2LAYOUT1_ECCN(v) \
+ (((v) << 11) & BM_BCH_FLASH2LAYOUT1_ECCN)
+#else
+#define BP_BCH_FLASH2LAYOUT1_ECCN 12
+#define BM_BCH_FLASH2LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH2LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH2LAYOUT1_ECCN)
+#endif
+#define BV_BCH_FLASH2LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC20 0xA
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC22 0xB
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC24 0xC
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC26 0xD
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC28 0xE
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC30 0xF
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC32 0x10
+#define BM_BCH_FLASH2LAYOUT1_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH2LAYOUT1_DATAN_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH2LAYOUT1_DATAN_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH2LAYOUT1_DATAN_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH2LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH2LAYOUT1_DATAN_SIZE)
+
+#define HW_BCH_FLASH3LAYOUT0 (0x000000e0)
+
+#define BP_BCH_FLASH3LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH3LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH3LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH3LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH3LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH3LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH3LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH3LAYOUT0_META_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH3LAYOUT0_ECC0 11
+#define BM_BCH_FLASH3LAYOUT0_ECC0 0x0000F800
+#define BF_BCH_FLASH3LAYOUT0_ECC0(v) \
+ (((v) << 11) & BM_BCH_FLASH3LAYOUT0_ECC0)
+#else
+#define BP_BCH_FLASH3LAYOUT0_ECC0 12
+#define BM_BCH_FLASH3LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH3LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH3LAYOUT0_ECC0)
+#endif
+#define BV_BCH_FLASH3LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC20 0xA
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC22 0xB
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC24 0xC
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC26 0xD
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC28 0xE
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC30 0xF
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC32 0x10
+#define BM_BCH_FLASH3LAYOUT0_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH3LAYOUT0_DATA0_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH3LAYOUT0_DATA0_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH3LAYOUT0_DATA0_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH3LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH3LAYOUT0_DATA0_SIZE)
+
+#define HW_BCH_FLASH3LAYOUT1 (0x000000f0)
+
+#define BP_BCH_FLASH3LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH3LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH3LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH3LAYOUT1_PAGE_SIZE)
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_FLASH3LAYOUT1_ECCN 11
+#define BM_BCH_FLASH3LAYOUT1_ECCN 0x0000F800
+#define BF_BCH_FLASH3LAYOUT1_ECCN(v) \
+ (((v) << 11) & BM_BCH_FLASH3LAYOUT1_ECCN)
+#else
+#define BP_BCH_FLASH3LAYOUT1_ECCN 12
+#define BM_BCH_FLASH3LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH3LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH3LAYOUT1_ECCN)
+#endif
+#define BV_BCH_FLASH3LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC20 0xA
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC22 0xB
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC24 0xC
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC26 0xD
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC28 0xE
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC30 0xF
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC32 0x10
+#define BM_BCH_FLASH3LAYOUT1_GF13_0_GF14_1 0x00000400
+#define BP_BCH_FLASH3LAYOUT1_DATAN_SIZE 0
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BM_BCH_FLASH3LAYOUT1_DATAN_SIZE 0x000003FF
+#else
+#define BM_BCH_FLASH3LAYOUT1_DATAN_SIZE 0x00000FFF
+#endif
+#define BF_BCH_FLASH3LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH3LAYOUT1_DATAN_SIZE)
+
+#define HW_BCH_DEBUG0 (0x00000100)
+#define HW_BCH_DEBUG0_SET (0x00000104)
+#define HW_BCH_DEBUG0_CLR (0x00000108)
+#define HW_BCH_DEBUG0_TOG (0x0000010c)
+
+#if defined(CONFIG_GPMI_NFC_V2)
+#define BP_BCH_DEBUG0_RSVD1 25
+#define BM_BCH_DEBUG0_RSVD1 0xFE000000
+#define BF_BCH_DEBUG0_RSVD1(v) \
+ (((v) << 25) & BM_BCH_DEBUG0_RSVD1)
+#else
+#define BP_BCH_DEBUG0_RSVD1 27
+#define BM_BCH_DEBUG0_RSVD1 0xF8000000
+#define BF_BCH_DEBUG0_RSVD1(v) \
+ (((v) << 27) & BM_BCH_DEBUG0_RSVD1)
+#define BM_BCH_DEBUG0_ROM_BIST_ENABLE 0x04000000
+#define BM_BCH_DEBUG0_ROM_BIST_COMPLETE 0x02000000
+#endif
+#define BP_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 16
+#define BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 0x01FF0000
+#define BF_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL(v) \
+ (((v) << 16) & BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL)
+#define BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__NORMAL 0x0
+#define BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__TEST_MODE 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_SHIFT_SYND 0x00008000
+#define BM_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG 0x00004000
+#define BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__DATA 0x1
+#define BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__AUX 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_MODE4K 0x00002000
+#define BV_BCH_DEBUG0_KES_DEBUG_MODE4K__4k 0x1
+#define BV_BCH_DEBUG0_KES_DEBUG_MODE4K__2k 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_KICK 0x00001000
+#define BM_BCH_DEBUG0_KES_STANDALONE 0x00000800
+#define BV_BCH_DEBUG0_KES_STANDALONE__NORMAL 0x0
+#define BV_BCH_DEBUG0_KES_STANDALONE__TEST_MODE 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_STEP 0x00000400
+#define BM_BCH_DEBUG0_KES_DEBUG_STALL 0x00000200
+#define BV_BCH_DEBUG0_KES_DEBUG_STALL__NORMAL 0x0
+#define BV_BCH_DEBUG0_KES_DEBUG_STALL__WAIT 0x1
+#define BM_BCH_DEBUG0_BM_KES_TEST_BYPASS 0x00000100
+#define BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__NORMAL 0x0
+#define BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__TEST_MODE 0x1
+#define BP_BCH_DEBUG0_RSVD0 6
+#define BM_BCH_DEBUG0_RSVD0 0x000000C0
+#define BF_BCH_DEBUG0_RSVD0(v) \
+ (((v) << 6) & BM_BCH_DEBUG0_RSVD0)
+#define BP_BCH_DEBUG0_DEBUG_REG_SELECT 0
+#define BM_BCH_DEBUG0_DEBUG_REG_SELECT 0x0000003F
+#define BF_BCH_DEBUG0_DEBUG_REG_SELECT(v) \
+ (((v) << 0) & BM_BCH_DEBUG0_DEBUG_REG_SELECT)
+
+#define HW_BCH_DBGKESREAD (0x00000110)
+
+#define BP_BCH_DBGKESREAD_VALUES 0
+#define BM_BCH_DBGKESREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGKESREAD_VALUES(v) (v)
+
+#define HW_BCH_DBGCSFEREAD (0x00000120)
+
+#define BP_BCH_DBGCSFEREAD_VALUES 0
+#define BM_BCH_DBGCSFEREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGCSFEREAD_VALUES(v) (v)
+
+#define HW_BCH_DBGSYNDGENREAD (0x00000130)
+
+#define BP_BCH_DBGSYNDGENREAD_VALUES 0
+#define BM_BCH_DBGSYNDGENREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGSYNDGENREAD_VALUES(v) (v)
+
+#define HW_BCH_DBGAHBMREAD (0x00000140)
+
+#define BP_BCH_DBGAHBMREAD_VALUES 0
+#define BM_BCH_DBGAHBMREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGAHBMREAD_VALUES(v) (v)
+
+#define HW_BCH_BLOCKNAME (0x00000150)
+
+#define BP_BCH_BLOCKNAME_NAME 0
+#define BM_BCH_BLOCKNAME_NAME 0xFFFFFFFF
+#define BF_BCH_BLOCKNAME_NAME(v) (v)
+
+#define HW_BCH_VERSION (0x00000160)
+
+#define BP_BCH_VERSION_MAJOR 24
+#define BM_BCH_VERSION_MAJOR 0xFF000000
+#define BF_BCH_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_BCH_VERSION_MAJOR)
+#define BP_BCH_VERSION_MINOR 16
+#define BM_BCH_VERSION_MINOR 0x00FF0000
+#define BF_BCH_VERSION_MINOR(v) \
+ (((v) << 16) & BM_BCH_VERSION_MINOR)
+#define BP_BCH_VERSION_STEP 0
+#define BM_BCH_VERSION_STEP 0x0000FFFF
+#define BF_BCH_VERSION_STEP(v) \
+ (((v) << 0) & BM_BCH_VERSION_STEP)
+#endif /* __ARCH_ARM___BCH_H */
diff --git a/drivers/mtd/nand/gpmi_nfc_gpmi.h b/drivers/mtd/nand/gpmi_nfc_gpmi.h
new file mode 100644
index 0000000..6fbde85
--- /dev/null
+++ b/drivers/mtd/nand/gpmi_nfc_gpmi.h
@@ -0,0 +1,1118 @@
+/*
+ * Freescale GPMI Register Definitions
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.19
+ * Template revision: 1.3
+ */
+
+#ifndef __GPMI_NFC_GPMI_REGS_H
+#define __GPMI_NFC_GPMI_REGS_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/compat.h>
+#include <linux/err.h>
+#include <common.h>
+
+#define HW_GPMI_CTRL0 (0x00000000)
+#define HW_GPMI_CTRL0_SET (0x00000004)
+#define HW_GPMI_CTRL0_CLR (0x00000008)
+#define HW_GPMI_CTRL0_TOG (0x0000000c)
+
+#define BM_GPMI_CTRL0_SFTRST 0x80000000
+#define BV_GPMI_CTRL0_SFTRST__RUN 0x0
+#define BV_GPMI_CTRL0_SFTRST__RESET 0x1
+#define BM_GPMI_CTRL0_CLKGATE 0x40000000
+#define BV_GPMI_CTRL0_CLKGATE__RUN 0x0
+#define BV_GPMI_CTRL0_CLKGATE__NO_CLKS 0x1
+#define BM_GPMI_CTRL0_RUN 0x20000000
+#define BV_GPMI_CTRL0_RUN__IDLE 0x0
+#define BV_GPMI_CTRL0_RUN__BUSY 0x1
+#define BM_GPMI_CTRL0_DEV_IRQ_EN 0x10000000
+#if defined(CONFIG_GPMI_NFC_V0)
+#define BM_GPMI_CTRL0_TIMEOUT_IRQ_EN 0x08000000
+#else
+#define BM_GPMI_CTRL0_LOCK_CS 0x08000000
+#define BV_GPMI_CTRL0_LOCK_CS__DISABLED 0x0
+#define BV_GPMI_CTRL0_LOCK_CS__ENABLED 0x1
+#endif
+#define BM_GPMI_CTRL0_UDMA 0x04000000
+#define BV_GPMI_CTRL0_UDMA__DISABLED 0x0
+#define BV_GPMI_CTRL0_UDMA__ENABLED 0x1
+#define BP_GPMI_CTRL0_COMMAND_MODE 24
+#define BM_GPMI_CTRL0_COMMAND_MODE 0x03000000
+#define BF_GPMI_CTRL0_COMMAND_MODE(v) \
+ (((v) << 24) & BM_GPMI_CTRL0_COMMAND_MODE)
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3
+#define BM_GPMI_CTRL0_WORD_LENGTH 0x00800000
+#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0
+#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1
+#if defined(CONFIG_GPMI_NFC_V0)
+#define BM_GPMI_CTRL0_LOCK_CS 0x00400000
+#define BV_GPMI_CTRL0_LOCK_CS__DISABLED 0x0
+#define BV_GPMI_CTRL0_LOCK_CS__ENABLED 0x1
+#endif
+#define BP_GPMI_CTRL0_CS 20
+#define BM_GPMI_CTRL0_CS 0x00700000
+#define BF_GPMI_CTRL0_CS(v) \
+ (((v) << 20) & BM_GPMI_CTRL0_CS)
+#define BP_GPMI_CTRL0_ADDRESS 17
+#define BM_GPMI_CTRL0_ADDRESS 0x000E0000
+#define BF_GPMI_CTRL0_ADDRESS(v) \
+ (((v) << 17) & BM_GPMI_CTRL0_ADDRESS)
+#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0
+#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1
+#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2
+#define BM_GPMI_CTRL0_ADDRESS_INCREMENT 0x00010000
+#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0
+#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1
+#define BP_GPMI_CTRL0_XFER_COUNT 0
+#define BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF
+#define BF_GPMI_CTRL0_XFER_COUNT(v) \
+ (((v) << 0) & BM_GPMI_CTRL0_XFER_COUNT)
+
+#define HW_GPMI_COMPARE (0x00000010)
+
+#define BP_GPMI_COMPARE_MASK 16
+#define BM_GPMI_COMPARE_MASK 0xFFFF0000
+#define BF_GPMI_COMPARE_MASK(v) \
+ (((v) << 16) & BM_GPMI_COMPARE_MASK)
+#define BP_GPMI_COMPARE_REFERENCE 0
+#define BM_GPMI_COMPARE_REFERENCE 0x0000FFFF
+#define BF_GPMI_COMPARE_REFERENCE(v) \
+ (((v) << 0) & BM_GPMI_COMPARE_REFERENCE)
+
+#define HW_GPMI_ECCCTRL (0x00000020)
+#define HW_GPMI_ECCCTRL_SET (0x00000024)
+#define HW_GPMI_ECCCTRL_CLR (0x00000028)
+#define HW_GPMI_ECCCTRL_TOG (0x0000002c)
+
+#define BP_GPMI_ECCCTRL_HANDLE 16
+#define BM_GPMI_ECCCTRL_HANDLE 0xFFFF0000
+#define BF_GPMI_ECCCTRL_HANDLE(v) \
+ (((v) << 16) & BM_GPMI_ECCCTRL_HANDLE)
+#define BM_GPMI_ECCCTRL_RSVD2 0x00008000
+#define BP_GPMI_ECCCTRL_ECC_CMD 13
+#define BM_GPMI_ECCCTRL_ECC_CMD 0x00006000
+#define BF_GPMI_ECCCTRL_ECC_CMD(v) \
+ (((v) << 13) & BM_GPMI_ECCCTRL_ECC_CMD)
+#if defined(CONFIG_GPMI_NFC_V0)
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT 0x0
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT 0x1
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT 0x2
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT 0x3
+#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE 0x0
+#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE 0x1
+#else
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE 0x0
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE 0x1
+#define BV_GPMI_ECCCTRL_ECC_CMD__RESERVE2 0x2
+#define BV_GPMI_ECCCTRL_ECC_CMD__RESERVE3 0x3
+#endif
+#define BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000
+#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1
+#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0
+#define BP_GPMI_ECCCTRL_RSVD1 9
+#define BM_GPMI_ECCCTRL_RSVD1 0x00000E00
+#define BF_GPMI_ECCCTRL_RSVD1(v) \
+ (((v) << 9) & BM_GPMI_ECCCTRL_RSVD1)
+#define BP_GPMI_ECCCTRL_BUFFER_MASK 0
+#define BM_GPMI_ECCCTRL_BUFFER_MASK 0x000001FF
+#define BF_GPMI_ECCCTRL_BUFFER_MASK(v) \
+ (((v) << 0) & BM_GPMI_ECCCTRL_BUFFER_MASK)
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF
+#if defined(CONFIG_GPMI_NFC_V0)
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY 0x100
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER7 0x080
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER6 0x040
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER5 0x020
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER4 0x010
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER3 0x008
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER2 0x004
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER1 0x002
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER0 0x001
+#endif
+
+#define HW_GPMI_ECCCOUNT (0x00000030)
+
+#define BP_GPMI_ECCCOUNT_RSVD2 16
+#define BM_GPMI_ECCCOUNT_RSVD2 0xFFFF0000
+#define BF_GPMI_ECCCOUNT_RSVD2(v) \
+ (((v) << 16) & BM_GPMI_ECCCOUNT_RSVD2)
+#define BP_GPMI_ECCCOUNT_COUNT 0
+#define BM_GPMI_ECCCOUNT_COUNT 0x0000FFFF
+#define BF_GPMI_ECCCOUNT_COUNT(v) \
+ (((v) << 0) & BM_GPMI_ECCCOUNT_COUNT)
+
+#define HW_GPMI_PAYLOAD (0x00000040)
+
+#define BP_GPMI_PAYLOAD_ADDRESS 2
+#define BM_GPMI_PAYLOAD_ADDRESS 0xFFFFFFFC
+#define BF_GPMI_PAYLOAD_ADDRESS(v) \
+ (((v) << 2) & BM_GPMI_PAYLOAD_ADDRESS)
+#define BP_GPMI_PAYLOAD_RSVD0 0
+#define BM_GPMI_PAYLOAD_RSVD0 0x00000003
+#define BF_GPMI_PAYLOAD_RSVD0(v) \
+ (((v) << 0) & BM_GPMI_PAYLOAD_RSVD0)
+
+#define HW_GPMI_AUXILIARY (0x00000050)
+
+#define BP_GPMI_AUXILIARY_ADDRESS 2
+#define BM_GPMI_AUXILIARY_ADDRESS 0xFFFFFFFC
+#define BF_GPMI_AUXILIARY_ADDRESS(v) \
+ (((v) << 2) & BM_GPMI_AUXILIARY_ADDRESS)
+#define BP_GPMI_AUXILIARY_RSVD0 0
+#define BM_GPMI_AUXILIARY_RSVD0 0x00000003
+#define BF_GPMI_AUXILIARY_RSVD0(v) \
+ (((v) << 0) & BM_GPMI_AUXILIARY_RSVD0)
+
+#define HW_GPMI_CTRL1 (0x00000060)
+#define HW_GPMI_CTRL1_SET (0x00000064)
+#define HW_GPMI_CTRL1_CLR (0x00000068)
+#define HW_GPMI_CTRL1_TOG (0x0000006c)
+
+#if defined(CONFIG_GPMI_NFC_V0)
+
+#define BP_GPMI_CTRL1_RSVD2 24
+#define BM_GPMI_CTRL1_RSVD2 0xFF000000
+#define BF_GPMI_CTRL1_RSVD2(v) \
+ (((v) << 24) & BM_GPMI_CTRL1_RSVD2)
+#define BM_GPMI_CTRL1_CE3_SEL 0x00800000
+#define BM_GPMI_CTRL1_CE2_SEL 0x00400000
+#define BM_GPMI_CTRL1_CE1_SEL 0x00200000
+#define BM_GPMI_CTRL1_CE0_SEL 0x00100000
+#define BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000
+#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define BP_GPMI_CTRL1_GPMI_MODE 0
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define BP_GPMI_CTRL1_RDN_DELAY 12
+#define BM_GPMI_CTRL1_BCH_MODE 0x00040000
+#define BP_GPMI_CTRL1_DLL_ENABLE 17
+
+#else
+
+#if defined(CONFIG_GPMI_NFC_V1)
+#define BP_GPMI_CTRL1_RSVD2 25
+#define BM_GPMI_CTRL1_RSVD2 0xFE000000
+#define BF_GPMI_CTRL1_RSVD2(v) \
+ (((v) << 25) & BM_GPMI_CTRL1_RSVD2)
+#elif defined(CONFIG_GPMI_NFC_V2)
+#define BM_GPMI_CTRL1_DEV_CLK_STOP 0x80000000
+#define BM_GPMI_CTRL1_SSYNC_CLK_STOP 0x40000000
+#define BM_GPMI_CTRL1_WRITE_CLK_STOP 0x20000000
+#define BM_GPMI_CTRL1_TOGGLE_MODE 0x10000000
+#define BM_GPMI_CTRL1_GPMI_CLK_DIV2_EN 0x08000000
+#define BM_GPMI_CTRL1_UPDATE_CS 0x04000000
+#define BM_GPMI_CTRL1_SSYNCMODE 0x02000000
+#define BV_GPMI_CTRL1_SSYNCMODE__ASYNC 0x0
+#define BV_GPMI_CTRL1_SSYNCMODE__SSYNC 0x1
+#endif
+#define BM_GPMI_CTRL1_DECOUPLE_CS 0x01000000
+#define BP_GPMI_CTRL1_WRN_DLY_SEL 22
+#define BM_GPMI_CTRL1_WRN_DLY_SEL 0x00C00000
+#define BF_GPMI_CTRL1_WRN_DLY_SEL(v) \
+ (((v) << 22) & BM_GPMI_CTRL1_WRN_DLY_SEL)
+#define BM_GPMI_CTRL1_RSVD1 0x00200000
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ_EN 0x00100000
+#define BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000
+#define BM_GPMI_CTRL1_BCH_MODE 0x00040000
+
+#endif
+
+#define BP_GPMI_CTRL1_DLL_ENABLE 17
+#define BM_GPMI_CTRL1_DLL_ENABLE 0x00020000
+#define BP_GPMI_CTRL1_HALF_PERIOD 16
+#define BM_GPMI_CTRL1_HALF_PERIOD 0x00010000
+#define BP_GPMI_CTRL1_RDN_DELAY 12
+#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define BF_GPMI_CTRL1_RDN_DELAY(v) \
+ (((v) << 12) & BM_GPMI_CTRL1_RDN_DELAY)
+#define BM_GPMI_CTRL1_DMA2ECC_MODE 0x00000800
+#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define BM_GPMI_CTRL1_BURST_EN 0x00000100
+#if defined(CONFIG_GPMI_NFC_V0)
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY3 0x00000080
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY2 0x00000040
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY1 0x00000020
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY0 0x00000010
+#else
+#define BM_GPMI_CTRL1_ABORT_WAIT_REQUEST 0x00000080
+#define BP_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL 4
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL 0x00000070
+#define BF_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL(v) \
+ (((v) << 4) & BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL)
+#endif
+#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0
+#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1
+#define BM_GPMI_CTRL1_CAMERA_MODE 0x00000002
+#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
+#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
+
+#define HW_GPMI_TIMING0 (0x00000070)
+
+#define BP_GPMI_TIMING0_RSVD1 24
+#define BM_GPMI_TIMING0_RSVD1 0xFF000000
+#define BF_GPMI_TIMING0_RSVD1(v) \
+ (((v) << 24) & BM_GPMI_TIMING0_RSVD1)
+#define BP_GPMI_TIMING0_ADDRESS_SETUP 16
+#define BM_GPMI_TIMING0_ADDRESS_SETUP 0x00FF0000
+#define BF_GPMI_TIMING0_ADDRESS_SETUP(v) \
+ (((v) << 16) & BM_GPMI_TIMING0_ADDRESS_SETUP)
+#define BP_GPMI_TIMING0_DATA_HOLD 8
+#define BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00
+#define BF_GPMI_TIMING0_DATA_HOLD(v) \
+ (((v) << 8) & BM_GPMI_TIMING0_DATA_HOLD)
+#define BP_GPMI_TIMING0_DATA_SETUP 0
+#define BM_GPMI_TIMING0_DATA_SETUP 0x000000FF
+#define BF_GPMI_TIMING0_DATA_SETUP(v) \
+ (((v) << 0) & BM_GPMI_TIMING0_DATA_SETUP)
+
+#define HW_GPMI_TIMING1 (0x00000080)
+
+#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
+#define BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(v) \
+ (((v) << 16) & BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT)
+#define BP_GPMI_TIMING1_RSVD1 0
+#define BM_GPMI_TIMING1_RSVD1 0x0000FFFF
+#define BF_GPMI_TIMING1_RSVD1(v) \
+ (((v) << 0) & BM_GPMI_TIMING1_RSVD1)
+
+#define HW_GPMI_TIMING2 (0x00000090)
+
+#if defined(CONFIG_GPMI_NFC_V0)
+
+#define BP_GPMI_TIMING2_UDMA_TRP 24
+#define BM_GPMI_TIMING2_UDMA_TRP 0xFF000000
+#define BF_GPMI_TIMING2_UDMA_TRP(v) \
+ (((v) << 24) & BM_GPMI_TIMING2_UDMA_TRP)
+#define BP_GPMI_TIMING2_UDMA_ENV 16
+#define BM_GPMI_TIMING2_UDMA_ENV 0x00FF0000
+#define BF_GPMI_TIMING2_UDMA_ENV(v) \
+ (((v) << 16) & BM_GPMI_TIMING2_UDMA_ENV)
+#define BP_GPMI_TIMING2_UDMA_HOLD 8
+#define BM_GPMI_TIMING2_UDMA_HOLD 0x0000FF00
+#define BF_GPMI_TIMING2_UDMA_HOLD(v) \
+ (((v) << 8) & BM_GPMI_TIMING2_UDMA_HOLD)
+#define BP_GPMI_TIMING2_UDMA_SETUP 0
+#define BM_GPMI_TIMING2_UDMA_SETUP 0x000000FF
+#define BF_GPMI_TIMING2_UDMA_SETUP(v) \
+ (((v) << 0) & BM_GPMI_TIMING2_UDMA_SETUP)
+
+#else
+
+#define BP_GPMI_TIMING2_RSVD1 27
+#define BM_GPMI_TIMING2_RSVD1 0xF8000000
+#define BF_GPMI_TIMING2_RSVD1(v) \
+ (((v) << 27) & BM_GPMI_TIMING2_RSVD1)
+#define BP_GPMI_TIMING2_READ_LATENCY 24
+#define BM_GPMI_TIMING2_READ_LATENCY 0x07000000
+#define BF_GPMI_TIMING2_READ_LATENCY(v) \
+ (((v) << 24) & BM_GPMI_TIMING2_READ_LATENCY)
+#define BP_GPMI_TIMING2_RSVD0 21
+#define BM_GPMI_TIMING2_RSVD0 0x00E00000
+#define BF_GPMI_TIMING2_RSVD0(v) \
+ (((v) << 21) & BM_GPMI_TIMING2_RSVD0)
+#define BP_GPMI_TIMING2_CE_DELAY 16
+#define BM_GPMI_TIMING2_CE_DELAY 0x001F0000
+#define BF_GPMI_TIMING2_CE_DELAY(v) \
+ (((v) << 16) & BM_GPMI_TIMING2_CE_DELAY)
+#define BP_GPMI_TIMING2_PREAMBLE_DELAY 12
+#define BM_GPMI_TIMING2_PREAMBLE_DELAY 0x0000F000
+#define BF_GPMI_TIMING2_PREAMBLE_DELAY(v) \
+ (((v) << 12) & BM_GPMI_TIMING2_PREAMBLE_DELAY)
+#define BP_GPMI_TIMING2_POSTAMBLE_DELAY 8
+#define BM_GPMI_TIMING2_POSTAMBLE_DELAY 0x00000F00
+#define BF_GPMI_TIMING2_POSTAMBLE_DELAY(v) \
+ (((v) << 8) & BM_GPMI_TIMING2_POSTAMBLE_DELAY)
+#define BP_GPMI_TIMING2_CMDADD_PAUSE 4
+#define BM_GPMI_TIMING2_CMDADD_PAUSE 0x000000F0
+#define BF_GPMI_TIMING2_CMDADD_PAUSE(v) \
+ (((v) << 4) & BM_GPMI_TIMING2_CMDADD_PAUSE)
+#define BP_GPMI_TIMING2_DATA_PAUSE 0
+#define BM_GPMI_TIMING2_DATA_PAUSE 0x0000000F
+#define BF_GPMI_TIMING2_DATA_PAUSE(v) \
+ (((v) << 0) & BM_GPMI_TIMING2_DATA_PAUSE)
+
+#endif
+
+#define HW_GPMI_DATA (0x000000a0)
+
+#define BP_GPMI_DATA_DATA 0
+#define BM_GPMI_DATA_DATA 0xFFFFFFFF
+#define BF_GPMI_DATA_DATA(v) (v)
+
+#define HW_GPMI_STAT (0x000000b0)
+
+#if defined(CONFIG_GPMI_NFC_V0)
+
+#define BM_GPMI_STAT_PRESENT 0x80000000
+#define BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0
+#define BV_GPMI_STAT_PRESENT__AVAILABLE 0x1
+#define BP_GPMI_STAT_RSVD1 12
+#define BM_GPMI_STAT_RSVD1 0x7FFFF000
+#define BF_GPMI_STAT_RSVD1(v) \
+ (((v) << 12) & BM_GPMI_STAT_RSVD1)
+#define BP_GPMI_STAT_RDY_TIMEOUT 8
+#define BM_GPMI_STAT_RDY_TIMEOUT 0x00000F00
+#define BF_GPMI_STAT_RDY_TIMEOUT(v) \
+ (((v) << 8) & BM_GPMI_STAT_RDY_TIMEOUT)
+#define BM_GPMI_STAT_ATA_IRQ 0x00000080
+#define BM_GPMI_STAT_INVALID_BUFFER_MASK 0x00000040
+#define BM_GPMI_STAT_FIFO_EMPTY 0x00000020
+#define BV_GPMI_STAT_FIFO_EMPTY__NOT_EMPTY 0x0
+#define BV_GPMI_STAT_FIFO_EMPTY__EMPTY 0x1
+#define BM_GPMI_STAT_FIFO_FULL 0x00000010
+#define BV_GPMI_STAT_FIFO_FULL__NOT_FULL 0x0
+#define BV_GPMI_STAT_FIFO_FULL__FULL 0x1
+#define BM_GPMI_STAT_DEV3_ERROR 0x00000008
+#define BM_GPMI_STAT_DEV2_ERROR 0x00000004
+#define BM_GPMI_STAT_DEV1_ERROR 0x00000002
+#define BM_GPMI_STAT_DEERROR 0x00000001
+
+#else
+
+#define BP_GPMI_STAT_READY_BUSY 24
+#define BM_GPMI_STAT_READY_BUSY 0xFF000000
+#define BF_GPMI_STAT_READY_BUSY(v) \
+ (((v) << 24) & BM_GPMI_STAT_READY_BUSY)
+#define BP_GPMI_STAT_RDY_TIMEOUT 16
+#define BM_GPMI_STAT_RDY_TIMEOUT 0x00FF0000
+#define BF_GPMI_STAT_RDY_TIMEOUT(v) \
+ (((v) << 16) & BM_GPMI_STAT_RDY_TIMEOUT)
+#define BM_GPMI_STAT_DEV7_ERROR 0x00008000
+#define BM_GPMI_STAT_DEV6_ERROR 0x00004000
+#define BM_GPMI_STAT_DEV5_ERROR 0x00002000
+#define BM_GPMI_STAT_DEV4_ERROR 0x00001000
+#define BM_GPMI_STAT_DEV3_ERROR 0x00000800
+#define BM_GPMI_STAT_DEV2_ERROR 0x00000400
+#define BM_GPMI_STAT_DEV1_ERROR 0x00000200
+#define BM_GPMI_STAT_DEV0_ERROR 0x00000100
+#define BP_GPMI_STAT_RSVD1 5
+#define BM_GPMI_STAT_RSVD1 0x000000E0
+#define BF_GPMI_STAT_RSVD1(v) \
+ (((v) << 5) & BM_GPMI_STAT_RSVD1)
+#define BM_GPMI_STAT_ATA_IRQ 0x00000010
+#define BM_GPMI_STAT_INVALID_BUFFER_MASK 0x00000008
+#define BM_GPMI_STAT_FIFO_EMPTY 0x00000004
+#define BV_GPMI_STAT_FIFO_EMPTY__NOT_EMPTY 0x0
+#define BV_GPMI_STAT_FIFO_EMPTY__EMPTY 0x1
+#define BM_GPMI_STAT_FIFO_FULL 0x00000002
+#define BV_GPMI_STAT_FIFO_FULL__NOT_FULL 0x0
+#define BV_GPMI_STAT_FIFO_FULL__FULL 0x1
+#define BM_GPMI_STAT_PRESENT 0x00000001
+#define BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0
+#define BV_GPMI_STAT_PRESENT__AVAILABLE 0x1
+
+#endif
+
+#define HW_GPMI_DEBUG (0x000000c0)
+
+#if defined(CONFIG_GPMI_NFC_V0)
+
+#define BM_GPMI_DEBUG_READY3 0x80000000
+#define BM_GPMI_DEBUG_READY2 0x40000000
+#define BM_GPMI_DEBUG_READY1 0x20000000
+#define BM_GPMI_DEBUG_READY0 0x10000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END3 0x08000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END2 0x04000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END1 0x02000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END0 0x01000000
+#define BM_GPMI_DEBUG_SENSE3 0x00800000
+#define BM_GPMI_DEBUG_SENSE2 0x00400000
+#define BM_GPMI_DEBUG_SENSE1 0x00200000
+#define BM_GPMI_DEBUG_SENSE0 0x00100000
+#define BM_GPMI_DEBUG_DMAREQ3 0x00080000
+#define BM_GPMI_DEBUG_DMAREQ2 0x00040000
+#define BM_GPMI_DEBUG_DMAREQ1 0x00020000
+#define BM_GPMI_DEBUG_DMAREQ0 0x00010000
+#define BP_GPMI_DEBUG_CMD_END 12
+#define BM_GPMI_DEBUG_CMD_END 0x0000F000
+#define BF_GPMI_DEBUG_CMD_END(v) \
+ (((v) << 12) & BM_GPMI_DEBUG_CMD_END)
+#define BP_GPMI_DEBUG_UDMA_STATE 8
+#define BM_GPMI_DEBUG_UDMA_STATE 0x00000F00
+#define BF_GPMI_DEBUG_UDMA_STATE(v) \
+ (((v) << 8) & BM_GPMI_DEBUG_UDMA_STATE)
+#define BM_GPMI_DEBUG_BUSY 0x00000080
+#define BV_GPMI_DEBUG_BUSY__DISABLED 0x0
+#define BV_GPMI_DEBUG_BUSY__ENABLED 0x1
+#define BP_GPMI_DEBUG_PIN_STATE 4
+#define BM_GPMI_DEBUG_PIN_STATE 0x00000070
+#define BF_GPMI_DEBUG_PIN_STATE(v) \
+ (((v) << 4) & BM_GPMI_DEBUG_PIN_STATE)
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_IDLE 0x0
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_BYTCNT 0x1
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_ADDR 0x2
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_STALL 0x3
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_STROBE 0x4
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_ATARDY 0x5
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_DHOLD 0x6
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_DONE 0x7
+#define BP_GPMI_DEBUG_MAIN_STATE 0
+#define BM_GPMI_DEBUG_MAIN_STATE 0x0000000F
+#define BF_GPMI_DEBUG_MAIN_STATE(v) \
+ (((v) << 0) & BM_GPMI_DEBUG_MAIN_STATE)
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_IDLE 0x0
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_BYTCNT 0x1
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFE 0x2
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFR 0x3
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAREQ 0x4
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAACK 0x5
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFF 0x6
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_LDFIFO 0x7
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_LDDMAR 0x8
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_RDCMP 0x9
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DONE 0xA
+
+#else
+
+#define BP_GPMI_DEBUG_WAIT_FOR_READY_END 24
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END 0xFF000000
+#define BF_GPMI_DEBUG_WAIT_FOR_READY_END(v) \
+ (((v) << 24) & BM_GPMI_DEBUG_WAIT_FOR_READY_END)
+#define BP_GPMI_DEBUG_DMA_SENSE 16
+#define BM_GPMI_DEBUG_DMA_SENSE 0x00FF0000
+#define BF_GPMI_DEBUG_DMA_SENSE(v) \
+ (((v) << 16) & BM_GPMI_DEBUG_DMA_SENSE)
+#define BP_GPMI_DEBUG_DMAREQ 8
+#define BM_GPMI_DEBUG_DMAREQ 0x0000FF00
+#define BF_GPMI_DEBUG_DMAREQ(v) \
+ (((v) << 8) & BM_GPMI_DEBUG_DMAREQ)
+#define BP_GPMI_DEBUG_CMD_END 0
+#define BM_GPMI_DEBUG_CMD_END 0x000000FF
+#define BF_GPMI_DEBUG_CMD_END(v) \
+ (((v) << 0) & BM_GPMI_DEBUG_CMD_END)
+
+#endif
+
+#define HW_GPMI_VERSION (0x000000d0)
+
+#define BP_GPMI_VERSION_MAJOR 24
+#define BM_GPMI_VERSION_MAJOR 0xFF000000
+#define BF_GPMI_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_GPMI_VERSION_MAJOR)
+#define BP_GPMI_VERSION_MINOR 16
+#define BM_GPMI_VERSION_MINOR 0x00FF0000
+#define BF_GPMI_VERSION_MINOR(v) \
+ (((v) << 16) & BM_GPMI_VERSION_MINOR)
+#define BP_GPMI_VERSION_STEP 0
+#define BM_GPMI_VERSION_STEP 0x0000FFFF
+#define BF_GPMI_VERSION_STEP(v) \
+ (((v) << 0) & BM_GPMI_VERSION_STEP)
+
+#define HW_GPMI_DEBUG2 (0x000000e0)
+
+#if defined(CONFIG_GPMI_NFC_V0)
+
+#define BP_GPMI_DEBUG2_RSVD1 16
+#define BM_GPMI_DEBUG2_RSVD1 0xFFFF0000
+#define BF_GPMI_DEBUG2_RSVD1(v) (((v) << 16) & BM_GPMI_DEBUG2_RSVD1)
+
+#else
+
+#define BP_GPMI_DEBUG2_RSVD1 28
+#define BM_GPMI_DEBUG2_RSVD1 0xF0000000
+#define BF_GPMI_DEBUG2_RSVD1(v) \
+ (((v) << 28) & BM_GPMI_DEBUG2_RSVD1)
+#define BP_GPMI_DEBUG2_UDMA_STATE 24
+#define BM_GPMI_DEBUG2_UDMA_STATE 0x0F000000
+#define BF_GPMI_DEBUG2_UDMA_STATE(v) \
+ (((v) << 24) & BM_GPMI_DEBUG2_UDMA_STATE)
+#define BM_GPMI_DEBUG2_BUSY 0x00800000
+#define BV_GPMI_DEBUG2_BUSY__DISABLED 0x0
+#define BV_GPMI_DEBUG2_BUSY__ENABLED 0x1
+#define BP_GPMI_DEBUG2_PIN_STATE 20
+#define BM_GPMI_DEBUG2_PIN_STATE 0x00700000
+#define BF_GPMI_DEBUG2_PIN_STATE(v) \
+ (((v) << 20) & BM_GPMI_DEBUG2_PIN_STATE)
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_IDLE 0x0
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_BYTCNT 0x1
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_ADDR 0x2
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_STALL 0x3
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_STROBE 0x4
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_ATARDY 0x5
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_DHOLD 0x6
+#define BV_GPMI_DEBUG2_PIN_STATE__PSM_DONE 0x7
+#define BP_GPMI_DEBUG2_MAIN_STATE 16
+#define BM_GPMI_DEBUG2_MAIN_STATE 0x000F0000
+#define BF_GPMI_DEBUG2_MAIN_STATE(v) \
+ (((v) << 16) & BM_GPMI_DEBUG2_MAIN_STATE)
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_IDLE 0x0
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_BYTCNT 0x1
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_WAITFE 0x2
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_WAITFR 0x3
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_DMAREQ 0x4
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_DMAACK 0x5
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_WAITFF 0x6
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_LDFIFO 0x7
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_LDDMAR 0x8
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_RDCMP 0x9
+#define BV_GPMI_DEBUG2_MAIN_STATE__MSM_DONE 0xA
+#define BP_GPMI_DEBUG2_SYND2GPMI_BE 12
+#define BM_GPMI_DEBUG2_SYND2GPMI_BE 0x0000F000
+#define BF_GPMI_DEBUG2_SYND2GPMI_BE(v) \
+ (((v) << 12) & BM_GPMI_DEBUG2_SYND2GPMI_BE)
+#define BM_GPMI_DEBUG2_GPMI2SYND_VALID 0x00000800
+#define BM_GPMI_DEBUG2_GPMI2SYND_READY 0x00000400
+#define BM_GPMI_DEBUG2_SYND2GPMI_VALID 0x00000200
+#define BM_GPMI_DEBUG2_SYND2GPMI_READY 0x00000100
+#define BM_GPMI_DEBUG2_VIEW_DELAYED_RDN 0x00000080
+#define BM_GPMI_DEBUG2_UPDATE_WINDOW 0x00000040
+#define BP_GPMI_DEBUG2_RDN_TAP 0
+#define BM_GPMI_DEBUG2_RDN_TAP 0x0000003F
+#define BF_GPMI_DEBUG2_RDN_TAP(v) \
+ (((v) << 0) & BM_GPMI_DEBUG2_RDN_TAP)
+
+#endif
+
+#define HW_GPMI_DEBUG3 (0x000000f0)
+
+#define BP_GPMI_DEBUG3_APB_WORD_CNTR 16
+#define BM_GPMI_DEBUG3_APB_WORD_CNTR 0xFFFF0000
+#define BF_GPMI_DEBUG3_APB_WORD_CNTR(v) \
+ (((v) << 16) & BM_GPMI_DEBUG3_APB_WORD_CNTR)
+#define BP_GPMI_DEBUG3_DEV_WORD_CNTR 0
+#define BM_GPMI_DEBUG3_DEV_WORD_CNTR 0x0000FFFF
+#define BF_GPMI_DEBUG3_DEV_WORD_CNTR(v) \
+ (((v) << 0) & BM_GPMI_DEBUG3_DEV_WORD_CNTR)
+
+#if defined(CONFIG_GPMI_NFC_V2)
+#define HW_GPMI_READ_DDR_DLL_CTRL (0x00000100)
+
+#define BP_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT 28
+#define BM_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT 0xF0000000
+#define BF_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT(v) \
+ (((v) << 28) & BM_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT)
+#define BP_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT 20
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT 0x0FF00000
+#define BF_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT(v) \
+ (((v) << 20) & BM_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT)
+#define BP_GPMI_READ_DDR_DLL_CTRL_RSVD1 18
+#define BM_GPMI_READ_DDR_DLL_CTRL_RSVD1 0x000C0000
+#define BF_GPMI_READ_DDR_DLL_CTRL_RSVD1(v) \
+ (((v) << 18) & BM_GPMI_READ_DDR_DLL_CTRL_RSVD1)
+#define BP_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 10
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 0x0003FC00
+#define BF_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL(v) \
+ (((v) << 10) & BM_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL)
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE 0x00000200
+#define BM_GPMI_READ_DDR_DLL_CTRL_REFCLK_ON 0x00000100
+#define BM_GPMI_READ_DDR_DLL_CTRL_GATE_UPDATE 0x00000080
+#define BP_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET 3
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET 0x00000078
+#define BF_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET(v) \
+ (((v) << 3) & BM_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET)
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_FORCE_UPD 0x00000004
+#define BM_GPMI_READ_DDR_DLL_CTRL_RESET 0x00000002
+#define BM_GPMI_READ_DDR_DLL_CTRL_ENABLE 0x00000001
+
+#define HW_GPMI_WRITE_DDR_DLL_CTRL (0x00000110)
+
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT 28
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT 0xF0000000
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT(v) \
+ (((v) << 28) & BM_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT)
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT 20
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT 0x0FF00000
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT(v) \
+ (((v) << 20) & BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT)
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_RSVD1 18
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_RSVD1 0x000C0000
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_RSVD1(v) \
+ (((v) << 18) & BM_GPMI_WRITE_DDR_DLL_CTRL_RSVD1)
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 10
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 0x0003FC00
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL(v) \
+ (((v) << 10) & BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL)
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE 0x00000200
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_REFCLK_ON 0x00000100
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_GATE_UPDATE 0x00000080
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET 3
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET 0x00000078
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET(v) \
+ (((v) << 3) & BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET)
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_FORCE_UPD 0x00000004
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_RESET 0x00000002
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_ENABLE 0x00000001
+
+#define HW_GPMI_READ_DDR_DLL_STS (0x00000120)
+
+#define BP_GPMI_READ_DDR_DLL_STS_RSVD1 25
+#define BM_GPMI_READ_DDR_DLL_STS_RSVD1 0xFE000000
+#define BF_GPMI_READ_DDR_DLL_STS_RSVD1(v) \
+ (((v) << 25) & BM_GPMI_READ_DDR_DLL_STS_RSVD1)
+#define BP_GPMI_READ_DDR_DLL_STS_REF_SEL 17
+#define BM_GPMI_READ_DDR_DLL_STS_REF_SEL 0x01FE0000
+#define BF_GPMI_READ_DDR_DLL_STS_REF_SEL(v) \
+ (((v) << 17) & BM_GPMI_READ_DDR_DLL_STS_REF_SEL)
+#define BM_GPMI_READ_DDR_DLL_STS_REF_LOCK 0x00010000
+#define BP_GPMI_READ_DDR_DLL_STS_RSVD0 9
+#define BM_GPMI_READ_DDR_DLL_STS_RSVD0 0x0000FE00
+#define BF_GPMI_READ_DDR_DLL_STS_RSVD0(v) \
+ (((v) << 9) & BM_GPMI_READ_DDR_DLL_STS_RSVD0)
+#define BP_GPMI_READ_DDR_DLL_STS_SLV_SEL 1
+#define BM_GPMI_READ_DDR_DLL_STS_SLV_SEL 0x000001FE
+#define BF_GPMI_READ_DDR_DLL_STS_SLV_SEL(v) \
+ (((v) << 1) & BM_GPMI_READ_DDR_DLL_STS_SLV_SEL)
+#define BM_GPMI_READ_DDR_DLL_STS_SLV_LOCK 0x00000001
+
+#define HW_GPMI_WRITE_DDR_DLL_STS (0x00000130)
+
+#define BP_GPMI_WRITE_DDR_DLL_STS_RSVD1 25
+#define BM_GPMI_WRITE_DDR_DLL_STS_RSVD1 0xFE000000
+#define BF_GPMI_WRITE_DDR_DLL_STS_RSVD1(v) \
+ (((v) << 25) & BM_GPMI_WRITE_DDR_DLL_STS_RSVD1)
+#define BP_GPMI_WRITE_DDR_DLL_STS_REF_SEL 17
+#define BM_GPMI_WRITE_DDR_DLL_STS_REF_SEL 0x01FE0000
+#define BF_GPMI_WRITE_DDR_DLL_STS_REF_SEL(v) \
+ (((v) << 17) & BM_GPMI_WRITE_DDR_DLL_STS_REF_SEL)
+#define BM_GPMI_WRITE_DDR_DLL_STS_REF_LOCK 0x00010000
+#define BP_GPMI_WRITE_DDR_DLL_STS_RSVD0 9
+#define BM_GPMI_WRITE_DDR_DLL_STS_RSVD0 0x0000FE00
+#define BF_GPMI_WRITE_DDR_DLL_STS_RSVD0(v) \
+ (((v) << 9) & BM_GPMI_WRITE_DDR_DLL_STS_RSVD0)
+#define BP_GPMI_WRITE_DDR_DLL_STS_SLV_SEL 1
+#define BM_GPMI_WRITE_DDR_DLL_STS_SLV_SEL 0x000001FE
+#define BF_GPMI_WRITE_DDR_DLL_STS_SLV_SEL(v) \
+ (((v) << 1) & BM_GPMI_WRITE_DDR_DLL_STS_SLV_SEL)
+#define BM_GPMI_WRITE_DDR_DLL_STS_SLV_LOCK 0x00000001
+#endif
+
+#define GPMI_NFC_COMMAND_BUFFER_SIZE (10)
+
+/* ECC Macros */
+#define GPMI_NFC_METADATA_SIZE (10)
+#define GPMI_NFC_CHUNK_DATA_CHUNK_SIZE (512)
+#define GPMI_NFC_CHUNK_DATA_CHUNK_SIZE_IN_BITS (512 * 6)
+#define GPMI_NFC_CHUNK_ECC_SIZE_IN_BITS(ecc_str) (ecc_str * 13)
+#define GPMI_NFC_ECC_CHUNK_CNT(page_data_size) \
+ (page_data_size / GPMI_NFC_CHUNK_DATA_CHUNK_SIZE)
+
+#define GPMI_NFC_AUX_STATUS_OFF ((GPMI_NFC_METADATA_SIZE + 0x3) & ~0x3)
+#define GPMI_NFC_AUX_SIZE(page_size) ((GPMI_NFC_AUX_STATUS_OFF) + \
+ ((GPMI_NFC_ECC_CHUNK_CNT(page_size) + 0x3) & ~0x3))
+
+static inline int abs(int n)
+{
+ if (n >= 0)
+ return n;
+ else
+ return n * -1;
+}
+
+static inline u32 gpmi_nfc_get_blk_mark_bit_ofs(u32 page_data_size,
+ u32 ecc_strength)
+{
+ u32 chunk_data_size_in_bits;
+ u32 chunk_ecc_size_in_bits;
+ u32 chunk_total_size_in_bits;
+ u32 block_mark_chunk_number;
+ u32 block_mark_chunk_bit_offset;
+ u32 block_mark_bit_offset;
+
+ /* 4096 bits */
+ chunk_data_size_in_bits = GPMI_NFC_CHUNK_DATA_CHUNK_SIZE * 8;
+ /* 208 bits */
+ chunk_ecc_size_in_bits = GPMI_NFC_CHUNK_ECC_SIZE_IN_BITS(ecc_strength);
+
+ /* 4304 bits */
+ chunk_total_size_in_bits =
+ chunk_data_size_in_bits + chunk_ecc_size_in_bits;
+
+ /* Compute the bit offset of the block mark within the physical page. */
+ /* 4096 * 8 = 32768 bits */
+ block_mark_bit_offset = page_data_size * 8;
+
+ /* Subtract the metadata bits. */
+ /* 32688 bits */
+ block_mark_bit_offset -= GPMI_NFC_METADATA_SIZE * 8;
+
+ /*
+ * Compute the chunk number (starting at zero) in which the block mark
+ * appears.
+ */
+ /* 7 */
+ block_mark_chunk_number =
+ block_mark_bit_offset / chunk_total_size_in_bits;
+
+ /*
+ * Compute the bit offset of the block mark within its chunk, and
+ * validate it.
+ */
+ /* 2560 bits */
+ block_mark_chunk_bit_offset =
+ block_mark_bit_offset -
+ (block_mark_chunk_number * chunk_total_size_in_bits);
+
+ if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
+ return 1;
+
+ /*
+ * Now that we know the chunk number in which the block mark appears,
+ * we can subtract all the ECC bits that appear before it.
+ */
+ /* 31232 bits */
+ block_mark_bit_offset -=
+ block_mark_chunk_number * chunk_ecc_size_in_bits;
+
+ return block_mark_bit_offset;
+}
+
+static inline u32 gpmi_nfc_get_ecc_strength(u32 page_data_size,
+ u32 page_oob_size)
+{
+ if (2048 == page_data_size)
+ return 8;
+ else if (4096 == page_data_size) {
+ if (128 == page_oob_size)
+ return 8;
+ else if (218 == page_oob_size)
+ return 16;
+ else
+ return 0;
+ } else
+ return 0;
+}
+
+static inline s32 gpmi_nfc_reset_block(void *hwreg, int is_enable)
+{
+ int timeout;
+
+ /* the process of software reset of IP block is done
+ in several steps:
+
+ - clear SFTRST and wait for block is enabled;
+ - clear clock gating (CLKGATE bit);
+ - set the SFTRST again and wait for block is in reset;
+ - clear SFTRST and wait for reset completion.
+ */
+ /* clear SFTRST */
+ REG_CLR_ADDR(hwreg, BM_GPMI_CTRL0_SFTRST);
+
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((REG_RD_ADDR(hwreg) & BM_GPMI_CTRL0_SFTRST) == 0)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when enabling\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ /* clear CLKGATE */
+ REG_CLR_ADDR(hwreg, BM_GPMI_CTRL0_CLKGATE);
+
+ if (is_enable) {
+ /* now again set SFTRST */
+ REG_SET_ADDR(hwreg, BM_GPMI_CTRL0_SFTRST);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* poll until CLKGATE set */
+ if (REG_RD_ADDR(hwreg) & BM_GPMI_CTRL0_CLKGATE)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when resetting\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ REG_CLR_ADDR(hwreg, BM_GPMI_CTRL0_SFTRST);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((REG_RD_ADDR(hwreg) & BM_GPMI_CTRL0_SFTRST) == 0)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when enabling "
+ "after reset\n", __func__, hwreg);
+ return -ETIME;
+ }
+
+ /* clear CLKGATE */
+ REG_CLR_ADDR(hwreg, BM_GPMI_CTRL0_CLKGATE);
+ }
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((REG_RD_ADDR(hwreg) & BM_GPMI_CTRL0_CLKGATE) == 0)
+ break;
+
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when unclockgating\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+/**
+ * struct gpmi_nfc_info - i.MX NFC per-device data.
+ *
+ * Note that the "device" managed by this driver represents the NAND Flash
+ * controller *and* the NAND Flash medium behind it. Thus, the per-device data
+ * structure has information about the controller, the chips to which it is
+ * connected, and properties of the medium as a whole.
+ *
+ * @dev: A pointer to the owning struct device.
+ * @pdev: A pointer to the owning struct platform_device.
+ * @pdata: A pointer to the device's platform data.
+ * @resources: Information about system resources used by this driver.
+ * @device_info: A structure that contains detailed information about
+ * the NAND Flash device.
+ * @physical_geometry: A description of the medium's physical geometry.
+ * @nfc: A pointer to a structure that represents the underlying
+ * NFC hardware.
+ * @nfc_geometry: A description of the medium geometry as viewed by the
+ * NFC.
+ * @rom: A pointer to a structure that represents the underlying
+ * Boot ROM.
+ * @rom_geometry: A description of the medium geometry as viewed by the
+ * Boot ROM.
+ * @mil: A collection of information used by the MTD Interface
+ * Layer.
+ */
+
+struct gpmi_nfc_info {
+
+ s32 cur_chip;
+ u8 *data_buf;
+ u8 *oob_buf;
+ u32 *cmd_queue;
+ u32 cmd_Q_len;
+
+ u8 m_u8MarkingBadBlock;
+ u8 m_u8RawOOBMode;
+
+ u32 m_u32EccChunkCnt;
+ u32 m_u32EccStrength;
+ u32 m_u32AuxSize;
+ u32 m_u32AuxStsOfs;
+ u32 m_u32BlkMarkByteOfs;
+ u32 m_u32BlkMarkBitStart;
+
+ int (*hooked_read_oob)(struct mtd_info *mtd,
+ loff_t from, struct mtd_oob_ops *ops);
+ int (*hooked_write_oob)(struct mtd_info *mtd,
+ loff_t to, struct mtd_oob_ops *ops);
+ int (*hooked_block_markbad)(struct mtd_info *mtd,
+ loff_t ofs);
+
+ /* NFC HAL */
+ struct nfc_hal *nfc;
+};
+
+
+/**
+ * struct gpmi_nfc_timing - GPMI NFC timing parameters
+ *
+ * This structure contains the fundamental timing attributes for the NAND Flash
+ * bus and the GPMI NFC hardware.
+ *
+ * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the
+ * maximum of tDS and tWP. A negative value
+ * indicates this characteristic isn't known.
+ * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the
+ * maximum of tDH, tWH and tREH. A negative value
+ * indicates this characteristic isn't known.
+ * @address_setup_in_ns: The address setup time, in nanoseconds. Usually
+ * the maximum of tCLS, tCS and tALS. A negative
+ * value indicates this characteristic isn't known.
+ * @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value
+ * indicates this characteristic isn't known.
+ * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A
+ * negative value indicates this characteristic isn't
+ * known.
+ * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A
+ * negative value indicates this characteristic isn't
+ * known.
+ * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A
+ * negative value indicates this characteristic isn't
+ * known.
+ */
+
+struct gpmi_nfc_timing {
+ u8 m_u8DataSetup;
+ u8 m_u8DataHold;
+ u8 m_u8AddressSetup;
+ u8 m_u8HalfPeriods;
+ u8 m_u8SampleDelay;
+ u8 m_u8NandTimingState;
+ u8 m_u8tREA;
+ u8 m_u8tRLOH;
+ u8 m_u8tRHOH;
+};
+
+/**
+ * struct nfc_hal - GPMI NFC HAL
+ *
+ * This structure embodies an abstract interface to the underlying NFC hardware.
+ *
+ * @version: The NFC hardware version.
+ * @description: A pointer to a human-readable description of
+ * the NFC hardware.
+ * @max_chip_count: The maximum number of chips the NFC can
+ * possibly support (this value is a constant for
+ * each NFC version). This may *not* be the actual
+ * number of chips connected.
+ * @max_data_setup_cycles: The maximum number of data setup cycles that
+ * can be expressed in the hardware.
+ * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires
+ * for data read internal setup. In the Reference
+ * Manual, see the chapter "High-Speed NAND
+ * Timing" for more details.
+ * @max_sample_delay_factor: The maximum sample delay factor that can be
+ * expressed in the hardware.
+ * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the
+ * sample delay DLL hardware can possibly work
+ * with (the DLL is unusable with longer periods).
+ * If the full-cycle period is greater than HALF
+ * this value, the DLL must be configured to use
+ * half-periods.
+ * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the
+ * DLL can implement.
+ * @dma_descriptors: A pool of DMA descriptors.
+ * @isr_dma_channel: The DMA channel with which the NFC HAL is
+ * working. We record this here so the ISR knows
+ * which DMA channel to acknowledge.
+ * @dma_done: The completion structure used for DMA
+ * interrupts.
+ * @bch_done: The completion structure used for BCH
+ * interrupts.
+ * @timing: The current timing configuration.
+ * @clock_frequency_in_hz: The clock frequency, in Hz, during the current
+ * I/O transaction. If no I/O transaction is in
+ * progress, this is the clock frequency during
+ * the most recent I/O transaction.
+ * @hardware_timing: The hardware timing configuration in effect
+ * during the current I/O transaction. If no I/O
+ * transaction is in progress, this is the
+ * hardware timing configuration during the most
+ * recent I/O transaction.
+ * @init: Initializes the NFC hardware and data
+ * structures. This function will be called after
+ * everything has been set up for communication
+ * with the NFC itself, but before the platform
+ * has set up off-chip communication. Thus, this
+ * function must not attempt to communicate with
+ * the NAND Flash hardware.
+ * @set_geometry: Configures the NFC hardware and data structures
+ * to match the physical NAND Flash geometry.
+ * @set_geometry: Configures the NFC hardware and data structures
+ * to match the physical NAND Flash geometry.
+ * @set_timing: Configures the NFC hardware and data structures
+ * to match the given NAND Flash bus timing.
+ * @get_timing: Returns the the clock frequency, in Hz, and
+ * the hardware timing configuration during the
+ * current I/O transaction. If no I/O transaction
+ * is in progress, this is the timing state during
+ * the most recent I/O transaction.
+ * @exit: Shuts down the NFC hardware and data
+ * structures. This function will be called after
+ * the platform has shut down off-chip
+ * communication but while communication with the
+ * NFC itself still works.
+ * @clear_bch: Clears a BCH interrupt (intended to be called
+ * by a more general interrupt handler to do
+ * device-specific clearing).
+ * @is_ready: Returns true if the given chip is ready.
+ * @begin: Begins an interaction with the NFC. This
+ * function must be called before *any* of the
+ * following functions so the NFC can prepare
+ * itself.
+ * @end: Ends interaction with the NFC. This function
+ * should be called to give the NFC a chance to,
+ * among other things, enter a lower-power state.
+ * @send_command: Sends the given buffer of command bytes.
+ * @send_data: Sends the given buffer of data bytes.
+ * @read_data: Reads data bytes into the given buffer.
+ * @send_page: Sends the given given data and OOB bytes,
+ * using the ECC engine.
+ * @read_page: Reads a page through the ECC engine and
+ * delivers the data and OOB bytes to the given
+ * buffers.
+ */
+
+#define NFC_DMA_DESCRIPTOR_COUNT (4)
+
+struct nfc_hal {
+
+ /* Hardware attributes. */
+
+ const unsigned int version;
+ const char *description;
+ const unsigned int max_chip_count;
+ const unsigned int max_data_setup_cycles;
+ const unsigned int internal_data_setup_in_ns;
+ const unsigned int max_sample_delay_factor;
+ const unsigned int max_dll_clock_period_in_ns;
+ const unsigned int max_dll_delay_in_ns;
+
+ /* Working variables. */
+ struct gpmi_nfc_timing timing;
+ unsigned long clock_frequency_in_hz;
+
+ /* Configuration functions. */
+
+ int (*init) (void);
+ int (*set_geometry)(struct mtd_info *);
+ int (*set_timing) (struct mtd_info *,
+ const struct gpmi_nfc_timing *);
+ void (*get_timing) (struct mtd_info *,
+ unsigned long *clock_frequency_in_hz,
+ struct gpmi_nfc_timing *);
+ void (*exit) (struct mtd_info *);
+
+ /* Call these functions to begin and end I/O. */
+
+ void (*begin) (struct mtd_info *);
+ void (*end) (struct mtd_info *);
+
+ /* Call these I/O functions only between begin() and end(). */
+
+ void (*clear_bch) (struct mtd_info *);
+ int (*is_ready) (struct mtd_info *, unsigned chip);
+ int (*send_command)(struct mtd_info *, unsigned chip,
+ dma_addr_t buffer, unsigned length);
+ int (*send_data) (struct mtd_info *, unsigned chip,
+ dma_addr_t buffer, unsigned length);
+ int (*read_data) (struct mtd_info *, unsigned chip,
+ dma_addr_t buffer, unsigned length);
+ int (*send_page) (struct mtd_info *, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary);
+ int (*read_page) (struct mtd_info *, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary);
+};
+
+extern struct nfc_hal gpmi_nfc_hal;
+
+#endif /* __ARCH_ARM___GPMI_H */
diff --git a/drivers/mtd/nand/gpmi_nfc_hal.c b/drivers/mtd/nand/gpmi_nfc_hal.c
new file mode 100644
index 0000000..ca8bd01
--- /dev/null
+++ b/drivers/mtd/nand/gpmi_nfc_hal.c
@@ -0,0 +1,1621 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * 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.
+ */
+
+#include <linux/mtd/mtd.h>
+#include "gpmi_nfc_gpmi.h"
+#include "gpmi_nfc_bch.h"
+#include <linux/mtd/nand.h>
+#include <linux/types.h>
+#include <asm/apbh_dma.h>
+#include <asm/io.h>
+#include <common.h>
+
+#ifdef CONFIG_ARCH_MMU
+#include <asm/arch/mmu.h>
+#endif
+
+#define MIN_PROP_DELAY_IN_NS (5)
+#define MAX_PROP_DELAY_IN_NS (9)
+
+#define NFC_DMA_DESCRIPTOR_COUNT (4)
+
+static struct mxs_dma_desc *dma_desc[NFC_DMA_DESCRIPTOR_COUNT];
+
+static struct gpmi_nfc_timing safe_timing = {
+ .m_u8DataSetup = 80,
+ .m_u8DataHold = 60,
+ .m_u8AddressSetup = 25,
+ .m_u8HalfPeriods = 0,
+ .m_u8SampleDelay = 6,
+ .m_u8NandTimingState = 0,
+ .m_u8tREA = -1,
+ .m_u8tRLOH = -1,
+ .m_u8tRHOH = -1,
+};
+
+/**
+ * init() - Initializes the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static int init(void)
+{
+ int error = 0, i;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /* Initialize DMA. */
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "dma_desc: 0x%08x, ",
+ (unsigned int)dma_desc);
+ for (i = 0; i < NFC_DMA_DESCRIPTOR_COUNT; ++i) {
+ dma_desc[i] = mxs_dma_alloc_desc();
+
+ if (NULL == dma_desc[i]) {
+ for (i -= 1; i >= 0; --i)
+ mxs_dma_free_desc(dma_desc[i]);
+ error = -ENOMEM;
+ }
+ MTDDEBUG(MTD_DEBUG_LEVEL1,
+ "dma_desc[%d]: 0x%08x, ",
+ i, (unsigned int)dma_desc[i]);
+ }
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "\n");
+
+ if (error)
+ return error;
+
+ mxs_dma_init();
+
+ /* Reset the GPMI block. */
+ gpmi_nfc_reset_block((void *)(CONFIG_GPMI_REG_BASE + HW_GPMI_CTRL0), 1);
+
+ /* Choose NAND mode. */
+ REG_CLR(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_GPMI_MODE);
+
+ /* Set the IRQ polarity. */
+ REG_SET(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY);
+
+ /* Disable write protection. */
+ REG_SET(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_DEV_RESET);
+
+ /* Select BCH ECC. */
+ REG_SET(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_BCH_MODE);
+
+ memcpy(&gpmi_nfc_hal.timing, &safe_timing,
+ sizeof(struct gpmi_nfc_timing));
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+}
+
+/**
+ * set_geometry() - Configures the NFC geometry.
+ *
+ * @this: Per-device data.
+ */
+static int set_geometry(struct mtd_info *mtd)
+{
+ u32 block_count;
+ u32 block_size;
+ u32 metadata_size;
+ u32 ecc_strength;
+ u32 page_size;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /* Translate the abstract choices into register fields. */
+ block_count = GPMI_NFC_ECC_CHUNK_CNT(mtd->writesize) - 1;
+#if defined(CONFIG_GPMI_NFC_V2)
+ block_size = GPMI_NFC_CHUNK_DATA_CHUNK_SIZE >> 2;
+#else
+ block_size = GPMI_NFC_CHUNK_DATA_CHUNK_SIZE;
+#endif
+ metadata_size = GPMI_NFC_METADATA_SIZE;
+
+ ecc_strength =
+ gpmi_nfc_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1;
+
+ page_size = mtd->writesize + mtd->oobsize;
+
+ /*
+ * Reset the BCH block. Notice that we pass in true for the just_enable
+ * flag. This is because the soft reset for the version 0 BCH block
+ * doesn't work and the version 1 BCH block is similar enough that we
+ * suspect the same (though this has not been officially tested). If you
+ * try to soft reset a version 0 BCH block, it becomes unusable until
+ * the next hard reset.
+ */
+
+#if defined(CONFIG_GPMI_NFC_V2)
+ gpmi_nfc_reset_block((void *)CONFIG_BCH_REG_BASE + HW_BCH_CTRL, 0);
+#else
+ gpmi_nfc_reset_block((void *)CONFIG_BCH_REG_BASE + HW_BCH_CTRL, 1);
+#endif
+
+ /* Configure layout 0. */
+ writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) |
+ BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) |
+ BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) |
+ BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size),
+ CONFIG_BCH_REG_BASE + HW_BCH_FLASH0LAYOUT0);
+
+ writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+ BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) |
+ BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size),
+ CONFIG_BCH_REG_BASE + HW_BCH_FLASH0LAYOUT1);
+
+ /* Set *all* chip selects to use layout 0. */
+ writel(0, CONFIG_BCH_REG_BASE + HW_BCH_LAYOUTSELECT);
+
+ /* Enable interrupts. */
+ REG_SET(CONFIG_BCH_REG_BASE, HW_BCH_CTRL,
+ BM_BCH_CTRL_COMPLETE_IRQ_EN);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+}
+
+/**
+ * ns_to_cycles - Converts time in nanoseconds to cycles.
+ *
+ * @ntime: The time, in nanoseconds.
+ * @period: The cycle period, in nanoseconds.
+ * @min: The minimum allowable number of cycles.
+ */
+static u32 ns_to_cycles(u32 time, u32 period, u32 min)
+{
+ u32 k;
+
+ /*
+ * Compute the minimum number of cycles that entirely contain the
+ * given time.
+ */
+ k = (time + period - 1) / period;
+
+ return max(k, min);
+}
+
+static int calculte_hw_timing(struct mtd_info *mtd,
+ struct gpmi_nfc_timing *nfc_timing,
+ struct gpmi_nfc_timing *hw_timing)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+
+ u8 improved_timing_is_available;
+ u32 clock_frequency_in_hz;
+ u32 clock_period_in_ns;
+ u8 dll_use_half_periods;
+ u32 dll_delay_shift;
+ u32 max_sample_delay_in_ns;
+ u32 address_setup_in_cycles;
+ u32 data_setup_in_ns;
+ u32 data_setup_in_cycles;
+ u32 data_hold_in_cycles;
+ s32 ideal_sample_delay_in_ns;
+ u32 sample_delay_factor;
+ s32 tEYE;
+ u32 min_prop_delay_in_ns = MIN_PROP_DELAY_IN_NS;
+ u32 max_prop_delay_in_ns = MAX_PROP_DELAY_IN_NS;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /*
+ * If there are multiple chips, we need to relax the timings to allow
+ * for signal distortion due to higher capacitance.
+ */
+ if (chip->numchips > 2) {
+ nfc_timing->m_u8DataSetup += 10;
+ nfc_timing->m_u8DataHold += 10;
+ nfc_timing->m_u8AddressSetup += 10;
+ } else {
+ nfc_timing->m_u8DataSetup += 5;
+ nfc_timing->m_u8DataHold += 5;
+ nfc_timing->m_u8AddressSetup += 5;
+ }
+
+ /* Check if improved timing information is available. */
+ improved_timing_is_available =
+ (nfc_timing->m_u8tREA >= 0) &&
+ (nfc_timing->m_u8tRLOH >= 0) &&
+ (nfc_timing->m_u8tRHOH >= 0) ;
+
+ /* Inspect the clock. */
+ clock_frequency_in_hz = mxc_get_clock(MXC_GPMI_CLK);
+ clock_period_in_ns = 1000000000 / clock_frequency_in_hz;
+
+ /*
+ * The NFC quantizes setup and hold parameters in terms of clock cycles.
+ * Here, we quantize the setup and hold timing parameters to the
+ * next-highest clock period to make sure we apply at least the
+ * specified times.
+ *
+ * For data setup and data hold, the hardware interprets a value of zero
+ * as the largest possible delay. This is not what's intended by a zero
+ * in the input parameter, so we impose a minimum of one cycle.
+ */
+ data_setup_in_cycles = ns_to_cycles(nfc_timing->m_u8DataSetup,
+ clock_period_in_ns, 1);
+ data_hold_in_cycles = ns_to_cycles(nfc_timing->m_u8DataHold,
+ clock_period_in_ns, 1);
+ address_setup_in_cycles = ns_to_cycles(nfc_timing->m_u8AddressSetup,
+ clock_period_in_ns, 0);
+
+ /*
+ * The clock's period affects the sample delay in a number of ways:
+ *
+ * (1) The NFC HAL tells us the maximum clock period the sample delay
+ * DLL can tolerate. If the clock period is greater than half that
+ * maximum, we must configure the DLL to be driven by half periods.
+ *
+ * (2) We need to convert from an ideal sample delay, in ns, to a
+ * "sample delay factor," which the NFC uses. This factor depends on
+ * whether we're driving the DLL with full or half periods.
+ * Paraphrasing the reference manual:
+ *
+ * AD = SDF x 0.125 x RP
+ *
+ * where:
+ *
+ * AD is the applied delay, in ns.
+ * SDF is the sample delay factor, which is dimensionless.
+ * RP is the reference period, in ns, which is a full clock period
+ * if the DLL is being driven by full periods, or half that if
+ * the DLL is being driven by half periods.
+ *
+ * Let's re-arrange this in a way that's more useful to us:
+ *
+ * 8
+ * SDF = AD x ----
+ * RP
+ *
+ * The reference period is either the clock period or half that, so this
+ * is:
+ *
+ * 8 AD x DDF
+ * SDF = AD x ----- = --------
+ * f x P P
+ *
+ * where:
+ *
+ * f is 1 or 1/2, depending on how we're driving the DLL.
+ * P is the clock period.
+ * DDF is the DLL Delay Factor, a dimensionless value that
+ * incorporates all the constants in the conversion.
+ *
+ * DDF will be either 8 or 16, both of which are powers of two. We can
+ * reduce the cost of this conversion by using bit shifts instead of
+ * multiplication or division. Thus:
+ *
+ * AD << DDS
+ * SDF = ---------
+ * P
+ *
+ * or
+ *
+ * AD = (SDF >> DDS) x P
+ *
+ * where:
+ *
+ * DDS is the DLL Delay Shift, the logarithm to base 2 of the DDF.
+ */
+ if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) {
+ dll_use_half_periods = 0;
+ dll_delay_shift = 3 + 1;
+ } else {
+ dll_use_half_periods = 1;
+ dll_delay_shift = 3;
+ }
+
+ /*
+ * Compute the maximum sample delay the NFC allows, under current
+ * conditions. If the clock is running too slowly, no sample delay is
+ * possible.
+ */
+ if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns)
+ max_sample_delay_in_ns = 0;
+
+ else {
+
+ /*
+ * Compute the delay implied by the largest sample delay factor
+ * the NFC allows.
+ */
+
+ max_sample_delay_in_ns =
+ (nfc->max_sample_delay_factor * clock_period_in_ns) >>
+ dll_delay_shift;
+
+ /*
+ * Check if the implied sample delay larger than the NFC
+ * actually allows.
+ */
+
+ if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns)
+ max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
+
+ }
+
+ /*
+ * Check if improved timing information is available. If not, we have to
+ * use a less-sophisticated algorithm.
+ */
+
+ if (!improved_timing_is_available) {
+
+ /*
+ * Fold the read setup time required by the NFC into the ideal
+ * sample delay.
+ */
+
+ ideal_sample_delay_in_ns = nfc_timing->m_u8SampleDelay +
+ nfc->internal_data_setup_in_ns;
+
+ /*
+ * The ideal sample delay may be greater than the maximum
+ * allowed by the NFC. If so, we can trade off sample delay time
+ * for more data setup time.
+ *
+ * In each iteration of the following loop, we add a cycle to
+ * the data setup time and subtract a corresponding amount from
+ * the sample delay until we've satisified the constraints or
+ * can't do any better.
+ */
+
+ while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
+ (data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+
+ data_setup_in_cycles++;
+ ideal_sample_delay_in_ns -= clock_period_in_ns;
+
+ if (ideal_sample_delay_in_ns < 0)
+ ideal_sample_delay_in_ns = 0;
+ }
+
+ /*
+ * Compute the sample delay factor that corresponds most closely
+ * to the ideal sample delay. If the result is too large for the
+ * NFC, use the maximum value.
+ *
+ * Notice that we use the ns_to_cycles function to compute the
+ * sample delay factor. We do this because the form of the
+ * computation is the same as that for calculating cycles.
+ */
+ sample_delay_factor =
+ ns_to_cycles(
+ ideal_sample_delay_in_ns << dll_delay_shift,
+ clock_period_in_ns, 0);
+
+ if (sample_delay_factor > nfc->max_sample_delay_factor)
+ sample_delay_factor = nfc->max_sample_delay_factor;
+
+ /* Skip to the part where we return our results. */
+ goto rtn_rslt;
+ }
+
+ /*
+ * If control arrives here, we have more detailed timing information,
+ * so we can use a better algorithm.
+ */
+
+ /*
+ * Fold the read setup time required by the NFC into the maximum
+ * propagation delay.
+ */
+ max_prop_delay_in_ns += nfc->internal_data_setup_in_ns;
+
+ /*
+ * Earlier, we computed the number of clock cycles required to satisfy
+ * the data setup time. Now, we need to know the actual nanoseconds.
+ */
+ data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles;
+
+ /*
+ * Compute tEYE, the width of the data eye when reading from the NAND
+ * Flash. The eye width is fundamentally determined by the data setup
+ * time, perturbed by propagation delays and some characteristics of the
+ * NAND Flash device.
+ *
+ * start of the eye = max_prop_delay + tREA
+ * end of the eye = min_prop_delay + tRHOH + data_setup
+ */
+
+ tEYE = (int)min_prop_delay_in_ns + (int)nfc_timing->m_u8tRHOH+
+ (int)data_setup_in_ns;
+
+ tEYE -= (int)max_prop_delay_in_ns + (int)nfc_timing->m_u8tREA;
+
+ /*
+ * The eye must be open. If it's not, we can try to open it by
+ * increasing its main forcer, the data setup time.
+ *
+ * In each iteration of the following loop, we increase the data setup
+ * time by a single clock cycle. We do this until either the eye is
+ * open or we run into NFC limits.
+ */
+ while ((tEYE <= 0) &&
+ (data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+ /* Give a cycle to data setup. */
+ data_setup_in_cycles++;
+ /* Synchronize the data setup time with the cycles. */
+ data_setup_in_ns += clock_period_in_ns;
+ /* Adjust tEYE accordingly. */
+ tEYE += clock_period_in_ns;
+ }
+
+ /*
+ * When control arrives here, the eye is open. The ideal time to sample
+ * the data is in the center of the eye:
+ *
+ * end of the eye + start of the eye
+ * --------------------------------- - data_setup
+ * 2
+ *
+ * After some algebra, this simplifies to the code immediately below.
+ */
+
+ ideal_sample_delay_in_ns =
+ ((int)max_prop_delay_in_ns +
+ (int)nfc_timing->m_u8tREA+
+ (int)min_prop_delay_in_ns +
+ (int)nfc_timing->m_u8tRHOH-
+ (int)data_setup_in_ns) >> 1;
+
+ /*
+ * The following figure illustrates some aspects of a NAND Flash read:
+ *
+ *
+ * __ _____________________________________
+ * RDN \_________________/
+ *
+ * <---- tEYE ----->
+ * /-----------------\
+ * Read Data ----------------------------< >---------
+ * \-----------------/
+ * ^ ^ ^ ^
+ * | | | |
+ * |<--Data Setup -->|<--Delay Time -->| |
+ * | | | |
+ * | | |
+ * | |<-- Quantized Delay Time -->|
+ * | | |
+ *
+ *
+ * We have some issues we must now address:
+ *
+ * (1) The *ideal* sample delay time must not be negative. If it is, we
+ * jam it to zero.
+ *
+ * (2) The *ideal* sample delay time must not be greater than that
+ * allowed by the NFC. If it is, we can increase the data setup
+ * time, which will reduce the delay between the end of the data
+ * setup and the center of the eye. It will also make the eye
+ * larger, which might help with the next issue...
+ *
+ * (3) The *quantized* sample delay time must not fall either before the
+ * eye opens or after it closes (the latter is the problem
+ * illustrated in the above figure).
+ */
+
+ /* Jam a negative ideal sample delay to zero. */
+ if (ideal_sample_delay_in_ns < 0)
+ ideal_sample_delay_in_ns = 0;
+
+ /*
+ * Extend the data setup as needed to reduce the ideal sample delay
+ * below the maximum permitted by the NFC.
+ */
+ while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
+ (data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+
+ /* Give a cycle to data setup. */
+ data_setup_in_cycles++;
+ /* Synchronize the data setup time with the cycles. */
+ data_setup_in_ns += clock_period_in_ns;
+ /* Adjust tEYE accordingly. */
+ tEYE += clock_period_in_ns;
+
+ /*
+ * Decrease the ideal sample delay by one half cycle, to keep it
+ * in the middle of the eye.
+ */
+ ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
+
+ /* Jam a negative ideal sample delay to zero. */
+ if (ideal_sample_delay_in_ns < 0)
+ ideal_sample_delay_in_ns = 0;
+
+ }
+
+ /*
+ * Compute the sample delay factor that corresponds to the ideal sample
+ * delay. If the result is too large, then use the maximum allowed
+ * value.
+ *
+ * Notice that we use the ns_to_cycles function to compute the sample
+ * delay factor. We do this because the form of the computation is the
+ * same as that for calculating cycles.
+ */
+ sample_delay_factor =
+ ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift,
+ clock_period_in_ns, 0);
+
+ if (sample_delay_factor > nfc->max_sample_delay_factor)
+ sample_delay_factor = nfc->max_sample_delay_factor;
+
+ /*
+ * These macros conveniently encapsulate a computation we'll use to
+ * continuously evaluate whether or not the data sample delay is inside
+ * the eye.
+ */
+ #define IDEAL_DELAY ((int)ideal_sample_delay_in_ns)
+
+ #define QUANTIZED_DELAY \
+ ((int) ((sample_delay_factor * clock_period_in_ns) >> \
+ dll_delay_shift))
+
+ #define DELAY_ERROR (abs(QUANTIZED_DELAY - IDEAL_DELAY))
+
+ #define SAMPLE_IS_NOT_WITHIN_THE_EYE (DELAY_ERROR > (tEYE >> 1))
+
+ /*
+ * While the quantized sample time falls outside the eye, reduce the
+ * sample delay or extend the data setup to move the sampling point back
+ * toward the eye. Do not allow the number of data setup cycles to
+ * exceed the maximum allowed by the NFC.
+ */
+ while (SAMPLE_IS_NOT_WITHIN_THE_EYE &&
+ (data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+
+ /*
+ * If control arrives here, the quantized sample delay falls
+ * outside the eye. Check if it's before the eye opens, or after
+ * the eye closes.
+ */
+
+ if (QUANTIZED_DELAY > IDEAL_DELAY) {
+ /*
+ * If control arrives here, the quantized sample delay
+ * falls after the eye closes. Decrease the quantized
+ * delay time and then go back to re-evaluate.
+ */
+ if (sample_delay_factor != 0)
+ sample_delay_factor--;
+
+ continue;
+
+ }
+
+ /*
+ * If control arrives here, the quantized sample delay falls
+ * before the eye opens. Shift the sample point by increasing
+ * data setup time. This will also make the eye larger.
+ */
+
+ /* Give a cycle to data setup. */
+ data_setup_in_cycles++;
+ /* Synchronize the data setup time with the cycles. */
+ data_setup_in_ns += clock_period_in_ns;
+ /* Adjust tEYE accordingly. */
+ tEYE += clock_period_in_ns;
+
+ /*
+ * Decrease the ideal sample delay by one half cycle, to keep it
+ * in the middle of the eye.
+ */
+ ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
+
+ /* ...and one less period for the delay time. */
+ ideal_sample_delay_in_ns -= clock_period_in_ns;
+
+ /* Jam a negative ideal sample delay to zero. */
+ if (ideal_sample_delay_in_ns < 0)
+ ideal_sample_delay_in_ns = 0;
+
+ /*
+ * We have a new ideal sample delay, so re-compute the quantized
+ * delay.
+ */
+
+ sample_delay_factor =
+ ns_to_cycles(
+ ideal_sample_delay_in_ns << dll_delay_shift,
+ clock_period_in_ns, 0);
+
+ if (sample_delay_factor > nfc->max_sample_delay_factor)
+ sample_delay_factor = nfc->max_sample_delay_factor;
+
+ }
+
+ /* Control arrives here when we're ready to return our results. */
+
+rtn_rslt:
+ hw_timing->m_u8DataSetup = data_setup_in_cycles;
+ hw_timing->m_u8DataHold = data_hold_in_cycles;
+ hw_timing->m_u8AddressSetup = address_setup_in_cycles;
+ hw_timing->m_u8HalfPeriods = dll_use_half_periods;
+ hw_timing->m_u8SampleDelay = sample_delay_factor;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+}
+
+/**
+ * set_timing() - Configures the NFC timing.
+ *
+ * @this: Per-device data.
+ * @timing: The timing of interest.
+ */
+static int set_timing(struct mtd_info *mtd,
+ const struct gpmi_nfc_timing *timing)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /* Accept the new timing. */
+ nfc->timing = *timing;
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+}
+
+/**
+ * get_timing() - Retrieves the NFC hardware timing.
+ *
+ * @this: Per-device data.
+ * @clock_frequency_in_hz: The clock frequency, in Hz, during the current
+ * I/O transaction. If no I/O transaction is in
+ * progress, this is the clock frequency during the
+ * most recent I/O transaction.
+ * @hardware_timing: The hardware timing configuration in effect during
+ * the current I/O transaction. If no I/O transaction
+ * is in progress, this is the hardware timing
+ * configuration during the most recent I/O
+ * transaction.
+ */
+static void get_timing(struct mtd_info *mtd,
+ unsigned long *clock_frequency_in_hz,
+ struct gpmi_nfc_timing *hardware_timing)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+ u32 register_image;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /* Return the clock frequency. */
+ *clock_frequency_in_hz = nfc->clock_frequency_in_hz;
+
+ /* Retrieve the hardware timing. */
+ register_image = REG_RD(CONFIG_GPMI_REG_BASE, HW_GPMI_TIMING0);
+
+ hardware_timing->m_u8DataSetup =
+ (register_image & BM_GPMI_TIMING0_DATA_SETUP) >>
+ BP_GPMI_TIMING0_DATA_SETUP;
+
+ hardware_timing->m_u8DataHold =
+ (register_image & BM_GPMI_TIMING0_DATA_HOLD) >>
+ BP_GPMI_TIMING0_DATA_HOLD;
+
+ hardware_timing->m_u8AddressSetup =
+ (register_image & BM_GPMI_TIMING0_ADDRESS_SETUP) >>
+ BP_GPMI_TIMING0_ADDRESS_SETUP;
+
+ register_image = REG_RD(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1);
+
+ hardware_timing->m_u8HalfPeriods =
+ (register_image & BM_GPMI_CTRL1_HALF_PERIOD) >>
+ BP_GPMI_CTRL1_HALF_PERIOD;
+
+ hardware_timing->m_u8SampleDelay =
+ (register_image & BM_GPMI_CTRL1_RDN_DELAY) >>
+ BP_GPMI_CTRL1_RDN_DELAY;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * exit() - Shuts down the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static void exit(struct mtd_info *mtd)
+{
+ int i;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ for (i = 0; i < NFC_DMA_DESCRIPTOR_COUNT; ++i)
+ mxs_dma_free_desc(dma_desc[i]);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * begin() - Begin NFC I/O.
+ *
+ * @this: Per-device data.
+ */
+static void begin(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+ struct gpmi_nfc_timing hw_timing;
+#if defined(CONFIG_GPMI_NFC_V0)
+ u32 clock_period_in_ns;
+ u32 register_image;
+ u32 dll_wait_time_in_us;
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /* Get the timing information we need. */
+ nfc->clock_frequency_in_hz = mxc_get_clock(MXC_GPMI_CLK);
+#if defined(CONFIG_GPMI_NFC_V0)
+ clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz;
+#endif
+ calculte_hw_timing(mtd, &(nfc->timing), &hw_timing);
+
+#if defined(CONFIG_GPMI_NFC_V0)
+ /* Set up all the simple timing parameters. */
+ register_image =
+ BF_GPMI_TIMING0_ADDRESS_SETUP(hw_timing.m_u8AddressSetup) |
+ BF_GPMI_TIMING0_DATA_HOLD(hw_timing.m_u8DataHold) |
+ BF_GPMI_TIMING0_DATA_SETUP(hw_timing.m_u8DataSetup) ;
+ writel(register_image, CONFIG_GPMI_REG_BASE + HW_GPMI_TIMING0);
+
+ /*
+ * HEY - PAY ATTENTION!
+ *
+ * DLL_ENABLE must be set to zero when setting RDN_DELAY or HALF_PERIOD.
+ */
+ REG_CLR(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_DLL_ENABLE)
+
+ /* Clear out the DLL control fields. */
+ REG_CLR(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_RDN_DELAY);
+ REG_CLR(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_HALF_PERIOD);
+
+ /* If no sample delay is called for, return immediately. */
+ if (!hw.sample_delay_factor)
+ return;
+
+ /* Configure the HALF_PERIOD flag. */
+ if (hw.use_half_periods)
+ REG_SET(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_HALF_PERIOD);
+
+ /* Set the delay factor. */
+ REG_SET(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BF_GPMI_CTRL1_RDN_DELAY(hw_timing.sample_delay_factor));
+
+ /* Enable the DLL. */
+ REG_SET(CONFIG_GPMI_REG_BASE, HW_GPMI_CTRL1,
+ BM_GPMI_CTRL1_DLL_ENABLE);
+
+ /*
+ * After we enable the GPMI DLL, we have to wait 64 clock cycles before
+ * we can use the GPMI.
+ *
+ * Calculate the amount of time we need to wait, in microseconds.
+ */
+
+ dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
+
+ if (!dll_wait_time_in_us)
+ dll_wait_time_in_us = 1;
+
+ /* Wait for the DLL to settle. */
+ udelay(dll_wait_time_in_us);
+#endif
+ /* Apply the hardware timing. */
+
+ /* Coming soon - the clock handling code isn't ready yet. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * end() - End NFC I/O.
+ *
+ * @this: Per-device data.
+ */
+static void end(struct mtd_info *mtd)
+{
+ /* Disable the clock. */
+}
+
+/**
+ * clear_bch() - Clears a BCH interrupt.
+ *
+ * @this: Per-device data.
+ */
+static void clear_bch(struct mtd_info *mtd)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+ REG_CLR(CONFIG_BCH_REG_BASE, HW_BCH_CTRL,
+ BM_BCH_CTRL_COMPLETE_IRQ);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<=%s\n", __func__);
+}
+
+/**
+ * is_ready() - Returns the ready/busy status of the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ */
+static int is_ready(struct mtd_info *mtd, unsigned int target_chip)
+{
+ u32 mask;
+ u32 register_image;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /* Extract and return the status. */
+#if defined(CONFIG_GPMI_NFC_V0)
+ mask = BM_GPMI_DEBUG_READY0 << target_chip;
+
+ register_image = REG_RD(CONFIG_GPMI_REG_BASE, HW_GPMI_DEBUG);
+#else
+ mask = BF_GPMI_STAT_READY_BUSY(1 << 0);
+
+ register_image = REG_RD(CONFIG_GPMI_REG_BASE, HW_GPMI_STAT);
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return register_image & mask;
+}
+
+/**
+ * send_command() - Sends a command and associated addresses.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that contains the command bytes.
+ * @length: The number of bytes in the buffer.
+ */
+static int send_command(struct mtd_info *mtd, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct mxs_dma_desc **d = dma_desc;
+ s32 dma_channel;
+ s32 error;
+ u32 command_mode;
+ u32 address;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "Chip: %d DMA Buf: 0x%08x Length: %d\n",
+ chip, buffer, length);
+
+#ifdef CONFIG_ARCH_MMU
+ /* FIXME: I don't know why this delay is needed.
+ * But with this delay, nand operations can be ok.
+ */
+ udelay(200);
+#endif
+
+ /* Compute the DMA channel. */
+ dma_channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + chip;
+
+ /* A DMA descriptor that sends out the command. */
+
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_CLE;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "1st Command: mode: %d, address: %d, ",
+ command_mode, address);
+
+ /* reset the cmd bits fieled */
+ (*d)->cmd.cmd.data = 0;
+
+ (*d)->cmd.cmd.bits.command = DMA_READ;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.chain = 0;
+#else
+ (*d)->cmd.cmd.bits.chain = 1;
+#endif
+ (*d)->cmd.cmd.bits.irq = 1;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 0;
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+ (*d)->cmd.cmd.bits.wait4end = 1;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.halt_on_terminate = 1;
+#else
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+#endif
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 3;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+#ifdef CONFIG_ARCH_MMU
+ (*d)->cmd.address = iomem_to_phys(buffer);
+#else
+ (*d)->cmd.address = buffer;
+#endif
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BM_GPMI_CTRL0_ADDRESS_INCREMENT |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "PIO Words[0]: 0x%08x, "
+ "PIO Words[1]: 0x%08x, PIO Words[2]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0],
+ (unsigned int)(*d)->cmd.pio_words[1],
+ (unsigned int)(*d)->cmd.pio_words[2]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+ error = mxs_dma_go(dma_channel);
+
+ if (error)
+ printf("[%s] DMA error\n", __func__);
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return error;
+}
+
+/**
+ * send_data() - Sends data to the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that contains the data.
+ * @length: The number of bytes in the buffer.
+ */
+static int send_data(struct mtd_info *mtd, unsigned chip,
+ dma_addr_t buffer, unsigned length)
+{
+ struct mxs_dma_desc **d = dma_desc;
+ int dma_channel;
+ int error = 0;
+ u32 command_mode;
+ u32 address;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Chip: %d DMA Buf: 0x%08x Length: %d\n",
+ chip, buffer, length);
+
+ /* Compute the DMA channel. */
+ dma_channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + chip;
+
+ /* A DMA descriptor that writes a buffer out. */
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "1st Command: mode: %d, address: %d, ",
+ command_mode, address);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = DMA_READ;
+ (*d)->cmd.cmd.bits.chain = 0;
+ (*d)->cmd.cmd.bits.irq = 1;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 0;
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+ (*d)->cmd.cmd.bits.wait4end = 1;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 4;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+#ifdef CONFIG_ARCH_MMU
+ (*d)->cmd.address = iomem_to_phys(buffer);
+#else
+ (*d)->cmd.address = buffer;
+#endif
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "PIO Words[0]: 0x%08x, "
+ "PIO Words[1]: 0x%08x, PIO Words[2]: 0x%08x, "
+ "PIO Words[3]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0],
+ (unsigned int)(*d)->cmd.pio_words[1],
+ (unsigned int)(*d)->cmd.pio_words[2],
+ (unsigned int)(*d)->cmd.pio_words[3]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+ error = mxs_dma_go(dma_channel);
+
+ if (error)
+ printf("[%s] DMA error\n", __func__);
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return error;
+
+}
+
+/**
+ * read_data() - Receives data from the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that will receive the data.
+ * @length: The number of bytes to read.
+ */
+static int read_data(struct mtd_info *mtd, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct mxs_dma_desc **d = dma_desc;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Chip: %d DMA Buf: 0x%08x Length: %d\n",
+ chip, buffer, length);
+
+ /* Compute the DMA channel. */
+ dma_channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + chip;
+
+ /* A DMA descriptor that reads the data. */
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "1st Command: mode: %d, address: %d, ",
+ command_mode, address);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = DMA_WRITE;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.chain = 0;
+ (*d)->cmd.cmd.bits.irq = 1;
+#else
+ (*d)->cmd.cmd.bits.chain = 1;
+ (*d)->cmd.cmd.bits.irq = 0;
+#endif
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 0;
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+ (*d)->cmd.cmd.bits.wait4end = 1;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.halt_on_terminate = 1;
+#else
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+#endif
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 1;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+#ifdef CONFIG_ARCH_MMU
+ (*d)->cmd.address = iomem_to_phys(buffer);
+#else
+ (*d)->cmd.address = buffer;
+#endif
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "PIO Words[0]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+#if !defined(CONFIG_GPMI_NFC_V2)
+ /*
+ * A DMA descriptor that waits for the command to end and the chip to
+ * become ready.
+ *
+ * I think we actually should *not* be waiting for the chip to become
+ * ready because, after all, we don't care. I think the original code
+ * did that and no one has re-thought it yet.
+ */
+
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "2nd Command: mode: %d, address: %d\n",
+ command_mode, address);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
+ (*d)->cmd.cmd.bits.chain = 0;
+ (*d)->cmd.cmd.bits.irq = 1;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 1;
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+ (*d)->cmd.cmd.bits.wait4end = 1;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 4;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "PIO Words[0]: 0x%08x, "
+ "PIO Words[1]: 0x%08x, "
+ "PIO Words[2]: 0x%08x, "
+ "PIO Words[3]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0],
+ (unsigned int)(*d)->cmd.pio_words[1],
+ (unsigned int)(*d)->cmd.pio_words[2],
+ (unsigned int)(*d)->cmd.pio_words[3]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+#endif
+ /* Go! */
+ error = mxs_dma_go(dma_channel);
+
+ if (error)
+ printf("[%s] DMA error\n", __func__);
+
+#ifdef CONFIG_MTD_DEBUG
+ {
+ int i;
+ dma_addr_t *tmp_buf_ptr = (dma_addr_t *)buffer;
+
+ printf("Buffer:");
+ for (i = 0; i < length; ++i)
+ printf("0x%08x ", tmp_buf_ptr[i]);
+ printf("\n");
+ }
+#endif
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return error;
+
+}
+
+int wait_for_bch_completion(u32 timeout)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ while ((!(REG_RD(CONFIG_BCH_REG_BASE, HW_BCH_CTRL) & 0x1)) &&
+ --timeout)
+ ;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return (timeout > 0) ? 0 : 1;
+}
+
+/**
+ * send_page() - Sends a page, using ECC.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @payload: The physical address of the payload buffer.
+ * @auxiliary: The physical address of the auxiliary buffer.
+ */
+static int send_page(struct mtd_info *mtd, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary)
+{
+ struct mxs_dma_desc **d = dma_desc;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+ uint32_t ecc_command;
+ uint32_t buffer_mask;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Chip: %d DMA Buf payload: 0x%08x "
+ "auxiliary: 0x%08x\n",
+ chip, payload, auxiliary);
+ /* Compute the DMA channel. */
+ dma_channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + chip;
+
+ /* A DMA descriptor that does an ECC page read. */
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+#if defined(CONFIG_GPMI_NFC_V0)
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
+#else
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__ENCODE;
+#endif
+ buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "1st Command: mode: %d, address: %d, "
+ "ecc command: %d, buffer_mask: %d",
+ command_mode, address, ecc_command, buffer_mask);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
+ (*d)->cmd.cmd.bits.chain = 0;
+ (*d)->cmd.cmd.bits.irq = 1;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 0;
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+ (*d)->cmd.cmd.bits.wait4end = 1;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 6;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+
+ (*d)->cmd.pio_words[2] =
+ BM_GPMI_ECCCTRL_ENABLE_ECC |
+ BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+
+ (*d)->cmd.pio_words[3] = (mtd->writesize + mtd->oobsize);
+#ifdef CONFIG_ARCH_MMU
+ (*d)->cmd.pio_words[4] = iomem_to_phys(payload);
+ (*d)->cmd.pio_words[5] = iomem_to_phys(auxiliary);
+#else
+ (*d)->cmd.pio_words[4] = payload;
+ (*d)->cmd.pio_words[5] = auxiliary;
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "PIO Words[0]: 0x%08x, "
+ "PIO Words[1]: 0x%08x, "
+ "PIO Words[2]: 0x%08x, "
+ "PIO Words[3]: 0x%08x, "
+ "PIO Words[4]: 0x%08x, "
+ "PIO Words[5]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0],
+ (unsigned int)(*d)->cmd.pio_words[1],
+ (unsigned int)(*d)->cmd.pio_words[2],
+ (unsigned int)(*d)->cmd.pio_words[3],
+ (unsigned int)(*d)->cmd.pio_words[4],
+ (unsigned int)(*d)->cmd.pio_words[5]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+ error = mxs_dma_go(dma_channel);
+
+ if (error)
+ printf("[%s] DMA error\n", __func__);
+
+ error = wait_for_bch_completion(10000);
+
+ error = (error) ? -ETIMEDOUT : 0;
+
+ if (error)
+ printf("[%s] bch timeout!!!\n", __func__);
+
+ clear_bch(NULL);
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return error;
+}
+
+/**
+ * read_page() - Reads a page, using ECC.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @payload: The physical address of the payload buffer.
+ * @auxiliary: The physical address of the auxiliary buffer.
+ */
+static int read_page(struct mtd_info *mtd, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary)
+{
+ struct mxs_dma_desc **d = dma_desc;
+ s32 dma_channel;
+ s32 error = 0;
+ u32 command_mode;
+ u32 address;
+ u32 ecc_command;
+ u32 buffer_mask;
+ u32 page_size = mtd->writesize + mtd->oobsize;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Chip: %d DMA Buf payload: 0x%08x "
+ "auxiliary: 0x%08x\n",
+ chip, payload, auxiliary);
+ /* Compute the DMA channel. */
+ dma_channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + chip;
+
+ /* Wait for the chip to report ready. */
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "1st Command: mode: %d, address: %d",
+ command_mode, address);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
+ (*d)->cmd.cmd.bits.chain = 1;
+ (*d)->cmd.cmd.bits.irq = 0;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 1;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.dec_sem = 0;
+#else
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+#endif
+ (*d)->cmd.cmd.bits.wait4end = 1;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 1;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "PIO Words[0]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Enable the BCH block and read. */
+
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+#if defined(CONFIG_GPMI_NFC_V0)
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
+#else
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__DECODE;
+#endif
+ buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "2nd Command: mode: %d, address: %d, "
+ "ecc command: %d, buffer_mask: %d",
+ command_mode, address, ecc_command, buffer_mask);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
+ (*d)->cmd.cmd.bits.chain = 1;
+ (*d)->cmd.cmd.bits.irq = 0;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 0;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.dec_sem = 0;
+#else
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+#endif
+ (*d)->cmd.cmd.bits.wait4end = 1;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 6;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(page_size) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] =
+ BM_GPMI_ECCCTRL_ENABLE_ECC |
+ BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+ (*d)->cmd.pio_words[3] = page_size;
+#ifdef CONFIG_ARCH_MMU
+ (*d)->cmd.pio_words[4] = iomem_to_phys(payload);
+ (*d)->cmd.pio_words[5] = iomem_to_phys(auxiliary);
+#else
+ (*d)->cmd.pio_words[4] = payload;
+ (*d)->cmd.pio_words[5] = auxiliary;
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "PIO Words[0]: 0x%08x, "
+ "PIO Words[1]: 0x%08x, "
+ "PIO Words[2]: 0x%08x, "
+ "PIO Words[3]: 0x%08x, "
+ "PIO Words[4]: 0x%08x, "
+ "PIO Words[5]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0],
+ (unsigned int)(*d)->cmd.pio_words[1],
+ (unsigned int)(*d)->cmd.pio_words[2],
+ (unsigned int)(*d)->cmd.pio_words[3],
+ (unsigned int)(*d)->cmd.pio_words[4],
+ (unsigned int)(*d)->cmd.pio_words[5]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Disable the BCH block */
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "3rd Command: mode: %d, address: %d",
+ command_mode, address);
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
+ (*d)->cmd.cmd.bits.chain = 1;
+ (*d)->cmd.cmd.bits.irq = 0;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 1;
+#if defined(CONFIG_GPMI_NFC_V2)
+ (*d)->cmd.cmd.bits.dec_sem = 0;
+#else
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+#endif
+ (*d)->cmd.cmd.bits.wait4end = 1;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 3;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(page_size) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "PIO Words[0]: 0x%08x, "
+ "PIO Words[1]: 0x%08x, "
+ "PIO Words[2]: 0x%08x\n",
+ (unsigned int)(*d)->cmd.pio_words[0],
+ (unsigned int)(*d)->cmd.pio_words[1],
+ (unsigned int)(*d)->cmd.pio_words[2]);
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Deassert the NAND lock and interrupt. */
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
+ (*d)->cmd.cmd.bits.chain = 0;
+ (*d)->cmd.cmd.bits.irq = 1;
+ (*d)->cmd.cmd.bits.nand_lock = 0;
+ (*d)->cmd.cmd.bits.nand_wait_4_ready = 0;
+ (*d)->cmd.cmd.bits.dec_sem = 1;
+ (*d)->cmd.cmd.bits.wait4end = 0;
+ (*d)->cmd.cmd.bits.halt_on_terminate = 0;
+ (*d)->cmd.cmd.bits.terminate_flush = 0;
+ (*d)->cmd.cmd.bits.pio_words = 0;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+ error = mxs_dma_go(dma_channel);
+
+ if (error)
+ printf("[%s] DMA error\n", __func__);
+
+ error = wait_for_bch_completion(10000);
+
+ error = (error) ? -ETIMEDOUT : 0;
+
+ if (error)
+ printf("[%s] bch timeout!!!\n", __func__);
+
+ clear_bch(NULL);
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return error;
+}
+
+/* This structure represents the NFC HAL for this version of the hardware. */
+struct nfc_hal gpmi_nfc_hal = {
+#if defined(CONFIG_GPMI_NFC_V0)
+ .version = 0,
+ .description = "4-chip GPMI and BCH",
+ .max_chip_count = 4,
+#else
+#if defined(CONFIG_GPMI_NFC_V1)
+ .version = 1,
+#else
+ .version = 2,
+#endif
+ .description = "8-chip GPMI and BCH",
+ .max_chip_count = 8,
+#endif
+ .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
+ BP_GPMI_TIMING0_DATA_SETUP),
+ .internal_data_setup_in_ns = 0,
+ .max_sample_delay_factor = (BM_GPMI_CTRL1_RDN_DELAY >>
+ BP_GPMI_CTRL1_RDN_DELAY),
+ .max_dll_clock_period_in_ns = 32,
+ .max_dll_delay_in_ns = 16,
+ .init = init,
+ .set_geometry = set_geometry,
+ .set_timing = set_timing,
+ .get_timing = get_timing,
+ .exit = exit,
+ .begin = begin,
+ .end = end,
+ .clear_bch = clear_bch,
+ .is_ready = is_ready,
+ .send_command = send_command,
+ .send_data = send_data,
+ .read_data = read_data,
+ .send_page = send_page,
+ .read_page = read_page,
+};
diff --git a/drivers/mtd/nand/gpmi_nfc_mil.c b/drivers/mtd/nand/gpmi_nfc_mil.c
new file mode 100644
index 0000000..e63071e
--- /dev/null
+++ b/drivers/mtd/nand/gpmi_nfc_mil.c
@@ -0,0 +1,1187 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * 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.
+ */
+
+#include <linux/mtd/mtd.h>
+#include "gpmi_nfc_gpmi.h"
+#include "gpmi_nfc_bch.h"
+#include "nand_device_info.h"
+#include <linux/mtd/nand.h>
+#include <linux/types.h>
+#include <asm/apbh_dma.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <common.h>
+
+#ifdef CONFIG_ARCH_MMU
+#include <asm/arch/mmu.h>
+#endif
+
+/**
+ * gpmi_nfc_cmd_ctrl - MTD Interface cmd_ctrl()
+ *
+ * This is the function that we install in the cmd_ctrl function pointer of the
+ * owning struct nand_chip. The only functions in the reference implementation
+ * that use these functions pointers are cmdfunc and select_chip.
+ *
+ * In this driver, we implement our own select_chip, so this function will only
+ * be called by the reference implementation's cmdfunc. For this reason, we can
+ * ignore the chip enable bit and concentrate only on sending bytes to the
+ * NAND Flash.
+ *
+ * @mtd: The owning MTD.
+ * @data: The value to push onto the data signals.
+ * @ctrl: The values to push onto the control signals.
+ */
+static void gpmi_nfc_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+ int error;
+ u32 *cmd_queue = gpmi_info->cmd_queue;
+ u32 *cmd_Q_len = &(gpmi_info->cmd_Q_len);
+#if defined(CONFIG_MTD_DEBUG)
+ unsigned int i;
+ char display[GPMI_NFC_COMMAND_BUFFER_SIZE * 5];
+#endif
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "%s =>\n", __func__);
+
+ /*
+ * Every operation begins with a command byte and a series of zero or
+ * more address bytes. These are distinguished by either the Address
+ * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
+ * asserted. When MTD is ready to execute the command, it will
+ * deasert both latch enables.
+ *
+ * Rather than run a separate DMA operation for every single byte, we
+ * queue them up and run a single DMA operation for the entire series
+ * of command and data bytes.
+ */
+
+ if ((ctrl & (NAND_ALE | NAND_CLE))) {
+ if (data != NAND_CMD_NONE)
+ cmd_queue[(*cmd_Q_len)++] = data;
+ return;
+ }
+
+ /*
+ * If control arrives here, MTD has deasserted both the ALE and CLE,
+ * which means it's ready to run an operation. Check if we have any
+ * bytes to send.
+ */
+
+ if (!(*cmd_Q_len))
+ return;
+
+#if defined(CONFIG_MTD_DEBUG)
+ display[0] = 0;
+ for (i = 0; i < (*cmd_Q_len); i++)
+ sprintf(display + strlen(display),
+ " 0x%02x", cmd_queue[i] & 0xff);
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "%s: command: %s\n", __func__, display);
+#endif
+
+#ifdef CONFIG_ARCH_MMU
+ error = nfc->send_command(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)iomem_to_phys((u32)cmd_queue), (*cmd_Q_len));
+#else
+ error = nfc->send_command(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)cmd_queue, (*cmd_Q_len));
+#endif
+
+ if (error)
+ printf("Command execute failed!\n");
+
+ /* Reset. */
+ (*cmd_Q_len) = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "<= %s\n", __func__);
+}
+
+/**
+ * gpmi_nfc_dev_ready() - MTD Interface dev_ready()
+ *
+ * @mtd: A pointer to the owning MTD.
+ */
+static int gpmi_nfc_dev_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ return (nfc->is_ready(mtd, gpmi_info->cur_chip)) ? 1 : 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * gpmi_nfc_select_chip() - MTD Interface select_chip()
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @chip: The chip number to select, or -1 to select no chip.
+ */
+static void gpmi_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = nand->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "%s =>\n", __func__);
+
+ nfc->begin(mtd);
+
+ gpmi_info->cur_chip = chip;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL2, "<= %s\n", __func__);
+}
+
+/**
+ * gpmi_nfc_read_buf() - MTD Interface read_buf().
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @buf: The destination buffer.
+ * @len: The number of bytes to read.
+ */
+static void gpmi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ if (len > NAND_MAX_PAGESIZE)
+ printf("[%s] Inadequate DMA buffer\n", __func__);
+
+ if (!buf)
+ printf("[%s] Buffer pointer is NULL\n", __func__);
+
+ /* Ask the NFC. */
+#ifdef CONFIG_ARCH_MMU
+ nfc->read_data(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)iomem_to_phys((u32)gpmi_info->data_buf),
+ len);
+#else
+ nfc->read_data(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)gpmi_info->data_buf, len);
+#endif
+
+ memcpy(buf, gpmi_info->data_buf, len);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * gpmi_nfc_write_buf() - MTD Interface write_buf().
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @buf: The source buffer.
+ * @len: The number of bytes to read.
+ */
+static void gpmi_nfc_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ if (len > NAND_MAX_PAGESIZE)
+ printf("[%s] Inadequate DMA buffer\n", __func__);
+
+ if (!buf)
+ printf("[%s] Buffer pointer is NULL\n", __func__);
+
+ memcpy(gpmi_info->data_buf, buf, len);
+
+ /* Ask the NFC. */
+#ifdef CONFIG_ARCH_MMU
+ nfc->send_data(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)iomem_to_phys((u32)gpmi_info->data_buf),
+ len);
+#else
+ nfc->send_data(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)gpmi_info->data_buf, len);
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * gpmi_nfc_read_byte() - MTD Interface read_byte().
+ *
+ * @mtd: A pointer to the owning MTD.
+ */
+static uint8_t gpmi_nfc_read_byte(struct mtd_info *mtd)
+{
+ u8 byte;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ gpmi_nfc_read_buf(mtd, (u8 *)&byte, 1);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return byte;
+}
+
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+/**
+ * gpmi_nfc_block_mark_swapping() - Handles block mark swapping.
+ *
+ * Note that, when this function is called, it doesn't know whether it's
+ * swapping the block mark, or swapping it *back* -- but it doesn't matter
+ * because the the operation is the same.
+ *
+ * @this: Per-device data.
+ * @payload: A pointer to the payload buffer.
+ * @auxiliary: A pointer to the auxiliary buffer.
+ */
+static void gpmi_nfc_block_mark_swapping(struct gpmi_nfc_info *gpmi_info,
+ void *data_buf, void *oob_buf)
+{
+ u8 *p;
+ u8 *a;
+ u32 bit;
+ u8 mask;
+ u8 from_data;
+ u8 from_oob;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+ /*
+ * If control arrives here, we're swapping. Make some convenience
+ * variables.
+ */
+ bit = gpmi_info->m_u32BlkMarkBitStart;
+ p = ((u8 *)data_buf) + gpmi_info->m_u32BlkMarkByteOfs;
+ a = oob_buf;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Block mark byte offset: %d, "
+ "bit offset: %d",
+ gpmi_info->m_u32BlkMarkByteOfs,
+ gpmi_info->m_u32BlkMarkBitStart);
+
+ /*
+ * Get the byte from the data area that overlays the block mark. Since
+ * the ECC engine applies its own view to the bits in the page, the
+ * physical block mark won't (in general) appear on a byte boundary in
+ * the data.
+ */
+ from_data = (p[0] >> bit) | (p[1] << (8 - bit));
+
+ /* Get the byte from the OOB. */
+ from_oob = a[0];
+
+ /* Swap them. */
+ a[0] = from_data;
+
+ mask = (0x1 << bit) - 1;
+ p[0] = (p[0] & mask) | (from_oob << bit);
+
+ mask = ~0 << bit;
+ p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+#endif
+
+/**
+ * gpmi_nfc_ecc_read_page() - MTD Interface ecc.read_page().
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @nand: A pointer to the owning NAND Flash MTD.
+ * @buf: A pointer to the destination buffer.
+ */
+static int gpmi_nfc_ecc_read_page(struct mtd_info *mtd,
+ struct nand_chip *nand, uint8_t *buf)
+{
+ struct gpmi_nfc_info *gpmi_info = nand->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+ unsigned int i;
+ unsigned char *status;
+ unsigned int failed;
+ unsigned int corrected;
+ int error = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Buf: 0x%08x, data_buf: 0x%08x, "
+ "oob_buf: 0x%08x",
+ buf, gpmi_info->data_buf, gpmi_info->oob_buf);
+ /* Ask the NFC. */
+#ifdef CONFIG_ARCH_MMU
+ error = nfc->read_page(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)iomem_to_phys((u32)gpmi_info->data_buf),
+ (dma_addr_t)iomem_to_phys((u32)gpmi_info->oob_buf));
+#else
+ error = nfc->read_page(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)gpmi_info->data_buf,
+ (dma_addr_t)gpmi_info->oob_buf);
+#endif
+ if (error) {
+ printf("[%s] Error in ECC-based read: %d\n",
+ __func__, error);
+ goto exit;
+ }
+
+ /* Handle block mark swapping. */
+ gpmi_nfc_block_mark_swapping(gpmi_info, gpmi_info->data_buf,
+ gpmi_info->oob_buf);
+
+ /* Loop over status bytes, accumulating ECC status. */
+ failed = 0;
+ corrected = 0;
+
+ status = ((u8 *)gpmi_info->oob_buf) +
+ gpmi_info->m_u32AuxStsOfs;
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Auxiliary status offset: %d, "
+ "Ecc chunk cnt: %d\n",
+ gpmi_info->m_u32AuxStsOfs, gpmi_info->m_u32EccChunkCnt);
+
+ for (i = 0; i < gpmi_info->m_u32EccChunkCnt; i++, status++) {
+
+ if ((*status == 0x00) || (*status == 0xff))
+ continue;
+
+ if (*status == 0xfe) {
+ failed++;
+ continue;
+ }
+
+ corrected += *status;
+ }
+
+ /* Propagate ECC status to the owning MTD. */
+ mtd->ecc_stats.failed += failed;
+ mtd->ecc_stats.corrected += corrected;
+
+ /*
+ * It's time to deliver the OOB bytes. See gpmi_nfc_ecc_read_oob() for
+ * details about our policy for delivering the OOB.
+ *
+ * We fill the caller's buffer with set bits, and then copy the block
+ * mark to th caller's buffer. Note that, if block mark swapping was
+ * necessary, it has already been done, so we can rely on the first
+ * byte of the auxiliary buffer to contain the block mark.
+ */
+ memset(nand->oob_poi, ~0, mtd->oobsize);
+
+ nand->oob_poi[0] = ((u8 *)gpmi_info->oob_buf)[0];
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "nand->oob_poi[0]: 0x%02x\n",
+ nand->oob_poi[0]);
+
+ /* Return. */
+ memcpy(buf, gpmi_info->data_buf, mtd->writesize);
+exit:
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return error;
+}
+
+/**
+ * gpmi_nfc_ecc_write_page() - MTD Interface ecc.write_page().
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @nand: A pointer to the owning NAND Flash MTD.
+ * @buf: A pointer to the source buffer.
+ */
+static void gpmi_nfc_ecc_write_page(struct mtd_info *mtd,
+ struct nand_chip *nand, const uint8_t *buf)
+{
+ struct gpmi_nfc_info *gpmi_info = nand->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+ int error;
+ u8 *data_buf = gpmi_info->data_buf;
+ u8 *oob_buf = gpmi_info->oob_buf;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Buf: 0x%08x, data_buf: 0x%08x, "
+ "oob_buf: 0x%08x\n", buf, data_buf, oob_buf);
+
+ memcpy(data_buf, buf, mtd->writesize);
+ memcpy(oob_buf, nand->oob_poi, mtd->oobsize);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "oob_buf[0]: 0x%02x\n",
+ oob_buf[0]);
+
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ /* Handle block mark swapping. */
+ gpmi_nfc_block_mark_swapping(gpmi_info,
+ (void *)data_buf,
+ (void *)oob_buf);
+#endif
+ /* Ask the NFC. */
+#ifdef CONFIG_ARCH_MMU
+ error = nfc->send_page(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)iomem_to_phys((u32)data_buf),
+ (dma_addr_t)iomem_to_phys((u32)oob_buf));
+#else
+ error = nfc->send_page(mtd, gpmi_info->cur_chip,
+ (dma_addr_t)data_buf,
+ (dma_addr_t)oob_buf);
+#endif
+
+ if (error)
+ printf("[%s] Error in ECC-based write: %d\n",
+ __func__, error);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+}
+
+/**
+ * gpmi_nfc_hook_read_oob() - Hooked MTD Interface read_oob().
+ *
+ * This function is a veneer that replaces the function originally installed by
+ * the NAND Flash MTD code. See the description of the raw_oob_mode field in
+ * struct mil for more information about this.
+ *
+ * @mtd: A pointer to the MTD.
+ * @from: The starting address to read.
+ * @ops: Describes the operation.
+ */
+static int gpmi_nfc_hook_read_oob(struct mtd_info *mtd,
+ loff_t from, struct mtd_oob_ops *ops)
+{
+ register struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ int ret;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ gpmi_info->m_u8RawOOBMode = ops->mode == MTD_OOB_RAW;
+ ret = gpmi_info->hooked_read_oob(mtd, from, ops);
+ gpmi_info->m_u8RawOOBMode = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return ret;
+}
+
+/**
+ * gpmi_nfc_hook_write_oob() - Hooked MTD Interface write_oob().
+ *
+ * This function is a veneer that replaces the function originally installed by
+ * the NAND Flash MTD code. See the description of the raw_oob_mode field in
+ * struct mil for more information about this.
+ *
+ * @mtd: A pointer to the MTD.
+ * @to: The starting address to write.
+ * @ops: Describes the operation.
+ */
+static int gpmi_nfc_hook_write_oob(struct mtd_info *mtd,
+ loff_t to, struct mtd_oob_ops *ops)
+{
+ register struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ int ret;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ gpmi_info->m_u8RawOOBMode = ops->mode == MTD_OOB_RAW;
+ ret = gpmi_info->hooked_write_oob(mtd, to, ops);
+ gpmi_info->m_u8RawOOBMode = false;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return ret;
+}
+
+/**
+ * gpmi_nfc_hook_block_markbad() - Hooked MTD Interface block_markbad().
+ *
+ * This function is a veneer that replaces the function originally installed by
+ * the NAND Flash MTD code. See the description of the marking_a_bad_block field
+ * in struct mil for more information about this.
+ *
+ * @mtd: A pointer to the MTD.
+ * @ofs: Byte address of the block to mark.
+ */
+static int gpmi_nfc_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ register struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = chip->priv;
+ int ret;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ gpmi_info->m_u8MarkingBadBlock = 1;
+ ret = gpmi_info->hooked_block_markbad(mtd, ofs);
+ gpmi_info->m_u8MarkingBadBlock = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return ret;
+}
+
+/**
+ * gpmi_nfc_ecc_read_oob() - MTD Interface ecc.read_oob().
+ *
+ * There are several places in this driver where we have to handle the OOB and
+ * block marks. This is the function where things are the most complicated, so
+ * this is where we try to explain it all. All the other places refer back to
+ * here.
+ *
+ * These are the rules, in order of decreasing importance:
+ *
+ * 1) Nothing the caller does can be allowed to imperil the block mark, so all
+ * write operations take measures to protect it.
+ *
+ * 2) In read operations, the first byte of the OOB we return must reflect the
+ * true state of the block mark, no matter where that block mark appears in
+ * the physical page.
+ *
+ * 3) ECC-based read operations return an OOB full of set bits (since we never
+ * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads
+ * return).
+ *
+ * 4) "Raw" read operations return a direct view of the physical bytes in the
+ * page, using the conventional definition of which bytes are data and which
+ * are OOB. This gives the caller a way to see the actual, physical bytes
+ * in the page, without the distortions applied by our ECC engine.
+ *
+ *
+ * What we do for this specific read operation depends on two questions:
+ *
+ * 1) Are we doing a "raw" read, or an ECC-based read?
+ *
+ * 2) Are we using block mark swapping or transcription?
+ *
+ * There are four cases, illustrated by the following Karnaugh map:
+ *
+ * | Raw | ECC-based |
+ * -------------+-------------------------+-------------------------+
+ * | Read the conventional | |
+ * | OOB at the end of the | |
+ * Swapping | page and return it. It | |
+ * | contains exactly what | |
+ * | we want. | Read the block mark and |
+ * -------------+-------------------------+ return it in a buffer |
+ * | Read the conventional | full of set bits. |
+ * | OOB at the end of the | |
+ * | page and also the block | |
+ * Transcribing | mark in the metadata. | |
+ * | Copy the block mark | |
+ * | into the first byte of | |
+ * | the OOB. | |
+ * -------------+-------------------------+-------------------------+
+ *
+ * Note that we break rule #4 in the Transcribing/Raw case because we're not
+ * giving an accurate view of the actual, physical bytes in the page (we're
+ * overwriting the block mark). That's OK because it's more important to follow
+ * rule #2.
+ *
+ * It turns out that knowing whether we want an "ECC-based" or "raw" read is not
+ * easy. When reading a page, for example, the NAND Flash MTD code calls our
+ * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
+ * ECC-based or raw view of the page is implicit in which function it calls
+ * (there is a similar pair of ECC-based/raw functions for writing).
+ *
+ * Since MTD assumes the OOB is not covered by ECC, there is no pair of
+ * ECC-based/raw functions for reading or or writing the OOB. The fact that the
+ * caller wants an ECC-based or raw view of the page is not propagated down to
+ * this driver.
+ *
+ * Since our OOB *is* covered by ECC, we need this information. So, we hook the
+ * ecc.read_oob and ecc.write_oob function pointers in the owning
+ * struct mtd_info with our own functions. These hook functions set the
+ * raw_oob_mode field so that, when control finally arrives here, we'll know
+ * what to do.
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @nand: A pointer to the owning NAND Flash MTD.
+ * @page: The page number to read.
+ * @sndcmd: Indicates this function should send a command to the chip before
+ * reading the out-of-band bytes. This is only false for small page
+ * chips that support auto-increment.
+ */
+static int gpmi_nfc_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
+ int page, int sndcmd)
+{
+ struct gpmi_nfc_info *gpmi_info = nand->priv;
+ int block_mark_column;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /*
+ if (sndcmd) {
+ nand->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+ sndcmd = 0;
+ }
+ */
+
+ /*
+ * First, fill in the OOB buffer. If we're doing a raw read, we need to
+ * get the bytes from the physical page. If we're not doing a raw read,
+ * we need to fill the buffer with set bits.
+ */
+ if (gpmi_info->m_u8RawOOBMode) {
+ /*
+ * If control arrives here, we're doing a "raw" read. Send the
+ * command to read the conventional OOB.
+ */
+ nand->cmdfunc(mtd, NAND_CMD_READ0,
+ mtd->writesize, page);
+
+ /* Read out the conventional OOB. */
+ nand->read_buf(mtd, nand->oob_poi, mtd->oobsize);
+ } else {
+ /*
+ * If control arrives here, we're not doing a "raw" read. Fill
+ * the OOB buffer with set bits.
+ */
+ memset(nand->oob_poi, ~0, mtd->oobsize);
+ }
+
+ /*
+ * Now, we want to make sure the block mark is correct. In the
+ * Swapping/Raw case, we already have it. Otherwise, we need to
+ * explicitly read it.
+ */
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ if (!gpmi_info->m_u8RawOOBMode) {
+ /* First, figure out where the block mark is. */
+ block_mark_column = mtd->writesize;
+#else
+ {
+ /* First, figure out where the block mark is. */
+ block_mark_column = 0;
+#endif
+ /* Send the command to read the block mark. */
+ nand->cmdfunc(mtd, NAND_CMD_READ0, block_mark_column, page);
+
+ /* Read the block mark into the first byte of the OOB buffer. */
+ nand->oob_poi[0] = nand->read_byte(mtd);
+ }
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+
+}
+
+/**
+ * gpmi_nfc_ecc_write_oob() - MTD Interface ecc.write_oob().
+ *
+ * @mtd: A pointer to the owning MTD.
+ * @nand: A pointer to the owning NAND Flash MTD.
+ * @page: The page number to write.
+ */
+static int gpmi_nfc_ecc_write_oob(struct mtd_info *mtd,
+ struct nand_chip *nand, int page)
+{
+ struct gpmi_nfc_info *gpmi_info = nand->priv;
+ uint8_t block_mark = 0;
+ int block_mark_column;
+ int status;
+ int error = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+ /*
+ * There are fundamental incompatibilities between the i.MX GPMI NFC and
+ * the NAND Flash MTD model that make it essentially impossible to write
+ * the out-of-band bytes.
+ *
+ * We permit *ONE* exception. If the *intent* of writing the OOB is to
+ * mark a block bad, we can do that.
+ */
+
+ if (gpmi_info->m_u8MarkingBadBlock) {
+ printf("This driver doesn't support writing the OOB\n");
+ error = -EIO;
+ goto exit;
+ }
+
+ /*
+ * If control arrives here, we're marking a block bad. First, figure out
+ * where the block mark is.
+ *
+ * If we're using swapping, the block mark is in the conventional
+ * location. Otherwise, we're using transcription, and the block mark
+ * appears in the first byte of the page.
+ */
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ block_mark_column = mtd->writesize;
+#else
+ block_mark_column = 0;
+#endif
+
+ /* Write the block mark. */
+ nand->cmdfunc(mtd, NAND_CMD_SEQIN, block_mark_column, page);
+ nand->write_buf(mtd, &block_mark, 1);
+ nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+ status = nand->waitfunc(mtd, nand);
+
+ /* Check if it worked. */
+ if (status & NAND_STATUS_FAIL)
+ error = -EIO;
+
+ /* Return. */
+exit:
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return error;
+}
+
+/**
+ * gpmi_nfc_block_bad - Claims all blocks are good.
+ *
+ * In principle, this function is *only* called when the NAND Flash MTD system
+ * isn't allowed to keep an in-memory bad block table, so it is forced to ask
+ * the driver for bad block information.
+ *
+ * In fact, we permit the NAND Flash MTD system to have an in-memory BBT, so
+ * this function is *only* called when we take it away.
+ *
+ * We take away the in-memory BBT when the user sets the "ignorebad" parameter,
+ * which indicates that all blocks should be reported good.
+ *
+ * Thus, this function is only called when we want *all* blocks to look good,
+ * so it *always* return success.
+ *
+ * @mtd: Ignored.
+ * @ofs: Ignored.
+ * @getchip: Ignored.
+ */
+static int gpmi_nfc_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+}
+
+#ifndef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+/**
+ * gpmi_nfc_pre_bbt_scan() - Prepare for the BBT scan.
+ *
+ * @this: Per-device data.
+ */
+static int gpmi_nfc_pre_bbt_scan(struct gpmi_nfc_info *this)
+{
+ /* Not implemented yet */
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+ return 0;
+}
+#endif
+
+/**
+ * gpmi_nfc_scan_bbt() - MTD Interface scan_bbt().
+ *
+ * The HIL calls this function once, when it initializes the NAND Flash MTD.
+ *
+ * Nominally, the purpose of this function is to look for or create the bad
+ * block table. In fact, since the HIL calls this function at the very end of
+ * the initialization process started by nand_scan(), and the HIL doesn't have a
+ * more formal mechanism, everyone "hooks" this function to continue the
+ * initialization process.
+ *
+ * At this point, the physical NAND Flash chips have been identified and
+ * counted, so we know the physical geometry. This enables us to make some
+ * important configuration decisions.
+ *
+ * The return value of this function propogates directly back to this driver's
+ * call to nand_scan(). Anything other than zero will cause this driver to
+ * tear everything down and declare failure.
+ *
+ * @mtd: A pointer to the owning MTD.
+ */
+static int gpmi_nfc_scan_bbt(struct mtd_info *mtd)
+{
+ uint8_t id_bytes[NAND_DEVICE_ID_BYTE_COUNT];
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_info *gpmi_info = nand->priv;
+ struct nfc_hal *nfc = gpmi_info->nfc;
+ struct nand_ecclayout *layout = nand->ecc.layout;
+ int saved_chip_number;
+ struct nand_device_info *dev_info;
+ struct gpmi_nfc_timing timing;
+ int error;
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ u32 blk_mark_bit_offs;
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ /*
+ * Tell MTD users that the out-of-band area can't be written.
+ *
+ * This flag is not part of the standard kernel source tree. It comes
+ * from a patch that touches both MTD and JFFS2.
+ *
+ * The problem is that, without this patch, JFFS2 believes it can write
+ * the data area and the out-of-band area separately. This is wrong for
+ * two reasons:
+ *
+ * 1) Our NFC distributes out-of-band bytes throughout the page,
+ * intermingled with the data, and covered by the same ECC.
+ * Thus, it's not possible to write the out-of-band bytes and
+ * data bytes separately.
+ *
+ * 2) Large page (MLC) Flash chips don't support partial page
+ * writes. You must write the entire page at a time. Thus, even
+ * if our NFC didn't force you to write out-of-band and data
+ * bytes together, it would *still* be a bad idea to do
+ * otherwise.
+ */
+
+ /* mtd->flags &= ~MTD_OOB_WRITEABLE; */
+
+ /*
+ * MTD identified the attached NAND Flash devices, but we have a much
+ * better database that we want to consult. First, we need to gather all
+ * the ID bytes from the first chip (MTD only read the first two).
+ */
+
+ saved_chip_number = gpmi_info->cur_chip;
+
+ /* Read ID bytes from the first NAND Flash chip. */
+ nand->select_chip(mtd, 0);
+
+ nand->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+ nand->read_buf(mtd, id_bytes, NAND_DEVICE_ID_BYTE_COUNT);
+
+ nand->select_chip(mtd, saved_chip_number);
+
+ /* Look up this device in our database. */
+ dev_info = nand_device_get_info(id_bytes);
+
+ /* Check if we understand this device. */
+ if (!dev_info) {
+ printf("Unrecognized NAND Flash device.\n");
+ return !0;
+ }
+
+ /* Display the information we discovered. */
+ nand_device_print_info(dev_info);
+
+ layout->eccbytes = 0;
+
+ /* Correct mtd setting */
+ mtd->size = dev_info->chip_size_in_bytes * nand->numchips;
+ /*
+ mtd->writesize = 1 << (fls(dev_info->page_total_size_in_bytes) - 1);
+ mtd->oobsize = dev_info->page_total_size_in_bytes - mtd->writesize;
+ mtd->erasesize = dev_info->block_size_in_pages * mtd->writesize;
+ */
+ mtd->ecclayout = layout;
+ mtd->oobavail = mtd->oobsize;
+ mtd->oobsize = mtd->oobavail + layout->eccbytes;
+ mtd->subpage_sft = 0; /* We don't support sub-page writing. */
+
+ /* Configure the struct nand_ecclayout. */
+ layout->oobavail = mtd->oobavail;
+ layout->oobfree[0].offset = 0;
+ layout->oobfree[0].length = layout->oobavail;
+
+ /* Configure the struct nand_chip. */
+ /*
+ nand->page_shift = ffs(mtd->writesize) - 1;
+ nand->pagemask = (nand->chipsize >> nand->page_shift) - 1;
+ nand->subpagesize = mtd->writesize >> mtd->subpage_sft;
+ nand->phys_erase_shift = ffs(mtd->erasesize) - 1;
+ nand->bbt_erase_shift = nand->phys_erase_shift;
+ nand->chip_shift = ffs(nand->chipsize) - 1;
+ nand->oob_poi = nand->buffers->databuf + mtd->writesize;
+ */
+ nand->phys_erase_shift = ffs(mtd->erasesize) - 1;
+ nand->ecc.layout = layout;
+ nand->ecc.size = 512;
+ /*
+ nand->ecc.steps = mtd->writesize / nand->ecc.size;
+ nand->ecc.total = nand->ecc.steps * nand->ecc.bytes;
+ */
+ /*
+ if (nand->chipsize & 0xffffffff)
+ nand->chip_shift = ffs((u32)nand->chipsize) - 1;
+ else
+ nand->chip_shift =
+ ffs((u32)(nand->chipsize >> 32)) + 32 - 1;
+ */
+
+ /* limit to 2G size due to Kernel
+ * larger 4G space support,need fix
+ * it later
+ */
+ if ((u32)mtd->size == 0) {
+ mtd->size = (u32)(1 << 31);
+ nand->numchips = 1;
+ nand->chipsize = mtd->size;
+ }
+
+ gpmi_info->m_u32EccChunkCnt = GPMI_NFC_ECC_CHUNK_CNT(mtd->writesize);
+ gpmi_info->m_u32EccStrength =
+ gpmi_nfc_get_ecc_strength(mtd->writesize, mtd->oobsize);
+
+ /* Try to calculate block mark info */
+ gpmi_info->m_u32AuxSize =
+ GPMI_NFC_AUX_SIZE(dev_info->page_total_size_in_bytes);
+ gpmi_info->m_u32AuxStsOfs = GPMI_NFC_AUX_STATUS_OFF;
+
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ blk_mark_bit_offs = gpmi_nfc_get_blk_mark_bit_ofs(mtd->writesize,
+ gpmi_info->m_u32EccStrength);
+
+ gpmi_info->m_u32BlkMarkByteOfs = blk_mark_bit_offs >> 3;
+ gpmi_info->m_u32BlkMarkBitStart = blk_mark_bit_offs & 0x7;
+#endif
+
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "ECC Chunk Cnt: %d, "
+ "Ecc Strength: %d, "
+ "Auxiliary Size: %d, "
+ "Auxiliary Status Offset: %d\n",
+ gpmi_info->m_u32EccChunkCnt, gpmi_info->m_u32EccStrength,
+ gpmi_info->m_u32AuxSize, gpmi_info->m_u32AuxStsOfs);
+
+#ifdef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "Block mark byte offset: %d, "
+ "Block mark bit start: %d\n",
+ gpmi_info->m_u32BlkMarkByteOfs,
+ gpmi_info->m_u32BlkMarkBitStart);
+#endif
+
+ /* Set nfc geo */
+ nfc->set_geometry(mtd);
+
+ /* Set timing */
+ timing.m_u8DataSetup = dev_info->data_setup_in_ns;
+ timing.m_u8DataHold = dev_info->data_hold_in_ns;
+ timing.m_u8AddressSetup = dev_info->address_setup_in_ns;
+ timing.m_u8SampleDelay = dev_info->gpmi_sample_delay_in_ns;
+ timing.m_u8tREA = dev_info->tREA_in_ns;
+ timing.m_u8tRLOH = dev_info->tRLOH_in_ns;
+ timing.m_u8tRHOH = dev_info->tRHOH_in_ns;
+
+ error = nfc->set_timing(mtd, &timing);
+
+ if (error)
+ return error;
+
+#ifndef CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ /* Prepare for the BBT scan. */
+ error = gpmi_nfc_pre_bbt_scan(gpmi_info);
+
+ if (error)
+ return error;
+#endif
+
+ /*
+ * Hook some operations at the MTD level. See the descriptions of the
+ * saved function pointer fields for details about why we hook these.
+ */
+ gpmi_info->hooked_read_oob = mtd->read_oob;
+ mtd->read_oob = gpmi_nfc_hook_read_oob;
+
+ gpmi_info->hooked_write_oob = mtd->write_oob;
+ mtd->write_oob = gpmi_nfc_hook_write_oob;
+
+ gpmi_info->hooked_block_markbad = mtd->block_markbad;
+ mtd->block_markbad = gpmi_nfc_hook_block_markbad;
+
+ /* We use the reference implementation for bad block management. */
+ error = nand_default_bbt(mtd);
+ if (error)
+ return error;
+
+ /* Return success. */
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return 0;
+
+}
+
+static int gpmi_nfc_alloc_buf(struct gpmi_nfc_info *gpmi_info)
+{
+ int err = 0;
+ u8 *pBuf = NULL;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+#ifdef CONFIG_ARCH_MMU
+ pBuf = (u8 *)ioremap_nocache(iomem_to_phys((ulong)memalign(MXS_DMA_ALIGNMENT,
+ NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)),
+ MXS_DMA_ALIGNMENT);
+#else
+ pBuf = (u8 *)memalign(MXS_DMA_ALIGNMENT,
+ NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE);
+#endif
+ if (!pBuf) {
+ printf("%s: failed to allocate buffer\n", __func__);
+ err = -ENOMEM;
+ return err;
+ }
+ memset(pBuf, 0, NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE);
+
+ gpmi_info->data_buf = pBuf;
+ gpmi_info->oob_buf = pBuf + NAND_MAX_PAGESIZE;
+
+#ifdef CONFIG_ARCH_MMU
+ gpmi_info->cmd_queue =
+ (u32 *)ioremap_nocache((u32)iomem_to_phys((ulong)kmalloc(GPMI_NFC_COMMAND_BUFFER_SIZE,
+ GFP_KERNEL)),
+ MXS_DMA_ALIGNMENT);
+#else
+ gpmi_info->cmd_queue =
+ memalign(MXS_DMA_ALIGNMENT, GPMI_NFC_COMMAND_BUFFER_SIZE);
+#endif
+ if (!gpmi_info->cmd_queue) {
+ printf("%s: failed to allocate command queuebuffer\n",
+ __func__);
+ err = -ENOMEM;
+ return err;
+ }
+ memset(gpmi_info->cmd_queue, 0, GPMI_NFC_COMMAND_BUFFER_SIZE);
+ gpmi_info->cmd_Q_len = 0;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return err;
+}
+
+/*!
+ * This function is called during the driver binding process.
+ *
+ * @param pdev the device structure used to store device specific
+ * information that is used by the suspend, resume and
+ * remove functions
+ *
+ * @return The function always returns 0.
+ */
+int board_nand_init(struct nand_chip *nand)
+{
+ struct gpmi_nfc_info *gpmi_info;
+ struct nand_chip *chip = nand;
+ struct nfc_hal *nfc;
+ static struct nand_ecclayout fake_ecc_layout;
+ int err;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s =>\n", __func__);
+
+ gpmi_info = kmalloc(sizeof(struct gpmi_nfc_info), GFP_KERNEL);
+ if (!gpmi_info) {
+ printf("%s: failed to allocate nand_info\n",
+ __func__);
+ err = -ENOMEM;
+ return err;
+ }
+ memset(gpmi_info, 0, sizeof(struct gpmi_nfc_info));
+
+ if (gpmi_nfc_alloc_buf(gpmi_info)) {
+ err = -ENOMEM;
+ return err;
+ }
+
+ /* Initialize the NFC HAL. */
+ gpmi_info->nfc = &gpmi_nfc_hal;
+ nfc = gpmi_info->nfc;
+ err = nfc->init();
+
+ memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout));
+
+ chip->priv = gpmi_info;
+
+ chip->cmd_ctrl = gpmi_nfc_cmd_ctrl;
+ /*
+ * Chip Control
+ *
+ * We rely on the reference implementations of:
+ * - cmdfunc
+ * - waitfunc
+ */
+ chip->cmdfunc = NULL;
+ chip->waitfunc = NULL;
+ chip->dev_ready = gpmi_nfc_dev_ready;
+ chip->select_chip = gpmi_nfc_select_chip;
+ chip->block_bad = gpmi_nfc_block_bad;
+ chip->block_markbad = NULL;
+ chip->read_byte = gpmi_nfc_read_byte;
+ /*
+ * Low-level I/O
+ *
+ * We don't support a 16-bit NAND Flash bus, so we don't implement
+ * read_word.
+ *
+ * We rely on the reference implentation of verify_buf.
+ */
+ chip->read_word = NULL;
+ chip->write_buf = gpmi_nfc_write_buf;
+ chip->read_buf = gpmi_nfc_read_buf;
+ chip->verify_buf = NULL;
+ /*
+ * High-level I/O
+ *
+ * We rely on the reference implementations of:
+ * - write_page
+ * - erase_cmd
+ */
+ chip->erase_cmd = NULL;
+ chip->write_page = NULL;
+ chip->scan_bbt = gpmi_nfc_scan_bbt;
+ /*
+ * Error Recovery Functions
+ *
+ * We don't fill in the errstat function pointer because it's optional
+ * and we don't have a need for it.
+ */
+ chip->errstat = NULL;
+ /*
+ * ECC-aware I/O
+ *
+ * We rely on the reference implementations of:
+ * - ecc.read_page_raw
+ * - ecc.write_page_raw
+ */
+ chip->ecc.read_page_raw = NULL;
+ chip->ecc.write_page_raw = NULL;
+ chip->ecc.read_page = gpmi_nfc_ecc_read_page;
+ /*
+ * Set up NAND Flash options. Specifically:
+ *
+ * - Disallow partial page writes.
+ */
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
+ chip->ecc.read_subpage = NULL;
+ chip->ecc.write_page = gpmi_nfc_ecc_write_page;
+ chip->ecc.read_oob = gpmi_nfc_ecc_read_oob;
+ chip->ecc.write_oob = gpmi_nfc_ecc_write_oob;
+ /*
+ * ECC Control
+ *
+ * None of these functions are necessary for us:
+ * - ecc.hwctl
+ * - ecc.calculate
+ * - ecc.correct
+ */
+ chip->ecc.calculate = NULL;
+ chip->ecc.correct = NULL;
+ chip->ecc.hwctl = NULL;
+ chip->ecc.layout = &fake_ecc_layout;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.bytes = 9;
+ chip->ecc.size = 512;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "<= %s\n", __func__);
+
+ return 0;
+}
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index acc5b7d..f840bcd 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -18,39 +18,13 @@
*/
#include <common.h>
-#ifdef CONFIG_MX31
-#include <asm/arch/mx31.h>
-#else
-#include <asm/arch/imx-regs.h>
-#include <asm/arch/clock.h>
-#endif
#define __REG(x) (*((volatile u32 *)(x)))
-#ifdef CONFIG_SYS_MX31_UART1
-#define UART_PHYS 0x43f90000
-#elif defined(CONFIG_SYS_MX31_UART2)
-#define UART_PHYS 0x43f94000
-#elif defined(CONFIG_SYS_MX31_UART3)
-#define UART_PHYS 0x5000c000
-#elif defined(CONFIG_SYS_MX31_UART4)
-#define UART_PHYS 0x43fb0000
-#elif defined(CONFIG_SYS_MX31_UART5)
-#define UART_PHYS 0x43fb4000
-#elif defined(CONFIG_SYS_MX27_UART1)
-#define UART_PHYS 0x1000a000
-#elif defined(CONFIG_SYS_MX27_UART2)
-#define UART_PHYS 0x1000b000
-#elif defined(CONFIG_SYS_MX27_UART3)
-#define UART_PHYS 0x1000c000
-#elif defined(CONFIG_SYS_MX27_UART4)
-#define UART_PHYS 0x1000d000
-#elif defined(CONFIG_SYS_MX27_UART5)
-#define UART_PHYS 0x1001b000
-#elif defined(CONFIG_SYS_MX27_UART6)
-#define UART_PHYS 0x1001c000
-#else
-#error "define CONFIG_SYS_MX31_UARTx to use the mx31 UART driver"
+#define UART_PHYS CONFIG_UART_BASE_ADDR
+
+#ifdef CONFIG_SERIAL_MULTI
+#warning "MXC driver does not support MULTI serials."
#endif
/* Register definitions */
@@ -166,11 +140,7 @@ DECLARE_GLOBAL_DATA_PTR;
void serial_setbrg (void)
{
-#ifdef CONFIG_MX31
- u32 clk = mx31_get_ipg_clk();
-#else
- u32 clk = imx_get_perclk1();
-#endif
+ u32 clk = mxc_get_clock(MXC_UART_CLK);
if (!gd->baudrate)
gd->baudrate = CONFIG_BAUDRATE;