diff options
author | Terry Lv <r65388@freescale.com> | 2010-09-05 18:27:46 +0800 |
---|---|---|
committer | Terry Lv <r65388@freescale.com> | 2010-09-19 23:25:21 +0800 |
commit | 6537dffd192344d8c786a037bce9f41db5448fc9 (patch) | |
tree | 0500e0c88f7b0c9c6675d14fad3563267b419936 /drivers | |
parent | 1e981afa607f3e04691fa8f05dc7c37070702845 (diff) | |
download | u-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/Makefile | 1 | ||||
-rw-r--r-- | drivers/dma/apbh_dma.c | 825 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi_nfc_bch.h | 664 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi_nfc_gpmi.h | 1118 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi_nfc_hal.c | 1621 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi_nfc_mil.c | 1187 | ||||
-rw-r--r-- | drivers/serial/serial_mxc.c | 40 |
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; |