summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Lv <r65388@freescale.com>2010-09-05 18:27:46 +0800
committerTerry Lv <r65388@freescale.com>2010-09-19 23:25:21 +0800
commit6537dffd192344d8c786a037bce9f41db5448fc9 (patch)
tree0500e0c88f7b0c9c6675d14fad3563267b419936
parent1e981afa607f3e04691fa8f05dc7c37070702845 (diff)
downloadu-boot-imx-6537dffd192344d8c786a037bce9f41db5448fc9.zip
u-boot-imx-6537dffd192344d8c786a037bce9f41db5448fc9.tar.gz
u-boot-imx-6537dffd192344d8c786a037bce9f41db5448fc9.tar.bz2
ENGR00127167: Add gpmi nfc and apbh dma support for mx50.
Add gpmi nfc and apbh dma support for mx50. Signed-off-by: Terry Lv <r65388@freescale.com>
-rw-r--r--board/freescale/mx50_arm2/mx50_arm2.c206
-rw-r--r--cpu/arm_cortexa8/mx50/Makefile3
-rw-r--r--cpu/arm_cortexa8/mx50/crm_regs.h2
-rw-r--r--cpu/arm_cortexa8/mx50/generic.c92
-rw-r--r--cpu/arm_cortexa8/mx50/mmu.c61
-rw-r--r--cpu/arm_cortexa8/mx50/serial.c226
-rw-r--r--cpu/arm_cortexa8/mx50/timer.c5
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/apbh_dma.c825
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/gpmi_nfc_bch.h664
-rw-r--r--drivers/mtd/nand/gpmi_nfc_gpmi.h1118
-rw-r--r--drivers/mtd/nand/gpmi_nfc_hal.c1621
-rw-r--r--drivers/mtd/nand/gpmi_nfc_mil.c1187
-rw-r--r--drivers/serial/serial_mxc.c40
-rw-r--r--include/asm-arm/apbh_dma.h987
-rw-r--r--include/asm-arm/arch-mx50/mmu.h37
-rw-r--r--include/asm-arm/arch-mx50/mx50.h5
-rw-r--r--include/asm-arm/arch-mx50/mx50_pins.h1
-rw-r--r--include/configs/mx50_arm2.h46
-rw-r--r--include/configs/mx50_arm2_lpddr2.h17
21 files changed, 6836 insertions, 309 deletions
diff --git a/board/freescale/mx50_arm2/mx50_arm2.c b/board/freescale/mx50_arm2/mx50_arm2.c
index 0494ea7..89b8b11 100644
--- a/board/freescale/mx50_arm2/mx50_arm2.c
+++ b/board/freescale/mx50_arm2/mx50_arm2.c
@@ -351,6 +351,204 @@ void spi_io_init(struct imx_spi_dev_t *dev)
}
#endif
+#ifdef CONFIG_NAND_GPMI
+void setup_gpmi_nand()
+{
+ u32 src_sbmr = readl(SRC_BASE_ADDR + 0x4);
+
+ /* Fix for gpmi gatelevel issue */
+ mxc_iomux_set_pad(MX50_PIN_SD3_CLK, 0x00e4);
+
+ /* RESETN,WRN,RDN,DATA0~7 Signals iomux*/
+ /* Check if 1.8v NAND is to be supported */
+ if ((src_sbmr & 0x00000004) >> 2)
+ *(u32 *)(IOMUXC_BASE_ADDR + PAD_GRP_START + 0x58) = (0x1 << 13);
+
+ /* RESETN */
+ mxc_request_iomux(MX50_PIN_SD3_WP, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_WP, PAD_CTL_DRV_HIGH);
+
+ /* WRN */
+ mxc_request_iomux(MX50_PIN_SD3_CMD, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_CMD, PAD_CTL_DRV_HIGH);
+
+ /* RDN */
+ mxc_request_iomux(MX50_PIN_SD3_CLK, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_CLK, PAD_CTL_DRV_HIGH);
+
+ /* D0 */
+ mxc_request_iomux(MX50_PIN_SD3_D4, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D4, PAD_CTL_DRV_HIGH);
+
+ /* D1 */
+ mxc_request_iomux(MX50_PIN_SD3_D5, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D5, PAD_CTL_DRV_HIGH);
+
+ /* D2 */
+ mxc_request_iomux(MX50_PIN_SD3_D6, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D6, PAD_CTL_DRV_HIGH);
+
+ /* D3 */
+ mxc_request_iomux(MX50_PIN_SD3_D7, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D7, PAD_CTL_DRV_HIGH);
+
+ /* D4 */
+ mxc_request_iomux(MX50_PIN_SD3_D0, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D0, PAD_CTL_DRV_HIGH);
+
+ /* D5 */
+ mxc_request_iomux(MX50_PIN_SD3_D1, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D1, PAD_CTL_DRV_HIGH);
+
+ /* D6 */
+ mxc_request_iomux(MX50_PIN_SD3_D2, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D2, PAD_CTL_DRV_HIGH);
+
+ /* D7 */
+ mxc_request_iomux(MX50_PIN_SD3_D3, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_SD3_D3, PAD_CTL_DRV_HIGH);
+
+ /*CE0~3,and other four controls signals muxed on KPP*/
+ switch ((src_sbmr & 0x00000018) >> 3) {
+ case 0:
+ /* Muxed on key */
+ if ((src_sbmr & 0x00000004) >> 2)
+ *(u32 *)(IOMUXC_BASE_ADDR + PAD_GRP_START + 0x20) =
+ (0x1 << 13);
+
+ /* CLE */
+ mxc_request_iomux(MX50_PIN_KEY_COL0, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_COL0, PAD_CTL_DRV_HIGH);
+
+ /* ALE */
+ mxc_request_iomux(MX50_PIN_KEY_ROW0, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_ROW0, PAD_CTL_DRV_HIGH);
+
+ /* READY0 */
+ mxc_request_iomux(MX50_PIN_KEY_COL3, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_COL3,
+ PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL |
+ PAD_CTL_100K_PU);
+ mxc_iomux_set_input(MUX_IN_RAWNAND_U_GPMI_INPUT_GPMI_RDY0_IN_SELECT_INPUT,
+ INPUT_CTL_PATH0);
+
+ /* DQS */
+ mxc_request_iomux(MX50_PIN_KEY_ROW3, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_ROW3, PAD_CTL_DRV_HIGH);
+ mxc_iomux_set_input(MUX_IN_RAWNAND_U_GPMI_INPUT_GPMI_DQS_IN_SELECT_INPUT,
+ INPUT_CTL_PATH0);
+
+ /* CE0 */
+ mxc_request_iomux(MX50_PIN_KEY_COL1, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_COL1, PAD_CTL_DRV_HIGH);
+
+ /* CE1 */
+ mxc_request_iomux(MX50_PIN_KEY_ROW1, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_ROW1, PAD_CTL_DRV_HIGH);
+
+ /* CE2 */
+ mxc_request_iomux(MX50_PIN_KEY_COL2, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_COL2, PAD_CTL_DRV_HIGH);
+
+ /* CE3 */
+ mxc_request_iomux(MX50_PIN_KEY_ROW2, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_KEY_ROW2, PAD_CTL_DRV_HIGH);
+
+ break;
+ case 1:
+ if ((src_sbmr & 0x00000004) >> 2)
+ *(u32 *)(IOMUXC_BASE_ADDR + PAD_GRP_START + 0xc) =
+ (0x1 << 13);
+
+ /* CLE */
+ mxc_request_iomux(MX50_PIN_EIM_DA8, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA8, PAD_CTL_DRV_HIGH);
+
+ /* ALE */
+ mxc_request_iomux(MX50_PIN_EIM_DA9, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA9, PAD_CTL_DRV_HIGH);
+
+ /* READY0 */
+ mxc_request_iomux(MX50_PIN_EIM_DA14, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA14,
+ PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL |
+ PAD_CTL_100K_PU);
+ mxc_iomux_set_input(MUX_IN_RAWNAND_U_GPMI_INPUT_GPMI_RDY0_IN_SELECT_INPUT,
+ INPUT_CTL_PATH2);
+
+ /* DQS */
+ mxc_request_iomux(MX50_PIN_EIM_DA15, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA15, PAD_CTL_DRV_HIGH);
+ mxc_iomux_set_input(MUX_IN_RAWNAND_U_GPMI_INPUT_GPMI_DQS_IN_SELECT_INPUT,
+ INPUT_CTL_PATH2);
+
+ /* CE0 */
+ mxc_request_iomux(MX50_PIN_EIM_DA10, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA10, PAD_CTL_DRV_HIGH);
+
+ /* CE1 */
+ mxc_request_iomux(MX50_PIN_EIM_DA11, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA11, PAD_CTL_DRV_HIGH);
+
+ /* CE2 */
+ mxc_request_iomux(MX50_PIN_EIM_DA12, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA12, PAD_CTL_DRV_HIGH);
+
+ /* CE3 */
+ mxc_request_iomux(MX50_PIN_EIM_DA13, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA13, PAD_CTL_DRV_HIGH);
+
+ break;
+ case 2:
+ if ((src_sbmr & 0x00000004) >> 2)
+ *(u32 *)(IOMUXC_BASE_ADDR + PAD_GRP_START + 0x48) =
+ (0x1 << 13);
+
+ /* CLE */
+ mxc_request_iomux(MX50_PIN_DISP_D8, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D8, PAD_CTL_DRV_HIGH);
+
+ /* ALE */
+ mxc_request_iomux(MX50_PIN_DISP_D9, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D9, PAD_CTL_DRV_HIGH);
+
+ /* READY0 */
+ mxc_request_iomux(MX50_PIN_DISP_D14, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D14,
+ PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL |
+ PAD_CTL_100K_PU);
+ mxc_iomux_set_input(MUX_IN_RAWNAND_U_GPMI_INPUT_GPMI_RDY0_IN_SELECT_INPUT,
+ INPUT_CTL_PATH1);
+
+ /* DQS */
+ mxc_request_iomux(MX50_PIN_DISP_D15, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D15, PAD_CTL_DRV_HIGH);
+ mxc_iomux_set_input(MUX_IN_RAWNAND_U_GPMI_INPUT_GPMI_DQS_IN_SELECT_INPUT,
+ INPUT_CTL_PATH1);
+
+ /* CE0 */
+ mxc_request_iomux(MX50_PIN_DISP_D10, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D10, PAD_CTL_DRV_HIGH);
+
+ /* CE1 */
+ mxc_request_iomux(MX50_PIN_EIM_DA11, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_EIM_DA11, PAD_CTL_DRV_HIGH);
+
+ /* CE2 */
+ mxc_request_iomux(MX50_PIN_DISP_D12, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D12, PAD_CTL_DRV_HIGH);
+
+ /* CE3 */
+ mxc_request_iomux(MX50_PIN_DISP_D13, IOMUX_CONFIG_ALT2);
+ mxc_iomux_set_pad(MX50_PIN_DISP_D13, PAD_CTL_DRV_HIGH);
+
+ break;
+ default:
+ break;
+ }
+}
+#endif
+
#ifdef CONFIG_MXC_FEC
#ifdef CONFIG_GET_FEC_MAC_ADDR_FROM_IIM
@@ -521,6 +719,7 @@ int esdhc_gpio_init(bd_t *bis)
break;
case 2:
+#ifndef CONFIG_NAND_GPMI
mxc_request_iomux(MX50_PIN_SD3_CMD, IOMUX_CONFIG_ALT0);
mxc_request_iomux(MX50_PIN_SD3_CLK, IOMUX_CONFIG_ALT0);
mxc_request_iomux(MX50_PIN_SD3_D0, IOMUX_CONFIG_ALT0);
@@ -542,7 +741,7 @@ int esdhc_gpio_init(bd_t *bis)
mxc_iomux_set_pad(MX50_PIN_SD3_D5, 0x1D4);
mxc_iomux_set_pad(MX50_PIN_SD3_D6, 0x1D4);
mxc_iomux_set_pad(MX50_PIN_SD3_D7, 0x1D4);
-
+#endif
break;
default:
printf("Warning: you configured more ESDHC controller"
@@ -809,7 +1008,6 @@ static void setup_power(void)
{
struct spi_slave *slave;
unsigned int val;
- unsigned int reg;
puts("PMIC Mode: SPI\n");
@@ -874,6 +1072,10 @@ int board_init(void)
setup_fec();
#endif
+#ifdef CONFIG_NAND_GPMI
+ setup_gpmi_nand();
+#endif
+
#ifdef CONFIG_MXC_EPDC
setup_epdc();
#endif
diff --git a/cpu/arm_cortexa8/mx50/Makefile b/cpu/arm_cortexa8/mx50/Makefile
index 460bdd9..51f6124 100644
--- a/cpu/arm_cortexa8/mx50/Makefile
+++ b/cpu/arm_cortexa8/mx50/Makefile
@@ -27,7 +27,8 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
-COBJS = interrupts.o serial.o generic.o iomux.o timer.o cache.o
+COBJS = interrupts.o generic.o iomux.o timer.o cache.o
+COBJS-$(CONFIG_ARCH_MMU) += mmu.o
COBJS += $(COBJS-y)
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/cpu/arm_cortexa8/mx50/crm_regs.h b/cpu/arm_cortexa8/mx50/crm_regs.h
index e8915c8..1af5f9e 100644
--- a/cpu/arm_cortexa8/mx50/crm_regs.h
+++ b/cpu/arm_cortexa8/mx50/crm_regs.h
@@ -119,6 +119,8 @@
#define MXC_CCM_CLKSEQ_BYPASS (MXC_CCM_BASE + 0x90)
#define MXC_CCM_CLK_SYS (MXC_CCM_BASE + 0x94)
#define MXC_CCM_CLK_DDR (MXC_CCM_BASE + 0x98)
+#define MXC_CCM_GPMI (MXC_CCM_BASE + 0xac)
+#define MXC_CCM_BCH (MXC_CCM_BASE + 0xb0)
/* Define the bits in register CCR */
#define MXC_CCM_CCR_COSC_EN (1 << 12)
diff --git a/cpu/arm_cortexa8/mx50/generic.c b/cpu/arm_cortexa8/mx50/generic.c
index 66ffaf9..bf24318 100644
--- a/cpu/arm_cortexa8/mx50/generic.c
+++ b/cpu/arm_cortexa8/mx50/generic.c
@@ -464,6 +464,88 @@ static u32 __get_esdhc4_clk(void)
}
#endif
+#ifdef CONFIG_CMD_NAND
+static inline void __enable_gpmi_clk(void)
+{
+ u32 reg1 = __REG(MXC_CCM_GPMI);
+
+ reg1 |= 0x80000000;
+
+ writel(reg1, MXC_CCM_GPMI);
+}
+
+static inline void __enable_bch_clk(void)
+{
+ u32 reg1 = __REG(MXC_CCM_BCH);
+
+ reg1 |= 0x80000000;
+
+ writel(reg1, MXC_CCM_BCH);
+}
+
+
+static u32 __get_gpmi_clk(void)
+{
+ u32 ret_val = 0;
+ u32 clkseq_bypass = __REG(MXC_CCM_CLKSEQ_BYPASS);
+ u32 clk_sel = (clkseq_bypass & MXC_CCM_CLKSEQ_BYPASS_GPMI_MASK)
+ >> MXC_CCM_CLKSEQ_BYPASS_GPMI_OFFSET;
+ u32 div = __REG(MXC_CCM_GPMI) & 0x3f;
+
+ __enable_gpmi_clk();
+
+ switch (clk_sel) {
+ case 0:
+ /* 24MHz xtal */
+ ret_val = CONFIG_MX50_HCLK_FREQ;
+ break;
+ case 1:
+ /* PFD4 */
+ puts("Warning, Fixme,not handle PFD mux\n");
+ break;
+ case 2:
+ /* PLL1 */
+ ret_val = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
+ break;
+ default:
+ break;
+ }
+
+ return (div > 0) ? (ret_val / div) : 0;
+}
+
+static u32 __get_bch_clk(void)
+{
+ u32 ret_val = 0;
+ u32 clkseq_bypass = __REG(MXC_CCM_CLKSEQ_BYPASS);
+ u32 clk_sel = (clkseq_bypass & MXC_CCM_CLKSEQ_BYPASS_BCH_MASK)
+ >> MXC_CCM_CLKSEQ_BYPASS_BCH_OFFSET;
+ u32 div = __REG(MXC_CCM_BCH) & 0x3f;
+
+ __enable_bch_clk();
+
+ switch (clk_sel) {
+ case 0:
+ /* 24MHz xtal */
+ ret_val = CONFIG_MX50_HCLK_FREQ;
+ break;
+ case 1:
+ /* PFD4 */
+ puts("Warning, Fixme,not handle PFD mux\n");
+ break;
+ case 2:
+ /* PLL1 */
+ ret_val = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
+ break;
+ default:
+ break;
+ }
+
+ return (div > 0) ? (ret_val / div) : 0;
+}
+
+#endif
+
unsigned int mxc_get_clock(enum mxc_clock clk)
{
switch (clk) {
@@ -501,6 +583,12 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
case MXC_ESDHC4_CLK:
return __get_esdhc4_clk();
#endif
+#ifdef CONFIG_CMD_NAND
+ case MXC_GPMI_CLK:
+ return __get_gpmi_clk();
+ case MXC_BCH_CLK:
+ return __get_bch_clk();
+#endif
default:
break;
}
@@ -533,6 +621,10 @@ void mxc_dump_clocks(void)
printf("esdhc3 clock : %dHz\n", mxc_get_clock(MXC_ESDHC3_CLK));
printf("esdhc4 clock : %dHz\n", mxc_get_clock(MXC_ESDHC4_CLK));
#endif
+#ifdef CONFIG_CMD_NAND
+ printf("GPMI clock : %dHz\n", mxc_get_clock(MXC_GPMI_CLK));
+ printf("BCH clock : %dHz\n", mxc_get_clock(MXC_BCH_CLK));
+#endif
}
#ifdef CONFIG_CMD_CLOCK
diff --git a/cpu/arm_cortexa8/mx50/mmu.c b/cpu/arm_cortexa8/mx50/mmu.c
new file mode 100644
index 0000000..8d5cd73
--- /dev/null
+++ b/cpu/arm_cortexa8/mx50/mmu.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <common.h>
+
+/*
+ * Translate the virtual address of ram space to physical address
+ * It is dependent on the implementation of mmu_init
+ */
+inline void *iomem_to_phys(unsigned long virt)
+{
+ if (virt >= 0xB0000000)
+ return (void *)((virt - 0xB0000000) + PHYS_SDRAM_1);
+
+ return (void *)virt;
+}
+
+/*
+ * remap the physical address of ram space to uncacheable virtual address space
+ * It is dependent on the implementation of hal_mmu_init
+ */
+void *__ioremap(unsigned long offset, size_t size, unsigned long flags)
+{
+ if (1 == flags) {
+ if (offset >= PHYS_SDRAM_1 &&
+ offset < (PHYS_SDRAM_1 + PHYS_SDRAM_1_SIZE))
+ return (void *)(offset - PHYS_SDRAM_1) + 0xB0000000;
+ else
+ return NULL;
+ } else
+ return (void *)offset;
+}
+
+/*
+ * Remap the physical address of ram space to uncacheable virtual address space
+ * It is dependent on the implementation of hal_mmu_init
+ */
+void __iounmap(void *addr)
+{
+ return;
+}
+
diff --git a/cpu/arm_cortexa8/mx50/serial.c b/cpu/arm_cortexa8/mx50/serial.c
deleted file mode 100644
index a0cef25..0000000
--- a/cpu/arm_cortexa8/mx50/serial.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * Copyright (C) 2010 Freescale Semiconductor, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <common.h>
-
-#if defined CONFIG_MX50_UART
-
-#include <asm/arch/mx50.h>
-
-#ifdef CONFIG_MX50_UART1
-#define UART_PHYS UART1_BASE_ADDR
-#elif defined(CONFIG_MX50_UART2)
-#define UART_PHYS UART2_BASE_ADDR
-#elif defined(CONFIG_MX50_UART3)
-#define UART_PHYS UART3_BASE_ADDR
-#else
-#error "define CFG_MX50_UARTx to use the mx50 UART driver"
-#endif
-
-/* Register definitions */
-#define URXD 0x0 /* Receiver Register */
-#define UTXD 0x40 /* Transmitter Register */
-#define UCR1 0x80 /* Control Register 1 */
-#define UCR2 0x84 /* Control Register 2 */
-#define UCR3 0x88 /* Control Register 3 */
-#define UCR4 0x8c /* Control Register 4 */
-#define UFCR 0x90 /* FIFO Control Register */
-#define USR1 0x94 /* Status Register 1 */
-#define USR2 0x98 /* Status Register 2 */
-#define UESC 0x9c /* Escape Character Register */
-#define UTIM 0xa0 /* Escape Timer Register */
-#define UBIR 0xa4 /* BRM Incremental Register */
-#define UBMR 0xa8 /* BRM Modulator Register */
-#define UBRC 0xac /* Baud Rate Count Register */
-#define UTS 0xb4 /* UART Test Register (mx31) */
-
-/* UART Control Register Bit Fields.*/
-#define URXD_CHARRDY (1<<15)
-#define URXD_ERR (1<<14)
-#define URXD_OVRRUN (1<<13)
-#define URXD_FRMERR (1<<12)
-#define URXD_BRK (1<<11)
-#define URXD_PRERR (1<<10)
-#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
-#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
-#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
-#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
-#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
-#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
-#define UCR1_IREN (1<<7) /* Infrared interface enable */
-#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
-#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
-#define UCR1_SNDBRK (1<<4) /* Send break */
-#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
-#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
-#define UCR1_DOZE (1<<1) /* Doze */
-#define UCR1_UARTEN (1<<0) /* UART enabled */
-#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
-#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
-#define UCR2_CTSC (1<<13) /* CTS pin control */
-#define UCR2_CTS (1<<12) /* Clear to send */
-#define UCR2_ESCEN (1<<11) /* Escape enable */
-#define UCR2_PREN (1<<8) /* Parity enable */
-#define UCR2_PROE (1<<7) /* Parity odd/even */
-#define UCR2_STPB (1<<6) /* Stop */
-#define UCR2_WS (1<<5) /* Word size */
-#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
-#define UCR2_TXEN (1<<2) /* Transmitter enabled */
-#define UCR2_RXEN (1<<1) /* Receiver enabled */
-#define UCR2_SRST (1<<0) /* SW reset */
-#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
-#define UCR3_PARERREN (1<<12) /* Parity enable */
-#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
-#define UCR3_DSR (1<<10) /* Data set ready */
-#define UCR3_DCD (1<<9) /* Data carrier detect */
-#define UCR3_RI (1<<8) /* Ring indicator */
-#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
-#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
-#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
-#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
-#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */
-#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */
-#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
-#define UCR3_BPEN (1<<0) /* Preset registers enable */
-#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
-#define UCR4_INVR (1<<9) /* Inverted infrared reception */
-#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
-#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
-#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
-#define UCR4_IRSC (1<<5) /* IR special case */
-#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
-#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
-#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
-#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
-#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
-#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
-#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
-#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
-#define USR1_RTSS (1<<14) /* RTS pin status */
-#define USR1_TRDY (1<<13)/* Transmitter ready interrupt/dma flag */
-#define USR1_RTSD (1<<12) /* RTS delta */
-#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
-#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
-#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
-#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
-#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
-#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
-#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
-#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
-#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
-#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
-#define USR2_IDLE (1<<12) /* Idle condition */
-#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
-#define USR2_WAKE (1<<7) /* Wake */
-#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
-#define USR2_TXDC (1<<3) /* Transmitter complete */
-#define USR2_BRCD (1<<2) /* Break condition */
-#define USR2_ORE (1<<1) /* Overrun error */
-#define USR2_RDR (1<<0) /* Recv data ready */
-#define UTS_FRCPERR (1<<13) /* Force parity error */
-#define UTS_LOOP (1<<12) /* Loop tx and rx */
-#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
-#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
-#define UTS_TXFULL (1<<4) /* TxFIFO full */
-#define UTS_RXFULL (1<<3) /* RxFIFO full */
-#define UTS_SOFTRST (1<<0) /* Software reset */
-
-DECLARE_GLOBAL_DATA_PTR;
-
-void serial_setbrg(void)
-{
- u32 clk = mxc_get_clock(MXC_UART_CLK);
-
- if (!gd->baudrate)
- gd->baudrate = CONFIG_BAUDRATE;
- __REG(UART_PHYS + UFCR) = 0x4 << 7; /* divide input clock by 2 */
- __REG(UART_PHYS + UBIR) = 0xf;
- __REG(UART_PHYS + UBMR) = clk / (2 * gd->baudrate);
-}
-
-int serial_getc(void)
-{
- while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY)
- ;
- return __REG(UART_PHYS + URXD);
-}
-
-void serial_putc(const char c)
-{
- __REG(UART_PHYS + UTXD) = c;
-
- /* wait for transmitter to be ready */
- while (!(__REG(UART_PHYS + UTS) & UTS_TXEMPTY))
- ;
-
- /* If \n, also do \r */
- if (c == '\n')
- serial_putc('\r');
-}
-
-/*
- * Test whether a character is in the RX buffer
- */
-int serial_tstc(void)
-{
- /* If receive fifo is empty, return false */
- if (__REG(UART_PHYS + UTS) & UTS_RXEMPTY)
- return 0;
- return 1;
-}
-
-void serial_puts(const char *s)
-{
- while (*s)
- serial_putc(*s++);
-}
-
-/*
- * Initialise the serial port with the given baudrate. The settings
- * are always 8 data bits, no parity, 1 stop bit, no start bits.
- *
- */
-int serial_init(void)
-{
- __REG(UART_PHYS + UCR1) = 0x0;
- __REG(UART_PHYS + UCR2) = 0x0;
-
- while (!(__REG(UART_PHYS + UCR2) & UCR2_SRST))
- ;
-
- __REG(UART_PHYS + UCR3) = 0x0704;
- __REG(UART_PHYS + UCR4) = 0x8000;
- __REG(UART_PHYS + UESC) = 0x002b;
- __REG(UART_PHYS + UTIM) = 0x0;
-
- __REG(UART_PHYS + UTS) = 0x0;
-
- serial_setbrg();
-
- __REG(UART_PHYS + UCR2) =
- UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST;
-
- __REG(UART_PHYS + UCR1) = UCR1_UARTEN;
-
- return 0;
-}
-
-#endif /* CONFIG_MX50_UART */
diff --git a/cpu/arm_cortexa8/mx50/timer.c b/cpu/arm_cortexa8/mx50/timer.c
index 00150ab..33ab82a 100644
--- a/cpu/arm_cortexa8/mx50/timer.c
+++ b/cpu/arm_cortexa8/mx50/timer.c
@@ -37,6 +37,7 @@
#define GPTCR_FRR (1<<9) /* Freerun / restart */
#define GPTCR_CLKSOURCE_32 (0x100<<6) /* Clock source */
#define GPTCR_CLKSOURCE_IPG (0x001<<6) /* Clock source */
+#define GPTCR_ENMOD_RESET (2)
#define GPTCR_TEN (1) /* Timer enable */
#define GPTPR_VAL (50)
@@ -56,6 +57,7 @@ static inline void setup_gpt(void)
GPTCR = 0; /* We have no udelay by now */
GPTPR = GPTPR_VAL; /* 50Mhz / 50 */
/* Freerun Mode, PERCLK1 input */
+ GPTCR |= GPTCR_ENMOD_RESET;
GPTCR |= GPTCR_CLKSOURCE_IPG | GPTCR_TEN;
}
@@ -69,8 +71,9 @@ int timer_init(void)
void reset_timer_masked(void)
{
GPTCR = 0;
+ GPTCR |= GPTCR_ENMOD_RESET;
/* Freerun Mode, PERCLK1 input */
- GPTCR = GPTCR_CLKSOURCE_IPG | GPTCR_TEN;
+ GPTCR |= GPTCR_CLKSOURCE_IPG | GPTCR_TEN;
}
inline ulong get_timer_masked(void)
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;
diff --git a/include/asm-arm/apbh_dma.h b/include/asm-arm/apbh_dma.h
new file mode 100644
index 0000000..5bb1f40
--- /dev/null
+++ b/include/asm-arm/apbh_dma.h
@@ -0,0 +1,987 @@
+/*
+ * Freescale APBH 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 __APBH_DMA_H__
+#define __APBH_DMA_H__
+
+#include <asm/types.h>
+#include <linux/list.h>
+#include <linux/stddef.h>
+
+#define HW_APBH_CTRL0 (0x00000000)
+#define HW_APBH_CTRL0_SET (0x00000004)
+#define HW_APBH_CTRL0_CLR (0x00000008)
+#define HW_APBH_CTRL0_TOG (0x0000000c)
+
+#define BM_APBH_CTRL0_SFTRST 0x80000000
+#define BM_APBH_CTRL0_CLKGATE 0x40000000
+#define BM_APBH_CTRL0_AHB_BURST8_EN 0x20000000
+#define BM_APBH_CTRL0_APB_BURST_EN 0x10000000
+#define BP_APBH_CTRL0_RSVD0 16
+#define BM_APBH_CTRL0_RSVD0 0x0FFF0000
+#define BF_APBH_CTRL0_RSVD0(v) \
+ (((v) << 16) & BM_APBH_CTRL0_RSVD0)
+#define BP_APBH_CTRL0_CLKGATE_CHANNEL 0
+#define BM_APBH_CTRL0_CLKGATE_CHANNEL 0x0000FFFF
+#define BF_APBH_CTRL0_CLKGATE_CHANNEL(v) \
+ (((v) << 0) & BM_APBH_CTRL0_CLKGATE_CHANNEL)
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND0 0x0001
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND1 0x0002
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND2 0x0004
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND3 0x0008
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND4 0x0010
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND5 0x0020
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND6 0x0040
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND7 0x0080
+#define BV_APBH_CTRL0_CLKGATE_CHANNEL__SSP 0x0100
+
+#define HW_APBH_CTRL1 (0x00000010)
+#define HW_APBH_CTRL1_SET (0x00000014)
+#define HW_APBH_CTRL1_CLR (0x00000018)
+#define HW_APBH_CTRL1_TOG (0x0000001c)
+
+#define BM_APBH_CTRL1_CH15_CMDCMPLT_IRQ_EN 0x80000000
+#define BM_APBH_CTRL1_CH14_CMDCMPLT_IRQ_EN 0x40000000
+#define BM_APBH_CTRL1_CH13_CMDCMPLT_IRQ_EN 0x20000000
+#define BM_APBH_CTRL1_CH12_CMDCMPLT_IRQ_EN 0x10000000
+#define BM_APBH_CTRL1_CH11_CMDCMPLT_IRQ_EN 0x08000000
+#define BM_APBH_CTRL1_CH10_CMDCMPLT_IRQ_EN 0x04000000
+#define BM_APBH_CTRL1_CH9_CMDCMPLT_IRQ_EN 0x02000000
+#define BM_APBH_CTRL1_CH8_CMDCMPLT_IRQ_EN 0x01000000
+#define BM_APBH_CTRL1_CH7_CMDCMPLT_IRQ_EN 0x00800000
+#define BM_APBH_CTRL1_CH6_CMDCMPLT_IRQ_EN 0x00400000
+#define BM_APBH_CTRL1_CH5_CMDCMPLT_IRQ_EN 0x00200000
+#define BM_APBH_CTRL1_CH4_CMDCMPLT_IRQ_EN 0x00100000
+#define BM_APBH_CTRL1_CH3_CMDCMPLT_IRQ_EN 0x00080000
+#define BM_APBH_CTRL1_CH2_CMDCMPLT_IRQ_EN 0x00040000
+#define BM_APBH_CTRL1_CH1_CMDCMPLT_IRQ_EN 0x00020000
+#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ_EN 0x00010000
+#define BM_APBH_CTRL1_CH15_CMDCMPLT_IRQ 0x00008000
+#define BM_APBH_CTRL1_CH14_CMDCMPLT_IRQ 0x00004000
+#define BM_APBH_CTRL1_CH13_CMDCMPLT_IRQ 0x00002000
+#define BM_APBH_CTRL1_CH12_CMDCMPLT_IRQ 0x00001000
+#define BM_APBH_CTRL1_CH11_CMDCMPLT_IRQ 0x00000800
+#define BM_APBH_CTRL1_CH10_CMDCMPLT_IRQ 0x00000400
+#define BM_APBH_CTRL1_CH9_CMDCMPLT_IRQ 0x00000200
+#define BM_APBH_CTRL1_CH8_CMDCMPLT_IRQ 0x00000100
+#define BM_APBH_CTRL1_CH7_CMDCMPLT_IRQ 0x00000080
+#define BM_APBH_CTRL1_CH6_CMDCMPLT_IRQ 0x00000040
+#define BM_APBH_CTRL1_CH5_CMDCMPLT_IRQ 0x00000020
+#define BM_APBH_CTRL1_CH4_CMDCMPLT_IRQ 0x00000010
+#define BM_APBH_CTRL1_CH3_CMDCMPLT_IRQ 0x00000008
+#define BM_APBH_CTRL1_CH2_CMDCMPLT_IRQ 0x00000004
+#define BM_APBH_CTRL1_CH1_CMDCMPLT_IRQ 0x00000002
+#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001
+
+#define HW_APBH_CTRL2 (0x00000020)
+#define HW_APBH_CTRL2_SET (0x00000024)
+#define HW_APBH_CTRL2_CLR (0x00000028)
+#define HW_APBH_CTRL2_TOG (0x0000002c)
+
+#define BM_APBH_CTRL2_CH15_ERROR_STATUS 0x80000000
+#define BV_APBH_CTRL2_CH15_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH15_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH14_ERROR_STATUS 0x40000000
+#define BV_APBH_CTRL2_CH14_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH14_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH13_ERROR_STATUS 0x20000000
+#define BV_APBH_CTRL2_CH13_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH13_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH12_ERROR_STATUS 0x10000000
+#define BV_APBH_CTRL2_CH12_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH12_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH11_ERROR_STATUS 0x08000000
+#define BV_APBH_CTRL2_CH11_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH11_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH10_ERROR_STATUS 0x04000000
+#define BV_APBH_CTRL2_CH10_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH10_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH9_ERROR_STATUS 0x02000000
+#define BV_APBH_CTRL2_CH9_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH9_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH8_ERROR_STATUS 0x01000000
+#define BV_APBH_CTRL2_CH8_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH8_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH7_ERROR_STATUS 0x00800000
+#define BV_APBH_CTRL2_CH7_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH7_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH6_ERROR_STATUS 0x00400000
+#define BV_APBH_CTRL2_CH6_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH6_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH5_ERROR_STATUS 0x00200000
+#define BV_APBH_CTRL2_CH5_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH5_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH4_ERROR_STATUS 0x00100000
+#define BV_APBH_CTRL2_CH4_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH4_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH3_ERROR_STATUS 0x00080000
+#define BV_APBH_CTRL2_CH3_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH3_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH2_ERROR_STATUS 0x00040000
+#define BV_APBH_CTRL2_CH2_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH2_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH1_ERROR_STATUS 0x00020000
+#define BV_APBH_CTRL2_CH1_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH1_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH0_ERROR_STATUS 0x00010000
+#define BV_APBH_CTRL2_CH0_ERROR_STATUS__TERMINATION 0x0
+#define BV_APBH_CTRL2_CH0_ERROR_STATUS__BUS_ERROR 0x1
+#define BM_APBH_CTRL2_CH15_ERROR_IRQ 0x00008000
+#define BM_APBH_CTRL2_CH14_ERROR_IRQ 0x00004000
+#define BM_APBH_CTRL2_CH13_ERROR_IRQ 0x00002000
+#define BM_APBH_CTRL2_CH12_ERROR_IRQ 0x00001000
+#define BM_APBH_CTRL2_CH11_ERROR_IRQ 0x00000800
+#define BM_APBH_CTRL2_CH10_ERROR_IRQ 0x00000400
+#define BM_APBH_CTRL2_CH9_ERROR_IRQ 0x00000200
+#define BM_APBH_CTRL2_CH8_ERROR_IRQ 0x00000100
+#define BM_APBH_CTRL2_CH7_ERROR_IRQ 0x00000080
+#define BM_APBH_CTRL2_CH6_ERROR_IRQ 0x00000040
+#define BM_APBH_CTRL2_CH5_ERROR_IRQ 0x00000020
+#define BM_APBH_CTRL2_CH4_ERROR_IRQ 0x00000010
+#define BM_APBH_CTRL2_CH3_ERROR_IRQ 0x00000008
+#define BM_APBH_CTRL2_CH2_ERROR_IRQ 0x00000004
+#define BM_APBH_CTRL2_CH1_ERROR_IRQ 0x00000002
+#define BM_APBH_CTRL2_CH0_ERROR_IRQ 0x00000001
+
+#define HW_APBH_CHANNEL_CTRL (0x00000030)
+#define HW_APBH_CHANNEL_CTRL_SET (0x00000034)
+#define HW_APBH_CHANNEL_CTRL_CLR (0x00000038)
+#define HW_APBH_CHANNEL_CTRL_TOG (0x0000003c)
+
+#define BP_APBH_CHANNEL_CTRL_RESET_CHANNEL 16
+#define BM_APBH_CHANNEL_CTRL_RESET_CHANNEL 0xFFFF0000
+#define BF_APBH_CHANNEL_CTRL_RESET_CHANNEL(v) \
+ (((v) << 16) & BM_APBH_CHANNEL_CTRL_RESET_CHANNEL)
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND0 0x0001
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND1 0x0002
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND2 0x0004
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND3 0x0008
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND4 0x0010
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND5 0x0020
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND6 0x0040
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND7 0x0080
+#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__SSP 0x0100
+#define BP_APBH_CHANNEL_CTRL_FREEZE_CHANNEL 0
+#define BM_APBH_CHANNEL_CTRL_FREEZE_CHANNEL 0x0000FFFF
+#define BF_APBH_CHANNEL_CTRL_FREEZE_CHANNEL(v) \
+ (((v) << 0) & BM_APBH_CHANNEL_CTRL_FREEZE_CHANNEL)
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND0 0x0001
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND1 0x0002
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND2 0x0004
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND3 0x0008
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND4 0x0010
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND5 0x0020
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND6 0x0040
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND7 0x0080
+#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__SSP 0x0100
+
+#define HW_APBH_DEVSEL (0x00000040)
+
+#define BP_APBH_DEVSEL_CH15 30
+#define BM_APBH_DEVSEL_CH15 0xC0000000
+#define BF_APBH_DEVSEL_CH15(v) \
+ (((v) << 30) & BM_APBH_DEVSEL_CH15)
+#define BP_APBH_DEVSEL_CH14 28
+#define BM_APBH_DEVSEL_CH14 0x30000000
+#define BF_APBH_DEVSEL_CH14(v) \
+ (((v) << 28) & BM_APBH_DEVSEL_CH14)
+#define BP_APBH_DEVSEL_CH13 26
+#define BM_APBH_DEVSEL_CH13 0x0C000000
+#define BF_APBH_DEVSEL_CH13(v) \
+ (((v) << 26) & BM_APBH_DEVSEL_CH13)
+#define BP_APBH_DEVSEL_CH12 24
+#define BM_APBH_DEVSEL_CH12 0x03000000
+#define BF_APBH_DEVSEL_CH12(v) \
+ (((v) << 24) & BM_APBH_DEVSEL_CH12)
+#define BP_APBH_DEVSEL_CH11 22
+#define BM_APBH_DEVSEL_CH11 0x00C00000
+#define BF_APBH_DEVSEL_CH11(v) \
+ (((v) << 22) & BM_APBH_DEVSEL_CH11)
+#define BP_APBH_DEVSEL_CH10 20
+#define BM_APBH_DEVSEL_CH10 0x00300000
+#define BF_APBH_DEVSEL_CH10(v) \
+ (((v) << 20) & BM_APBH_DEVSEL_CH10)
+#define BP_APBH_DEVSEL_CH9 18
+#define BM_APBH_DEVSEL_CH9 0x000C0000
+#define BF_APBH_DEVSEL_CH9(v) \
+ (((v) << 18) & BM_APBH_DEVSEL_CH9)
+#define BP_APBH_DEVSEL_CH8 16
+#define BM_APBH_DEVSEL_CH8 0x00030000
+#define BF_APBH_DEVSEL_CH8(v) \
+ (((v) << 16) & BM_APBH_DEVSEL_CH8)
+#define BP_APBH_DEVSEL_CH7 14
+#define BM_APBH_DEVSEL_CH7 0x0000C000
+#define BF_APBH_DEVSEL_CH7(v) \
+ (((v) << 14) & BM_APBH_DEVSEL_CH7)
+#define BP_APBH_DEVSEL_CH6 12
+#define BM_APBH_DEVSEL_CH6 0x00003000
+#define BF_APBH_DEVSEL_CH6(v) \
+ (((v) << 12) & BM_APBH_DEVSEL_CH6)
+#define BP_APBH_DEVSEL_CH5 10
+#define BM_APBH_DEVSEL_CH5 0x00000C00
+#define BF_APBH_DEVSEL_CH5(v) \
+ (((v) << 10) & BM_APBH_DEVSEL_CH5)
+#define BP_APBH_DEVSEL_CH4 8
+#define BM_APBH_DEVSEL_CH4 0x00000300
+#define BF_APBH_DEVSEL_CH4(v) \
+ (((v) << 8) & BM_APBH_DEVSEL_CH4)
+#define BP_APBH_DEVSEL_CH3 6
+#define BM_APBH_DEVSEL_CH3 0x000000C0
+#define BF_APBH_DEVSEL_CH3(v) \
+ (((v) << 6) & BM_APBH_DEVSEL_CH3)
+#define BP_APBH_DEVSEL_CH2 4
+#define BM_APBH_DEVSEL_CH2 0x00000030
+#define BF_APBH_DEVSEL_CH2(v) \
+ (((v) << 4) & BM_APBH_DEVSEL_CH2)
+#define BP_APBH_DEVSEL_CH1 2
+#define BM_APBH_DEVSEL_CH1 0x0000000C
+#define BF_APBH_DEVSEL_CH1(v) \
+ (((v) << 2) & BM_APBH_DEVSEL_CH1)
+#define BP_APBH_DEVSEL_CH0 0
+#define BM_APBH_DEVSEL_CH0 0x00000003
+#define BF_APBH_DEVSEL_CH0(v) \
+ (((v) << 0) & BM_APBH_DEVSEL_CH0)
+
+#define HW_APBH_DMA_BURST_SIZE (0x00000050)
+
+#define BP_APBH_DMA_BURST_SIZE_CH15 30
+#define BM_APBH_DMA_BURST_SIZE_CH15 0xC0000000
+#define BF_APBH_DMA_BURST_SIZE_CH15(v) \
+ (((v) << 30) & BM_APBH_DMA_BURST_SIZE_CH15)
+#define BP_APBH_DMA_BURST_SIZE_CH14 28
+#define BM_APBH_DMA_BURST_SIZE_CH14 0x30000000
+#define BF_APBH_DMA_BURST_SIZE_CH14(v) \
+ (((v) << 28) & BM_APBH_DMA_BURST_SIZE_CH14)
+#define BP_APBH_DMA_BURST_SIZE_CH13 26
+#define BM_APBH_DMA_BURST_SIZE_CH13 0x0C000000
+#define BF_APBH_DMA_BURST_SIZE_CH13(v) \
+ (((v) << 26) & BM_APBH_DMA_BURST_SIZE_CH13)
+#define BP_APBH_DMA_BURST_SIZE_CH12 24
+#define BM_APBH_DMA_BURST_SIZE_CH12 0x03000000
+#define BF_APBH_DMA_BURST_SIZE_CH12(v) \
+ (((v) << 24) & BM_APBH_DMA_BURST_SIZE_CH12)
+#define BP_APBH_DMA_BURST_SIZE_CH11 22
+#define BM_APBH_DMA_BURST_SIZE_CH11 0x00C00000
+#define BF_APBH_DMA_BURST_SIZE_CH11(v) \
+ (((v) << 22) & BM_APBH_DMA_BURST_SIZE_CH11)
+#define BP_APBH_DMA_BURST_SIZE_CH10 20
+#define BM_APBH_DMA_BURST_SIZE_CH10 0x00300000
+#define BF_APBH_DMA_BURST_SIZE_CH10(v) \
+ (((v) << 20) & BM_APBH_DMA_BURST_SIZE_CH10)
+#define BP_APBH_DMA_BURST_SIZE_CH9 18
+#define BM_APBH_DMA_BURST_SIZE_CH9 0x000C0000
+#define BF_APBH_DMA_BURST_SIZE_CH9(v) \
+ (((v) << 18) & BM_APBH_DMA_BURST_SIZE_CH9)
+#define BP_APBH_DMA_BURST_SIZE_CH8 16
+#define BM_APBH_DMA_BURST_SIZE_CH8 0x00030000
+#define BF_APBH_DMA_BURST_SIZE_CH8(v) \
+ (((v) << 16) & BM_APBH_DMA_BURST_SIZE_CH8)
+#define BV_APBH_DMA_BURST_SIZE_CH8__BURST0 0x0
+#define BV_APBH_DMA_BURST_SIZE_CH8__BURST4 0x1
+#define BV_APBH_DMA_BURST_SIZE_CH8__BURST8 0x2
+#define BP_APBH_DMA_BURST_SIZE_CH7 14
+#define BM_APBH_DMA_BURST_SIZE_CH7 0x0000C000
+#define BF_APBH_DMA_BURST_SIZE_CH7(v) \
+ (((v) << 14) & BM_APBH_DMA_BURST_SIZE_CH7)
+#define BP_APBH_DMA_BURST_SIZE_CH6 12
+#define BM_APBH_DMA_BURST_SIZE_CH6 0x00003000
+#define BF_APBH_DMA_BURST_SIZE_CH6(v) \
+ (((v) << 12) & BM_APBH_DMA_BURST_SIZE_CH6)
+#define BP_APBH_DMA_BURST_SIZE_CH5 10
+#define BM_APBH_DMA_BURST_SIZE_CH5 0x00000C00
+#define BF_APBH_DMA_BURST_SIZE_CH5(v) \
+ (((v) << 10) & BM_APBH_DMA_BURST_SIZE_CH5)
+#define BP_APBH_DMA_BURST_SIZE_CH4 8
+#define BM_APBH_DMA_BURST_SIZE_CH4 0x00000300
+#define BF_APBH_DMA_BURST_SIZE_CH4(v) \
+ (((v) << 8) & BM_APBH_DMA_BURST_SIZE_CH4)
+#define BP_APBH_DMA_BURST_SIZE_CH3 6
+#define BM_APBH_DMA_BURST_SIZE_CH3 0x000000C0
+#define BF_APBH_DMA_BURST_SIZE_CH3(v) \
+ (((v) << 6) & BM_APBH_DMA_BURST_SIZE_CH3)
+#define BP_APBH_DMA_BURST_SIZE_CH2 4
+#define BM_APBH_DMA_BURST_SIZE_CH2 0x00000030
+#define BF_APBH_DMA_BURST_SIZE_CH2(v) \
+ (((v) << 4) & BM_APBH_DMA_BURST_SIZE_CH2)
+#define BP_APBH_DMA_BURST_SIZE_CH1 2
+#define BM_APBH_DMA_BURST_SIZE_CH1 0x0000000C
+#define BF_APBH_DMA_BURST_SIZE_CH1(v) \
+ (((v) << 2) & BM_APBH_DMA_BURST_SIZE_CH1)
+#define BP_APBH_DMA_BURST_SIZE_CH0 0
+#define BM_APBH_DMA_BURST_SIZE_CH0 0x00000003
+#define BF_APBH_DMA_BURST_SIZE_CH0(v) \
+ (((v) << 0) & BM_APBH_DMA_BURST_SIZE_CH0)
+
+#define HW_APBH_DEBUG (0x00000060)
+
+#define BP_APBH_DEBUG_RSVD 1
+#define BM_APBH_DEBUG_RSVD 0xFFFFFFFE
+#define BF_APBH_DEBUG_RSVD(v) \
+ (((v) << 1) & BM_APBH_DEBUG_RSVD)
+#define BM_APBH_DEBUG_GPMI_ONE_FIFO 0x00000001
+
+/*
+ * multi-register-define name HW_APBH_CHn_CURCMDAR
+ * base 0x00000100
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_CURCMDAR(n) (0x00000100 + (n) * 0x70)
+#define BP_APBH_CHn_CURCMDAR_CMD_ADDR 0
+#define BM_APBH_CHn_CURCMDAR_CMD_ADDR 0xFFFFFFFF
+#define BF_APBH_CHn_CURCMDAR_CMD_ADDR(v) (v)
+
+/*
+ * multi-register-define name HW_APBH_CHn_NXTCMDAR
+ * base 0x00000110
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_NXTCMDAR(n) (0x00000110 + (n) * 0x70)
+#define BP_APBH_CHn_NXTCMDAR_CMD_ADDR 0
+#define BM_APBH_CHn_NXTCMDAR_CMD_ADDR 0xFFFFFFFF
+#define BF_APBH_CHn_NXTCMDAR_CMD_ADDR(v) (v)
+
+/*
+ * multi-register-define name HW_APBH_CHn_CMD
+ * base 0x00000120
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_CMD(n) (0x00000120 + (n) * 0x70)
+#define BP_APBH_CHn_CMD_XFER_COUNT 16
+#define BM_APBH_CHn_CMD_XFER_COUNT 0xFFFF0000
+#define BF_APBH_CHn_CMD_XFER_COUNT(v) \
+ (((v) << 16) & BM_APBH_CHn_CMD_XFER_COUNT)
+#define BP_APBH_CHn_CMD_CMDWORDS 12
+#define BM_APBH_CHn_CMD_CMDWORDS 0x0000F000
+#define BF_APBH_CHn_CMD_CMDWORDS(v) \
+ (((v) << 12) & BM_APBH_CHn_CMD_CMDWORDS)
+#define BP_APBH_CHn_CMD_RSVD1 9
+#define BM_APBH_CHn_CMD_RSVD1 0x00000E00
+#define BF_APBH_CHn_CMD_RSVD1(v) \
+ (((v) << 9) & BM_APBH_CHn_CMD_RSVD1)
+#define BM_APBH_CHn_CMD_HALTONTERMINATE 0x00000100
+#define BM_APBH_CHn_CMD_WAIT4ENDCMD 0x00000080
+#define BM_APBH_CHn_CMD_SEMAPHORE 0x00000040
+#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020
+#define BM_APBH_CHn_CMD_NANDLOCK 0x00000010
+#define BM_APBH_CHn_CMD_IRQONCMPLT 0x00000008
+#define BM_APBH_CHn_CMD_CHAIN 0x00000004
+#define BP_APBH_CHn_CMD_COMMAND 0
+#define BM_APBH_CHn_CMD_COMMAND 0x00000003
+#define BF_APBH_CHn_CMD_COMMAND(v) \
+ (((v) << 0) & BM_APBH_CHn_CMD_COMMAND)
+#define BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER 0x0
+#define BV_APBH_CHn_CMD_COMMAND__DMA_WRITE 0x1
+#define BV_APBH_CHn_CMD_COMMAND__DMA_READ 0x2
+#define BV_APBH_CHn_CMD_COMMAND__DMA_SENSE 0x3
+
+/*
+ * multi-register-define name HW_APBH_CHn_BAR
+ * base 0x00000130
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_BAR(n) (0x00000130 + (n) * 0x70)
+#define BP_APBH_CHn_BAR_ADDRESS 0
+#define BM_APBH_CHn_BAR_ADDRESS 0xFFFFFFFF
+#define BF_APBH_CHn_BAR_ADDRESS(v) (v)
+
+/*
+ * multi-register-define name HW_APBH_CHn_SEMA
+ * base 0x00000140
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_SEMA(n) (0x00000140 + (n) * 0x70)
+#define BP_APBH_CHn_SEMA_RSVD2 24
+#define BM_APBH_CHn_SEMA_RSVD2 0xFF000000
+#define BF_APBH_CHn_SEMA_RSVD2(v) \
+ (((v) << 24) & BM_APBH_CHn_SEMA_RSVD2)
+#define BP_APBH_CHn_SEMA_PHORE 16
+#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000
+#define BF_APBH_CHn_SEMA_PHORE(v) \
+ (((v) << 16) & BM_APBH_CHn_SEMA_PHORE)
+#define BP_APBH_CHn_SEMA_RSVD1 8
+#define BM_APBH_CHn_SEMA_RSVD1 0x0000FF00
+#define BF_APBH_CHn_SEMA_RSVD1(v) \
+ (((v) << 8) & BM_APBH_CHn_SEMA_RSVD1)
+#define BP_APBH_CHn_SEMA_INCREMENT_SEMA 0
+#define BM_APBH_CHn_SEMA_INCREMENT_SEMA 0x000000FF
+#define BF_APBH_CHn_SEMA_INCREMENT_SEMA(v) \
+ (((v) << 0) & BM_APBH_CHn_SEMA_INCREMENT_SEMA)
+
+/*
+ * multi-register-define name HW_APBH_CHn_DEBUG1
+ * base 0x00000150
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_DEBUG1(n) (0x00000150 + (n) * 0x70)
+#define BM_APBH_CHn_DEBUG1_REQ 0x80000000
+#define BM_APBH_CHn_DEBUG1_BURST 0x40000000
+#define BM_APBH_CHn_DEBUG1_KICK 0x20000000
+#define BM_APBH_CHn_DEBUG1_END 0x10000000
+#define BM_APBH_CHn_DEBUG1_SENSE 0x08000000
+#define BM_APBH_CHn_DEBUG1_READY 0x04000000
+#define BM_APBH_CHn_DEBUG1_LOCK 0x02000000
+#define BM_APBH_CHn_DEBUG1_NEXTCMDADDRVALID 0x01000000
+#define BM_APBH_CHn_DEBUG1_RD_FIFO_EMPTY 0x00800000
+#define BM_APBH_CHn_DEBUG1_RD_FIFO_FULL 0x00400000
+#define BM_APBH_CHn_DEBUG1_WR_FIFO_EMPTY 0x00200000
+#define BM_APBH_CHn_DEBUG1_WR_FIFO_FULL 0x00100000
+#define BP_APBH_CHn_DEBUG1_RSVD1 5
+#define BM_APBH_CHn_DEBUG1_RSVD1 0x000FFFE0
+#define BF_APBH_CHn_DEBUG1_RSVD1(v) \
+ (((v) << 5) & BM_APBH_CHn_DEBUG1_RSVD1)
+#define BP_APBH_CHn_DEBUG1_STATEMACHINE 0
+#define BM_APBH_CHn_DEBUG1_STATEMACHINE 0x0000001F
+#define BF_APBH_CHn_DEBUG1_STATEMACHINE(v) \
+ (((v) << 0) & BM_APBH_CHn_DEBUG1_STATEMACHINE)
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__IDLE 0x00
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD1 0x01
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD3 0x02
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD2 0x03
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__XFER_DECODE 0x04
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_WAIT 0x05
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD4 0x06
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__PIO_REQ 0x07
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_FLUSH 0x08
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_WAIT 0x09
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WRITE 0x0C
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_REQ 0x0D
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__CHECK_CHAIN 0x0E
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__XFER_COMPLETE 0x0F
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__TERMINATE 0x14
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WAIT_END 0x15
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WRITE_WAIT 0x1C
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__HALT_AFTER_TERM 0x1D
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__CHECK_WAIT 0x1E
+#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WAIT_READY 0x1F
+
+/*
+ * multi-register-define name HW_APBH_CHn_DEBUG2
+ * base 0x00000160
+ * count 16
+ * offset 0x70
+ */
+#define HW_APBH_CHn_DEBUG2(n) (0x00000160 + (n) * 0x70)
+#define BP_APBH_CHn_DEBUG2_APB_BYTES 16
+#define BM_APBH_CHn_DEBUG2_APB_BYTES 0xFFFF0000
+#define BF_APBH_CHn_DEBUG2_APB_BYTES(v) \
+ (((v) << 16) & BM_APBH_CHn_DEBUG2_APB_BYTES)
+#define BP_APBH_CHn_DEBUG2_AHB_BYTES 0
+#define BM_APBH_CHn_DEBUG2_AHB_BYTES 0x0000FFFF
+#define BF_APBH_CHn_DEBUG2_AHB_BYTES(v) \
+ (((v) << 0) & BM_APBH_CHn_DEBUG2_AHB_BYTES)
+
+#define HW_APBH_VERSION (0x00000800)
+
+#define BP_APBH_VERSION_MAJOR 24
+#define BM_APBH_VERSION_MAJOR 0xFF000000
+#define BF_APBH_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_APBH_VERSION_MAJOR)
+#define BP_APBH_VERSION_MINOR 16
+#define BM_APBH_VERSION_MINOR 0x00FF0000
+#define BF_APBH_VERSION_MINOR(v) \
+ (((v) << 16) & BM_APBH_VERSION_MINOR)
+#define BP_APBH_VERSION_STEP 0
+#define BM_APBH_VERSION_STEP 0x0000FFFF
+#define BF_APBH_VERSION_STEP(v) \
+ (((v) << 0) & BM_APBH_VERSION_STEP)
+
+enum {
+ MXS_DMA_CHANNEL_AHB_APBH = 0,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI0 = MXS_DMA_CHANNEL_AHB_APBH,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI1,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI2,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI3,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI4,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI5,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI6,
+ MXS_DMA_CHANNEL_AHB_APBH_GPMI7,
+ MXS_DMA_CHANNEL_AHB_APBH_SSP,
+ MXS_MAX_DMA_CHANNELS,
+};
+
+#ifndef CONFIG_ARCH_DMA_PIO_WORDS
+#define DMA_PIO_WORDS 15
+#else
+#define DMA_PIO_WORDS CONFIG_ARCH_DMA_PIO_WORDS
+#endif
+
+#define MXS_DMA_ALIGNMENT 8
+
+/**
+ * struct mxs_dma_cmd_bits - MXS DMA hardware command bits.
+ *
+ * This structure describes the in-memory layout of the command bits in a DMA
+ * command. See the appropriate reference manual for a detailed description
+ * of what these bits mean to the DMA hardware.
+ */
+struct mxs_dma_cmd_bits {
+ unsigned int command:2;
+#define NO_DMA_XFER 0x00
+#define DMA_WRITE 0x01
+#define DMA_READ 0x02
+#define DMA_SENSE 0x03
+
+ unsigned int chain:1;
+ unsigned int irq:1;
+ unsigned int nand_lock:1;
+ unsigned int nand_wait_4_ready:1;
+ unsigned int dec_sem:1;
+ unsigned int wait4end:1;
+ unsigned int halt_on_terminate:1;
+ unsigned int terminate_flush:1;
+ unsigned int resv2:2;
+ unsigned int pio_words:4;
+ unsigned int bytes:16;
+};
+
+/**
+ * struct mxs_dma_cmd - MXS DMA hardware command.
+ *
+ * This structure describes the in-memory layout of an entire DMA command,
+ * including space for the maximum number of PIO accesses. See the appropriate
+ * reference manual for a detailed description of what these fields mean to the
+ * DMA hardware.
+ */
+struct mxs_dma_cmd {
+ unsigned long next;
+ union {
+ unsigned long data;
+ struct mxs_dma_cmd_bits bits;
+ } cmd;
+ union {
+ dma_addr_t address;
+ unsigned long alternate;
+ };
+ unsigned long pio_words[DMA_PIO_WORDS];
+};
+
+/**
+ * struct mxs_dma_desc - MXS DMA command descriptor.
+ *
+ * This structure incorporates an MXS DMA hardware command structure, along
+ * with metadata.
+ *
+ * @cmd: The MXS DMA hardware command block.
+ * @flags: Flags that represent the state of this DMA descriptor.
+ * @address: The physical address of this descriptor.
+ * @buffer: A convenient place for software to put the virtual address of the
+ * associated data buffer (the physical address of the buffer
+ * appears in the DMA command). The MXS platform DMA software doesn't
+ * use this field -- it is provided as a convenience.
+ * @node: Links this structure into a list.
+ */
+struct mxs_dma_desc {
+ struct mxs_dma_cmd cmd;
+ unsigned int flags;
+#define MXS_DMA_DESC_READY 0x80000000
+#define MXS_DMA_DESC_FIRST 0x00000001
+#define MXS_DMA_DESC_LAST 0x00000002
+ dma_addr_t address;
+ void *buffer;
+ struct list_head node;
+};
+
+struct mxs_dma_info {
+ unsigned int status;
+#define MXS_DMA_INFO_ERR 0x00000001
+#define MXS_DMA_INFO_ERR_STAT 0x00010000
+ unsigned int buf_addr;
+};
+
+/**
+ * struct mxs_dma_chan - MXS DMA channel
+ *
+ * This structure represents a single DMA channel. The MXS platform code
+ * maintains an array of these structures to represent every DMA channel in the
+ * system (see mxs_dma_channels).
+ *
+ * @name: A human-readable string that describes how this channel is
+ * being used or what software "owns" it. This field is set when
+ * when the channel is reserved by mxs_dma_request().
+ * @dev: A pointer to a struct device *, cast to an unsigned long, and
+ * representing the software that "owns" the channel. This field
+ * is set when when the channel is reserved by mxs_dma_request().
+ * @lock: Arbitrates access to this channel.
+ * @dma: A pointer to a struct mxs_dma_device representing the driver
+ * code that operates this channel.
+ * @flags: Flag bits that represent the state of this channel.
+ * @active_num: If the channel is not busy, this value is zero. If the channel
+ * is busy, this field contains the number of DMA command
+ * descriptors at the head of the active list that the hardware
+ * has been told to process. This value is set at the moment the
+ * channel is enabled by mxs_dma_enable(). More descriptors may
+ * arrive after the channel is enabled, so the number of
+ * descriptors on the active list may be greater than this value.
+ * In fact, it should always be active_num + pending_num.
+ * @pending_num: The number of DMA command descriptors at the tail of the
+ * active list that the hardware has not been told to process.
+ * @active: The list of DMA command descriptors either currently being
+ * processed by the hardware or waiting to be processed.
+ * Descriptors being processed appear at the head of the list,
+ * while pending descriptors appear at the tail. The total number
+ * should always be active_num + pending_num.
+ * @done: The list of DMA command descriptors that have either been
+ * processed by the DMA hardware or aborted by a call to
+ * mxs_dma_disable().
+ */
+struct mxs_dma_chan {
+ const char *name;
+ unsigned long dev;
+ struct mxs_dma_device *dma;
+ unsigned int flags;
+#define MXS_DMA_FLAGS_IDLE 0x00000000
+#define MXS_DMA_FLAGS_BUSY 0x00000001
+#define MXS_DMA_FLAGS_FREE 0x00000000
+#define MXS_DMA_FLAGS_ALLOCATED 0x00010000
+#define MXS_DMA_FLAGS_VALID 0x80000000
+ unsigned int active_num;
+ unsigned int pending_num;
+ struct list_head active;
+ struct list_head done;
+};
+
+/**
+ * struct mxs_dma_device - DMA channel driver interface.
+ *
+ * This structure represents the driver that operates a DMA channel. Every
+ * struct mxs_dma_chan contains a pointer to a structure of this type, which is
+ * installed when the driver registers to "own" the channel (see
+ * mxs_dma_device_register()).
+ */
+struct mxs_dma_device {
+ struct list_head node;
+ const char *name;
+ void *base;
+ unsigned int chan_base;
+ unsigned int chan_num;
+ unsigned int data;
+};
+
+/**
+ * mxs_dma_device_register - Register a DMA driver.
+ *
+ * This function registers a driver for a contiguous group of DMA channels (the
+ * ordering of DMA channels is specified by the globally unique DMA channel
+ * numbers given in mach/dma.h).
+ *
+ * @pdev: A pointer to a structure that represents the driver. This structure
+ * contains fields that specify the first DMA channel number and the
+ * number of channels.
+ */
+extern int mxs_dma_device_register(struct mxs_dma_device *pdev);
+
+/**
+ * mxs_dma_request - Request to reserve a DMA channel.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @dev: A pointer to a struct device representing the channel "owner."
+ * @name: A human-readable string that identifies the channel owner or the
+ * purpose of the channel.
+ */
+extern int mxs_dma_request(int channel);
+
+/**
+ * mxs_dma_release - Release a DMA channel.
+ *
+ * This function releases a DMA channel from its current owner.
+ *
+ * The channel will NOT be released if it's marked "busy" (see
+ * mxs_dma_enable()).
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @dev: A pointer to a struct device representing the channel "owner." If
+ * this doesn't match the owner given to mxs_dma_request(), the
+ * channel will NOT be released.
+ */
+extern void mxs_dma_release(int channel);
+
+/**
+ * mxs_dma_enable - Enable a DMA channel.
+ *
+ * If the given channel has any DMA descriptors on its active list, this
+ * function causes the DMA hardware to begin processing them.
+ *
+ * This function marks the DMA channel as "busy," whether or not there are any
+ * descriptors to process.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern int mxs_dma_enable(int channel);
+
+/**
+ * mxs_dma_disable - Disable a DMA channel.
+ *
+ * This function shuts down a DMA channel and marks it as "not busy." Any
+ * descriptors on the active list are immediately moved to the head of the
+ * "done" list, whether or not they have actually been processed by the
+ * hardware. The "ready" flags of these descriptors are NOT cleared, so they
+ * still appear to be active.
+ *
+ * This function immediately shuts down a DMA channel's hardware, aborting any
+ * I/O that may be in progress, potentially leaving I/O hardware in an undefined
+ * state. It is unwise to call this function if there is ANY chance the hardware
+ * is still processing a command.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern void mxs_dma_disable(int channel);
+
+/**
+ * mxs_dma_reset - Resets the DMA channel hardware.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern void mxs_dma_reset(int channel);
+
+/**
+ * mxs_dma_freeze - Freeze a DMA channel.
+ *
+ * This function causes the channel to continuously fail arbitration for bus
+ * access, which halts all forward progress without losing any state. A call to
+ * mxs_dma_unfreeze() will cause the channel to continue its current operation
+ * with no ill effect.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern void mxs_dma_freeze(int channel);
+
+/**
+ * mxs_dma_unfreeze - Unfreeze a DMA channel.
+ *
+ * This function reverses the effect of mxs_dma_freeze(), enabling the DMA
+ * channel to continue from where it was frozen.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+
+extern void mxs_dma_unfreeze(int channel);
+
+/* get dma channel information */
+extern int mxs_dma_get_info(int channel, struct mxs_dma_info *info);
+
+/**
+ * mxs_dma_cooked - Clean up processed DMA descriptors.
+ *
+ * This function removes processed DMA descriptors from the "active" list. Pass
+ * in a non-NULL list head to get the descriptors moved to your list. Pass NULL
+ * to get the descriptors moved to the channel's "done" list. Descriptors on
+ * the "done" list can be retrieved with mxs_dma_get_cooked().
+ *
+ * This function marks the DMA channel as "not busy" if no unprocessed
+ * descriptors remain on the "active" list.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @head: If this is not NULL, it is the list to which the processed
+ * descriptors should be moved. If this list is NULL, the descriptors
+ * will be moved to the "done" list.
+ */
+extern int mxs_dma_cooked(int channel, struct list_head *head);
+
+/**
+ * mxs_dma_read_semaphore - Read a DMA channel's hardware semaphore.
+ *
+ * As used by the MXS platform's DMA software, the DMA channel's hardware
+ * semaphore reflects the number of DMA commands the hardware will process, but
+ * has not yet finished. This is a volatile value read directly from hardware,
+ * so it must be be viewed as immediately stale.
+ *
+ * If the channel is not marked busy, or has finished processing all its
+ * commands, this value should be zero.
+ *
+ * See mxs_dma_append() for details on how DMA command blocks must be configured
+ * to maintain the expected behavior of the semaphore's value.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern int mxs_dma_read_semaphore(int channel);
+
+/**
+ * mxs_dma_irq_is_pending - Check if a DMA interrupt is pending.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern int mxs_dma_irq_is_pending(int channel);
+
+/**
+ * mxs_dma_enable_irq - Enable or disable DMA interrupt.
+ *
+ * This function enables the given DMA channel to interrupt the CPU.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @en: True if the interrupt for this channel should be enabled. False
+ * otherwise.
+ */
+extern void mxs_dma_enable_irq(int channel, int en);
+
+/**
+ * mxs_dma_ack_irq - Clear DMA interrupt.
+ *
+ * The software that is using the DMA channel must register to receive its
+ * interrupts and, when they arrive, must call this function to clear them.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ */
+extern void mxs_dma_ack_irq(int channel);
+
+/**
+ * mxs_dma_set_target - Set the target for a DMA channel.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @target: Indicates the target for the channel.
+ */
+extern void mxs_dma_set_target(int channel, int target);
+
+/* mxs dma utility functions */
+extern struct mxs_dma_desc *mxs_dma_alloc_desc(void);
+extern void mxs_dma_free_desc(struct mxs_dma_desc *);
+
+/**
+ * mxs_dma_cmd_address - Return the address of the command within a descriptor.
+ *
+ * @desc: The DMA descriptor of interest.
+ */
+static inline unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc)
+{
+ return desc->address += offsetof(struct mxs_dma_desc, cmd);
+}
+
+/**
+ * mxs_dma_desc_pending - Check if descriptor is on a channel's active list.
+ *
+ * This function returns the state of a descriptor's "ready" flag. This flag is
+ * usually set only if the descriptor appears on a channel's active list. The
+ * descriptor may or may not have already been processed by the hardware.
+ *
+ * The "ready" flag is set when the descriptor is submitted to a channel by a
+ * call to mxs_dma_append() or mxs_dma_append_list(). The "ready" flag is
+ * cleared when a processed descriptor is moved off the active list by a call
+ * to mxs_dma_cooked(). The "ready" flag is NOT cleared if the descriptor is
+ * aborted by a call to mxs_dma_disable().
+ *
+ * @desc: The DMA descriptor of interest.
+ */
+static inline int mxs_dma_desc_pending(struct mxs_dma_desc *pdesc)
+{
+ return pdesc->flags & MXS_DMA_DESC_READY;
+}
+
+/**
+ * mxs_dma_desc_append - Add a DMA descriptor to a channel.
+ *
+ * If the descriptor list for this channel is not empty, this function sets the
+ * CHAIN bit and the NEXTCMD_ADDR fields in the last descriptor's DMA command so
+ * it will chain to the new descriptor's command.
+ *
+ * Then, this function marks the new descriptor as "ready," adds it to the end
+ * of the active descriptor list, and increments the count of pending
+ * descriptors.
+ *
+ * The MXS platform DMA software imposes some rules on DMA commands to maintain
+ * important invariants. These rules are NOT checked, but they must be carefully
+ * applied by software that uses MXS DMA channels.
+ *
+ * Invariant:
+ * The DMA channel's hardware semaphore must reflect the number of DMA
+ * commands the hardware will process, but has not yet finished.
+ *
+ * Explanation:
+ * A DMA channel begins processing commands when its hardware semaphore is
+ * written with a value greater than zero, and it stops processing commands
+ * when the semaphore returns to zero.
+ *
+ * When a channel finishes a DMA command, it will decrement its semaphore if
+ * the DECREMENT_SEMAPHORE bit is set in that command's flags bits.
+ *
+ * In principle, it's not necessary for the DECREMENT_SEMAPHORE to be set,
+ * unless it suits the purposes of the software. For example, one could
+ * construct a series of five DMA commands, with the DECREMENT_SEMAPHORE
+ * bit set only in the last one. Then, setting the DMA channel's hardware
+ * semaphore to one would cause the entire series of five commands to be
+ * processed. However, this example would violate the invariant given above.
+ *
+ * Rule:
+ * ALL DMA commands MUST have the DECREMENT_SEMAPHORE bit set so that the DMA
+ * channel's hardware semaphore will be decremented EVERY time a command is
+ * processed.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @pdesc: A pointer to the new descriptor.
+ */
+extern int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc);
+
+/**
+ * mxs_dma_desc_add_list - Add a list of DMA descriptors to a channel.
+ *
+ * This function marks all the new descriptors as "ready," adds them to the end
+ * of the active descriptor list, and adds the length of the list to the count
+ * of pending descriptors.
+ *
+ * See mxs_dma_desc_append() for important rules that apply to incoming DMA
+ * descriptors.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @head: A pointer to the head of the list of DMA descriptors to add.
+ */
+extern int mxs_dma_desc_add_list(int channel, struct list_head *head);
+
+/**
+ * mxs_dma_desc_get_cooked - Retrieve processed DMA descriptors.
+ *
+ * This function moves all the descriptors from the DMA channel's "done" list to
+ * the head of the given list.
+ *
+ * @channel: The channel number. This is one of the globally unique DMA channel
+ * numbers given in mach/dma.h.
+ * @head: A pointer to the head of the list that will receive the
+ * descriptors on the "done" list.
+ */
+extern int mxs_dma_get_cooked(int channel, struct list_head *head);
+
+extern int mxs_dma_init(void);
+extern int mxs_dma_wait_complete(u32 uSecTimeout, unsigned int chan);
+extern int mxs_dma_go(int chan);
+
+#endif /* __ARCH_ARM___APBH_H */
diff --git a/include/asm-arm/arch-mx50/mmu.h b/include/asm-arm/arch-mx50/mmu.h
index 29e8091..502b94c 100644
--- a/include/asm-arm/arch-mx50/mmu.h
+++ b/include/asm-arm/arch-mx50/mmu.h
@@ -143,41 +143,4 @@ union ARM_MMU_FIRST_LEVEL_DESCRIPTOR {
ARM_ACCESS_TYPE_NO_ACCESS(14) | \
ARM_ACCESS_TYPE_NO_ACCESS(15))
-/*
- * Translate the virtual address of ram space to physical address
- * It is dependent on the implementation of mmu_init
- */
-inline void *iomem_to_phys(unsigned long virt)
-{
- if (virt >= 0xB0000000)
- return (void *)((virt - 0xB0000000) + PHYS_SDRAM_1);
-
- return (void *)virt;
-}
-
-/*
- * remap the physical address of ram space to uncacheable virtual address space
- * It is dependent on the implementation of hal_mmu_init
- */
-void *__ioremap(unsigned long offset, size_t size, unsigned long flags)
-{
- if (1 == flags) {
- if (offset >= PHYS_SDRAM_1 &&
- offset < (PHYS_SDRAM_1 + PHYS_SDRAM_1_SIZE))
- return (void *)(offset - PHYS_SDRAM_1) + 0xB0000000;
- else
- return NULL;
- } else
- return (void *)offset;
-}
-
-/*
- * Remap the physical address of ram space to uncacheable virtual address space
- * It is dependent on the implementation of hal_mmu_init
- */
-void __iounmap(void *addr)
-{
- return;
-}
-
#endif
diff --git a/include/asm-arm/arch-mx50/mx50.h b/include/asm-arm/arch-mx50/mx50.h
index 2395252..69e639c 100644
--- a/include/asm-arm/arch-mx50/mx50.h
+++ b/include/asm-arm/arch-mx50/mx50.h
@@ -42,7 +42,10 @@
#define CTI2_BASE_ADDR (DEBUG_BASE_ADDR + 0x00006000)
#define CTI3_BASE_ADDR (DEBUG_BASE_ADDR + 0x00007000)
#define CORTEX_DBG_BASE_ADDR (DEBUG_BASE_ADDR + 0x00008000)
+#define ABPHDMA_BASE_ADDR (DEBUG_BASE_ADDR + 0x01000000)
#define OCOTP_CTRL_BASE_ADDR (DEBUG_BASE_ADDR + 0x01002000)
+#define GPMI_BASE_ADDR (DEBUG_BASE_ADDR + 0x01006000)
+#define BCH_BASE_ADDR (DEBUG_BASE_ADDR + 0x01008000)
#define EPDC_BASE_ADDR (DEBUG_BASE_ADDR + 0x01010000)
/*
@@ -306,6 +309,8 @@ enum mxc_clock {
MXC_ESDHC2_CLK,
MXC_ESDHC3_CLK,
MXC_ESDHC4_CLK,
+ MXC_GPMI_CLK,
+ MXC_BCH_CLK,
};
enum mxc_peri_clocks {
diff --git a/include/asm-arm/arch-mx50/mx50_pins.h b/include/asm-arm/arch-mx50/mx50_pins.h
index 05935c9..311d434 100644
--- a/include/asm-arm/arch-mx50/mx50_pins.h
+++ b/include/asm-arm/arch-mx50/mx50_pins.h
@@ -69,6 +69,7 @@
#define NON_PAD_I PIN_TO_PAD_MASK
#define MUX_I_START 0x0020
#define PAD_I_START 0x2CC
+#define PAD_GRP_START 0x668
#define INPUT_CTL_START 0x6C4
#define MUX_I_END (PAD_I_START - 4)
diff --git a/include/configs/mx50_arm2.h b/include/configs/mx50_arm2.h
index c7f8faf..48bd307 100644
--- a/include/configs/mx50_arm2.h
+++ b/include/configs/mx50_arm2.h
@@ -33,8 +33,10 @@
#define CONFIG_SKIP_RELOCATE_UBOOT
+/*
#define CONFIG_ARCH_CPU_INIT
#define CONFIG_ARCH_MMU
+*/
#define CONFIG_MX50_HCLK_FREQ 24000000
#define CONFIG_SYS_PLL2_FREQ 400
@@ -68,8 +70,8 @@
/*
* Hardware drivers
*/
-#define CONFIG_MX50_UART 1
-#define CONFIG_MX50_UART1 1
+#define CONFIG_MXC_UART
+#define CONFIG_UART_BASE_ADDR UART1_BASE_ADDR
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
@@ -195,12 +197,17 @@
/*
* I2C Configs
*/
+/*
#define CONFIG_CMD_I2C 1
-#define CONFIG_HARD_I2C 1
-#define CONFIG_I2C_MXC 1
-#define CONFIG_SYS_I2C_PORT I2C2_BASE_ADDR
-#define CONFIG_SYS_I2C_SPEED 100000
-#define CONFIG_SYS_I2C_SLAVE 0xfe
+*/
+
+#ifdef CONFIG_CMD_I2C
+ #define CONFIG_HARD_I2C 1
+ #define CONFIG_I2C_MXC 1
+ #define CONFIG_SYS_I2C_PORT I2C2_BASE_ADDR
+ #define CONFIG_SYS_I2C_SPEED 100000
+ #define CONFIG_SYS_I2C_SLAVE 0xfe
+#endif
/*
@@ -241,6 +248,31 @@
#define CONFIG_MMC_8BIT_PORTS 0x6 /* ports 1 and 2 */
#endif
+
+/*
+ * GPMI Nand Configs
+ */
+#define CONFIG_CMD_NAND
+
+#ifdef CONFIG_CMD_NAND
+ #define CONFIG_NAND_GPMI
+ #define CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ #define CONFIG_GPMI_NFC_V2
+
+ #define CONFIG_GPMI_REG_BASE GPMI_BASE_ADDR
+ #define CONFIG_BCH_REG_BASE BCH_BASE_ADDR
+
+ #define NAND_MAX_CHIPS 8
+ #define CONFIG_SYS_NAND_BASE 0x40000000
+ #define CONFIG_SYS_MAX_NAND_DEVICE 1
+#endif
+
+/*
+ * APBH DMA Configs
+ */
+#define CONFIG_APBH_DMA
+#define CONFIG_MXS_DMA_REG_BASE ABPHDMA_BASE_ADDR
+
/*-----------------------------------------------------------------------
* Stack sizes
*
diff --git a/include/configs/mx50_arm2_lpddr2.h b/include/configs/mx50_arm2_lpddr2.h
index 01cbc12..9a85050 100644
--- a/include/configs/mx50_arm2_lpddr2.h
+++ b/include/configs/mx50_arm2_lpddr2.h
@@ -240,9 +240,26 @@
/* Indicate to esdhc driver which ports support 8-bit data */
#define CONFIG_MMC_8BIT_PORTS 0x6 /* ports 1 and 2 */
+#endif
+
+/*
+ * GPMI Nand Configs
+ */
+#define CONFIG_CMD_NAND
+
+#ifdef CONFIG_CMD_NAND
+ #define CONFIG_NAND_GPMI
+ #define CONFIG_GPMI_NFC_SWAP_BLOCK_MARK
+ #define CONFIG_GPMI_NFC_V2
+ #define CONFIG_GPMI_REG_BASE GPMI_BASE_ADDR
+ #define CONFIG_BCH_REG_BASE BCH_BASE_ADDR
+ #define NAND_MAX_CHIPS 8
+ #define CONFIG_SYS_NAND_BASE 0x40000000
+ #define CONFIG_SYS_MAX_NAND_DEVICE 1
#endif
+
/*-----------------------------------------------------------------------
* Stack sizes
*